Compare commits
274 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ebb5fc1285 | ||
|
4cfb3dcc7b | ||
|
e8fff4561e | ||
|
b56e66310d | ||
|
bda3bd1557 | ||
|
7723673038 | ||
|
c69e667f5e | ||
|
6157860c0a | ||
|
32fc4e3d0f | ||
|
ee0c0c4a59 | ||
|
356117819c | ||
|
834c96a374 | ||
|
2195d980a2 | ||
|
3e43b042eb | ||
|
851742e5d9 | ||
|
c6c7feb0c2 | ||
|
1fde69ef48 | ||
|
894bedcae7 | ||
|
47f15eaa03 | ||
|
b0c0739db9 | ||
|
c3dc23e84a | ||
|
cc7fc447a4 | ||
|
a401b2b4cf | ||
|
d8c66c8981 | ||
|
49a415414f | ||
|
6c540d2ada | ||
|
da62ebac1a | ||
|
25aee12502 | ||
|
d8e8528797 | ||
|
ed8c796877 | ||
|
ec750cf3eb | ||
|
4a35053fba | ||
|
9797178ad1 | ||
|
dbc58455df | ||
|
4a3f851e49 | ||
|
5a3bf5c90e | ||
|
de6ec11efc | ||
|
7aec87c086 | ||
|
eabc21c23a | ||
|
713f346211 | ||
|
a81bc0ecf8 | ||
|
a3f1580b8b | ||
|
4f20798654 | ||
|
0ecd1755a6 | ||
|
57dd8a555a | ||
|
f64cd4a75a | ||
|
2ce6c86c2a | ||
|
ff9573714b | ||
|
826111cf79 | ||
|
f31f1d0f52 | ||
|
e220f7067b | ||
|
d9726e61bc | ||
|
786fa4f22e | ||
|
5b74678e37 | ||
|
d203bd1998 | ||
|
5f5fa38d85 | ||
|
fadf1efa41 | ||
|
0269fffa5a | ||
|
50e441a9ed | ||
|
9413051053 | ||
|
13e176a633 | ||
|
9268239c75 | ||
|
e51d7af847 | ||
|
147ba1de69 | ||
|
7cc709c82a | ||
|
a2395e8730 | ||
|
ae605f8f02 | ||
|
ea2cc90215 | ||
|
e15ddbb979 | ||
|
bbd8bd2e74 | ||
|
a5794efe16 | ||
|
27095378fa | ||
|
a8836649cb | ||
|
cc81830f13 | ||
|
558a46f5d5 | ||
|
57add5366e | ||
|
5057aaddc0 | ||
|
3865219085 | ||
|
6da06654ff | ||
|
4a375acebc | ||
|
9fcd465928 | ||
|
1f8ef5e640 | ||
|
a1b0f2f681 | ||
|
f59d4f29d9 | ||
|
b379004c3b | ||
|
25491780df | ||
|
4354ad3299 | ||
|
4e94446fc3 | ||
|
d99795c000 | ||
|
fe775a9716 | ||
|
ac76a75937 | ||
|
6c1678244f | ||
|
63a9f33be1 | ||
|
c9da91cb1c | ||
|
b3488e0139 | ||
|
f3814a0478 | ||
|
5e8d8cfb49 | ||
|
ad37276d83 | ||
|
719db7eed0 | ||
|
4ddb72a32d | ||
|
ff1171338f | ||
|
28683b0ad8 | ||
|
4ef3a679a4 | ||
|
e02bcbdae2 | ||
|
7b0187a148 | ||
|
e92283c8d2 | ||
|
ef3781d4ee | ||
|
6da4bec41d | ||
|
31ed985fd0 | ||
|
cdc10712b1 | ||
|
935a836a7d | ||
|
97ba3cbeb0 | ||
|
e8ca35f9ec | ||
|
d5aae9a8af | ||
|
3bb8016a40 | ||
|
579065443a | ||
|
81d636c2bf | ||
|
6a7ce8500b | ||
|
8ee294639a | ||
|
b275f65ef1 | ||
|
37c2b68677 | ||
|
d9944c8ae3 | ||
|
6c8bbdca0a | ||
|
10e8f3ab32 | ||
|
8c0b0f235e | ||
|
ec8ba76e4d | ||
|
60fba7be75 | ||
|
24075ceeff | ||
|
f7ef1e68b0 | ||
|
723e7f11b9 | ||
|
f7211d3c07 | ||
|
6234090361 | ||
|
a001c1c8f6 | ||
|
7f62f4f621 | ||
|
8334a76e5b | ||
|
eadab5e2f0 | ||
|
8bb7b53f3b | ||
|
8c7b8e8c5d | ||
|
a2857928a4 | ||
|
f6780d72b1 | ||
|
5d003c6dab | ||
|
79ee0e06b2 | ||
|
443f132de5 | ||
|
95299e43a2 | ||
|
0cf1894ede | ||
|
f2f4f28c0b | ||
|
57da68d563 | ||
|
8d2337ccf8 | ||
|
270749185c | ||
|
6184254416 | ||
|
c8bb13b3f7 | ||
|
5da83c1491 | ||
|
b04ce80255 | ||
|
a788021181 | ||
|
553e9fb8cd | ||
|
f1bc7ec4fa | ||
|
581181e87f | ||
|
36e1f9fae8 | ||
|
f10ae394c8 | ||
|
f7905d369a | ||
|
ef079d202b | ||
|
b7efc2373c | ||
|
d3b50bc55b | ||
|
8fd3465f8a | ||
|
23b9e6eae3 | ||
|
fe1a977f9e | ||
|
5e538eff7c | ||
|
3efe4b5478 | ||
|
90e0d4fefe | ||
|
2e983fb39f | ||
|
527b20fbbd | ||
|
a0c4b4e5fc | ||
|
282315a721 | ||
|
b8198f8cc5 | ||
|
68ad2dcce1 | ||
|
e87c3421bc | ||
|
20754a7115 | ||
|
8a57ee181e | ||
|
4e6b5a9808 | ||
|
f24fbde43b | ||
|
47f60c7607 | ||
|
8b307ed409 | ||
|
cf21719a07 | ||
|
3157b464c4 | ||
|
2581db5748 | ||
|
634959b3ab | ||
|
03b21f2e9d | ||
|
cc5565b17e | ||
|
50beef0b15 | ||
|
06a54e1423 | ||
|
4d731ecd08 | ||
|
ee06789a66 | ||
|
2dabe1d706 | ||
|
3b1279a005 | ||
|
5c9f85f28d | ||
|
e12dd46ef3 | ||
|
c4fa03b478 | ||
|
9fb749deb7 | ||
|
bd48344de2 | ||
|
78e54f1d2c | ||
|
76a6576976 | ||
|
92ec1ae255 | ||
|
0d203728cc | ||
|
625773e5b8 | ||
|
a4cb1e45ae | ||
|
8aded2778e | ||
|
d940c5b1a3 | ||
|
1be045df94 | ||
|
86191911c7 | ||
|
8f852d8a6b | ||
|
68a439f8da | ||
|
e021832708 | ||
|
87b11aa187 | ||
|
7475a6f444 | ||
|
86ce650661 | ||
|
4dc5a53014 | ||
|
5e35cf3536 | ||
|
e8a8d1efb3 | ||
|
defd9238fa | ||
|
5f061dcea1 | ||
|
e6ee27a738 | ||
|
dd2d25d698 | ||
|
9096c3df02 | ||
|
9f94c2a9a0 | ||
|
34213da9f4 | ||
|
c3c4991c44 | ||
|
9d37a33dcd | ||
|
a04ca03fee | ||
|
64ce4a6203 | ||
|
7ac3c9ec76 | ||
|
7d91515e8d | ||
|
4e3f2c3d2d | ||
|
8b67ba6d3d | ||
|
c2ce68ab90 | ||
|
fe87cb1cd1 | ||
|
1c8f6a836a | ||
|
3d5ff7968e | ||
|
d6160f7744 | ||
|
5e9ce99abf | ||
|
ebd6fe7acb | ||
|
9e91a2c2fd | ||
|
899f57962a | ||
|
3176b00e57 | ||
|
08b9da8397 | ||
|
2bc21ecba2 | ||
|
5b2a65fab3 | ||
|
f5d56eabf3 | ||
|
af45efb62c | ||
|
f528cda832 | ||
|
eeef9f4e59 | ||
|
32124b59e9 | ||
|
aa9772f9c0 | ||
|
5f183bd773 | ||
|
2238e5001b | ||
|
79fa7ef55c | ||
|
07df827411 | ||
|
a259ff0e72 | ||
|
d7d3e767e7 | ||
|
6e8aa9af17 | ||
|
0236de7bc8 | ||
|
899bd1572a | ||
|
97ec4cd44e | ||
|
5500970a7e | ||
|
caea04d8d5 | ||
|
b1a90c3580 | ||
|
5bd4e38345 | ||
|
fddba08571 | ||
|
87963764fa | ||
|
b691a159dd | ||
|
5af1d48be8 | ||
|
3b3ec3313f | ||
|
be00246fb5 | ||
|
1d80ba9edf | ||
|
4bcf976ecd |
@@ -36,7 +36,4 @@ export CARGO_TARGET_CACHE=$HOME/cargo-target-cache/"$CHANNEL"-"$BUILDKITE_LABEL"
|
||||
# `std:
|
||||
# "found possibly newer version of crate `std` which `xyz` depends on
|
||||
rm -rf target/bpfel-unknown-unknown
|
||||
if [[ $BUILDKITE_LABEL = "stable-perf" ]]; then
|
||||
rm -rf target/release
|
||||
fi
|
||||
)
|
||||
|
@@ -73,7 +73,7 @@ jobs:
|
||||
|
||||
language: node_js
|
||||
node_js:
|
||||
- "lts/*"
|
||||
- "node"
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
856
Cargo.lock
generated
856
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,6 @@ members = [
|
||||
"perf",
|
||||
"validator",
|
||||
"genesis",
|
||||
"genesis-utils",
|
||||
"gossip",
|
||||
"install",
|
||||
"keygen",
|
||||
@@ -32,6 +31,7 @@ members = [
|
||||
"log-analyzer",
|
||||
"merkle-root-bench",
|
||||
"merkle-tree",
|
||||
"stake-o-matic",
|
||||
"storage-bigtable",
|
||||
"storage-proto",
|
||||
"streamer",
|
||||
@@ -39,20 +39,21 @@ members = [
|
||||
"metrics",
|
||||
"net-shaper",
|
||||
"notifier",
|
||||
"poh",
|
||||
"poh-bench",
|
||||
"program-test",
|
||||
"programs/secp256k1",
|
||||
"programs/bpf_loader",
|
||||
"programs/budget",
|
||||
"programs/config",
|
||||
"programs/exchange",
|
||||
"programs/failure",
|
||||
"programs/noop",
|
||||
"programs/ownable",
|
||||
"programs/stake",
|
||||
"programs/vest",
|
||||
"programs/vote",
|
||||
"remote-wallet",
|
||||
"rpc",
|
||||
"ramp-tps",
|
||||
"runtime",
|
||||
"runtime/store-tool",
|
||||
"sdk",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<p align="center">
|
||||
<a href="https://solana.com">
|
||||
<img alt="Solana" src="https://i.imgur.com/uBVzyX3.png" width="250" />
|
||||
<img alt="Solana" src="https://i.imgur.com/OMnvVEz.png" width="250" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -32,12 +32,6 @@ $ sudo apt-get update
|
||||
$ sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang make
|
||||
```
|
||||
|
||||
On Mac M1s, make sure you set up your terminal & homebrew [to use](https://5balloons.info/correct-way-to-install-and-use-homebrew-on-m1-macs/) Rosetta. You can install it with:
|
||||
|
||||
```bash
|
||||
$ softwareupdate --install-rosetta
|
||||
```
|
||||
|
||||
## **2. Download the source code.**
|
||||
|
||||
```bash
|
||||
|
20
SECURITY.md
20
SECURITY.md
@@ -51,27 +51,13 @@ The following components are out of scope for the bounty program
|
||||
* Attacks that require social engineering
|
||||
|
||||
Eligibility:
|
||||
* The participant submitting the bug report shall follow the process outlined within this document
|
||||
* The participant submitting the bug bounty shall follow the process outlined within this document
|
||||
* Valid exploits can be eligible even if they are not successfully executed on the cluster
|
||||
* Multiple submissions for the same class of exploit are still eligible for compensation, though may be compensated at a lower rate, however these will be assessed on a case-by-case basis
|
||||
* Participants must complete KYC and sign the participation agreement here when the registrations are open https://solana.com/validator-registration. Security exploits will still be assessed and open for submission at all times. This needs only be done prior to distribution of tokens.
|
||||
|
||||
Payment of Bug Bounties:
|
||||
* Payments for eligible bug reports are distributed monthly.
|
||||
* Bounties for all bug reports submitted in a given month are paid out in the middle of the
|
||||
following month.
|
||||
* The SOL/USD conversion rate used for payments is the market price at the end of
|
||||
the last day of the month for the month in which the bug was submitted.
|
||||
* The reference for this price is the Closing Price given by Coingecko.com on
|
||||
that date given here:
|
||||
https://www.coingecko.com/en/coins/solana/historical_data/usd#panel
|
||||
* For example, for all bugs submitted in March 2021, the SOL/USD price for bug
|
||||
payouts is the Close price on 2021-03-31 of $19.49. This applies to all bugs
|
||||
submitted in March 2021, to be paid in mid-April 2021.
|
||||
* Bug bounties are paid out in
|
||||
[stake accounts](https://solana.com/staking) with a
|
||||
[lockup](https://docs.solana.com/staking/stake-accounts#lockups)
|
||||
expiring 12 months from the last day of the month in which the bug was submitted.
|
||||
Notes:
|
||||
* All locked tokens can be staked during the lockup period
|
||||
|
||||
<a name="process"></a>
|
||||
## Incident Response Process
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-account-decoder"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
description = "Solana account decoder"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -19,10 +19,11 @@ lazy_static = "1.4.0"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-config-program = { path = "../programs/config", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.7" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.7" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.0", features = ["no-entrypoint"] }
|
||||
thiserror = "1.0"
|
||||
zstd = "0.5.1"
|
||||
|
||||
|
@@ -48,7 +48,7 @@ pub enum UiAccountData {
|
||||
Binary(String, UiAccountEncoding),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum UiAccountEncoding {
|
||||
Binary, // Legacy. Retained for RPC backwards compatibility
|
||||
@@ -62,7 +62,7 @@ pub enum UiAccountEncoding {
|
||||
impl UiAccount {
|
||||
pub fn encode<T: ReadableAccount>(
|
||||
pubkey: &Pubkey,
|
||||
account: &T,
|
||||
account: T,
|
||||
encoding: UiAccountEncoding,
|
||||
additional_data: Option<AccountAdditionalData>,
|
||||
data_slice_config: Option<UiDataSliceConfig>,
|
||||
@@ -224,7 +224,7 @@ mod test {
|
||||
fn test_base64_zstd() {
|
||||
let encoded_account = UiAccount::encode(
|
||||
&Pubkey::default(),
|
||||
&AccountSharedData::from(Account {
|
||||
AccountSharedData::from(Account {
|
||||
data: vec![0; 1024],
|
||||
..Account::default()
|
||||
}),
|
||||
|
@@ -9,14 +9,14 @@ use crate::{
|
||||
};
|
||||
use inflector::Inflector;
|
||||
use serde_json::Value;
|
||||
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, stake, system_program, sysvar};
|
||||
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, system_program, sysvar};
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
|
||||
lazy_static! {
|
||||
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
|
||||
static ref CONFIG_PROGRAM_ID: Pubkey = solana_config_program::id();
|
||||
static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id();
|
||||
static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id();
|
||||
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
|
||||
static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id();
|
||||
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();
|
||||
|
@@ -6,10 +6,10 @@ use bincode::deserialize;
|
||||
use serde_json::Value;
|
||||
use solana_config_program::{get_config_data, ConfigKeys};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::stake::config::{self as stake_config, Config as StakeConfig};
|
||||
use solana_stake_program::config::Config as StakeConfig;
|
||||
|
||||
pub fn parse_config(data: &[u8], pubkey: &Pubkey) -> Result<ConfigAccountType, ParseAccountError> {
|
||||
let parsed_account = if pubkey == &stake_config::id() {
|
||||
let parsed_account = if pubkey == &solana_stake_program::config::id() {
|
||||
get_config_data(data)
|
||||
.ok()
|
||||
.and_then(|data| deserialize::<StakeConfig>(data).ok())
|
||||
@@ -101,7 +101,11 @@ mod test {
|
||||
};
|
||||
let stake_config_account = create_config_account(vec![], &stake_config, 10);
|
||||
assert_eq!(
|
||||
parse_config(&stake_config_account.data(), &stake_config::id()).unwrap(),
|
||||
parse_config(
|
||||
&stake_config_account.data(),
|
||||
&solana_stake_program::config::id()
|
||||
)
|
||||
.unwrap(),
|
||||
ConfigAccountType::StakeConfig(UiStakeConfig {
|
||||
warmup_cooldown_rate: 0.25,
|
||||
slash_penalty: 50,
|
||||
|
@@ -4,7 +4,7 @@ use crate::{
|
||||
};
|
||||
use bincode::deserialize;
|
||||
use solana_sdk::clock::{Epoch, UnixTimestamp};
|
||||
use solana_sdk::stake::state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
|
||||
use solana_stake_program::stake_state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
|
||||
|
||||
pub fn parse_stake(data: &[u8]) -> Result<StakeAccountType, ParseAccountError> {
|
||||
let stake_state: StakeState = deserialize(data)
|
||||
|
@@ -14,23 +14,23 @@ use std::str::FromStr;
|
||||
// A helper function to convert spl_token_v2_0::id() as spl_sdk::pubkey::Pubkey to
|
||||
// solana_sdk::pubkey::Pubkey
|
||||
pub fn spl_token_id_v2_0() -> Pubkey {
|
||||
Pubkey::new_from_array(spl_token_v2_0::id().to_bytes())
|
||||
Pubkey::from_str(&spl_token_v2_0::id().to_string()).unwrap()
|
||||
}
|
||||
|
||||
// A helper function to convert spl_token_v2_0::native_mint::id() as spl_sdk::pubkey::Pubkey to
|
||||
// solana_sdk::pubkey::Pubkey
|
||||
pub fn spl_token_v2_0_native_mint() -> Pubkey {
|
||||
Pubkey::new_from_array(spl_token_v2_0::native_mint::id().to_bytes())
|
||||
Pubkey::from_str(&spl_token_v2_0::native_mint::id().to_string()).unwrap()
|
||||
}
|
||||
|
||||
// A helper function to convert a solana_sdk::pubkey::Pubkey to spl_sdk::pubkey::Pubkey
|
||||
pub fn spl_token_v2_0_pubkey(pubkey: &Pubkey) -> SplTokenPubkey {
|
||||
SplTokenPubkey::new_from_array(pubkey.to_bytes())
|
||||
SplTokenPubkey::from_str(&pubkey.to_string()).unwrap()
|
||||
}
|
||||
|
||||
// A helper function to convert a spl_sdk::pubkey::Pubkey to solana_sdk::pubkey::Pubkey
|
||||
pub fn pubkey_from_spl_token_v2_0(pubkey: &SplTokenPubkey) -> Pubkey {
|
||||
Pubkey::new_from_array(pubkey.to_bytes())
|
||||
Pubkey::from_str(&pubkey.to_string()).unwrap()
|
||||
}
|
||||
|
||||
pub fn parse_token(
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-accounts-bench"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -11,11 +11,11 @@ publish = false
|
||||
[dependencies]
|
||||
log = "0.4.11"
|
||||
rayon = "1.5.0"
|
||||
solana-logger = { path = "../logger", version = "=1.7.2" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||
solana-measure = { path = "../measure", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-version = { path = "../version", version = "=1.7.2" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.7" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.7" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
solana-version = { path = "../version", version = "=1.6.7" }
|
||||
rand = "0.7.0"
|
||||
clap = "2.33.1"
|
||||
crossbeam-channel = "0.4"
|
||||
|
@@ -6,12 +6,10 @@ use rayon::prelude::*;
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_runtime::{
|
||||
accounts::{create_test_accounts, update_accounts_bench, Accounts},
|
||||
accounts_db::AccountShrinkThreshold,
|
||||
accounts_index::AccountSecondaryIndexes,
|
||||
ancestors::Ancestors,
|
||||
accounts_index::Ancestors,
|
||||
};
|
||||
use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey};
|
||||
use std::{env, fs, path::PathBuf};
|
||||
use std::{collections::HashSet, env, fs, path::PathBuf};
|
||||
|
||||
fn main() {
|
||||
solana_logger::setup();
|
||||
@@ -60,13 +58,8 @@ fn main() {
|
||||
if fs::remove_dir_all(path.clone()).is_err() {
|
||||
println!("Warning: Couldn't remove {:?}", path);
|
||||
}
|
||||
let accounts = Accounts::new_with_config(
|
||||
vec![path],
|
||||
&ClusterType::Testnet,
|
||||
AccountSecondaryIndexes::default(),
|
||||
false,
|
||||
AccountShrinkThreshold::default(),
|
||||
);
|
||||
let accounts =
|
||||
Accounts::new_with_config(vec![path], &ClusterType::Testnet, HashSet::new(), false);
|
||||
println!("Creating {} accounts", num_accounts);
|
||||
let mut create_time = Measure::start("create accounts");
|
||||
let pubkeys: Vec<_> = (0..num_slots)
|
||||
@@ -90,19 +83,17 @@ fn main() {
|
||||
num_slots,
|
||||
create_time
|
||||
);
|
||||
let mut ancestors = Vec::with_capacity(num_slots);
|
||||
ancestors.push(0);
|
||||
let mut ancestors: Ancestors = vec![(0, 0)].into_iter().collect();
|
||||
for i in 1..num_slots {
|
||||
ancestors.push(i as u64);
|
||||
ancestors.insert(i as u64, i - 1);
|
||||
accounts.add_root(i as u64);
|
||||
}
|
||||
let ancestors = Ancestors::from(ancestors);
|
||||
let mut elapsed = vec![0; iterations];
|
||||
let mut elapsed_store = vec![0; iterations];
|
||||
for x in 0..iterations {
|
||||
if clean {
|
||||
let mut time = Measure::start("clean");
|
||||
accounts.accounts_db.clean_accounts(None, false);
|
||||
accounts.accounts_db.clean_accounts(None);
|
||||
time.stop();
|
||||
println!("{}", time);
|
||||
for slot in 0..num_slots {
|
||||
@@ -121,7 +112,6 @@ fn main() {
|
||||
solana_sdk::clock::Slot::default(),
|
||||
&ancestors,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
time_store.stop();
|
||||
if results != results_store {
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-accounts-cluster-bench"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -13,23 +13,22 @@ clap = "2.33.1"
|
||||
log = "0.4.11"
|
||||
rand = "0.7.0"
|
||||
rayon = "1.4.1"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
|
||||
solana-client = { path = "../client", version = "=1.7.2" }
|
||||
solana-core = { path = "../core", version = "=1.7.2" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.7.2" }
|
||||
solana-gossip = { path = "../gossip", version = "=1.7.2" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.2" }
|
||||
solana-measure = { path = "../measure", version = "=1.7.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
||||
solana-version = { path = "../version", version = "=1.7.2" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.7" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.7" }
|
||||
solana-client = { path = "../client", version = "=1.6.7" }
|
||||
solana-core = { path = "../core", version = "=1.6.7" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.7" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.7" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.7" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.7" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.7" }
|
||||
solana-version = { path = "../version", version = "=1.6.7" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.0", features = ["no-entrypoint"] }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.7.2" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.7" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -6,8 +6,8 @@ use rayon::prelude::*;
|
||||
use solana_account_decoder::parse_token::spl_token_v2_0_pubkey;
|
||||
use solana_clap_utils::input_parsers::pubkey_of;
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_core::gossip_service::discover;
|
||||
use solana_faucet::faucet::{request_airdrop_transaction, FAUCET_PORT};
|
||||
use solana_gossip::gossip_service::discover;
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_runtime::inline_spl_token_v2_0;
|
||||
use solana_sdk::{
|
||||
@@ -363,7 +363,7 @@ fn run_accounts_bench(
|
||||
iterations: usize,
|
||||
maybe_space: Option<u64>,
|
||||
batch_size: usize,
|
||||
close_nth_batch: u64,
|
||||
close_nth: u64,
|
||||
maybe_lamports: Option<u64>,
|
||||
num_instructions: usize,
|
||||
mint: Option<Pubkey>,
|
||||
@@ -441,7 +441,6 @@ fn run_accounts_bench(
|
||||
}
|
||||
}
|
||||
|
||||
// Create accounts
|
||||
let sigs_len = executor.num_outstanding();
|
||||
if sigs_len < batch_size {
|
||||
let num_to_create = batch_size - sigs_len;
|
||||
@@ -476,14 +475,10 @@ fn run_accounts_bench(
|
||||
}
|
||||
}
|
||||
|
||||
if close_nth_batch > 0 {
|
||||
let num_batches_to_close =
|
||||
total_accounts_created as u64 / (close_nth_batch * batch_size as u64);
|
||||
let expected_closed = num_batches_to_close * batch_size as u64;
|
||||
let max_closed_seed = seed_tracker.max_closed.load(Ordering::Relaxed);
|
||||
// Close every account we've created with seed between max_closed_seed..expected_closed
|
||||
if max_closed_seed < expected_closed {
|
||||
let txs: Vec<_> = (0..expected_closed - max_closed_seed)
|
||||
if close_nth > 0 {
|
||||
let expected_closed = total_accounts_created as u64 / close_nth;
|
||||
if expected_closed > total_accounts_closed {
|
||||
let txs: Vec<_> = (0..expected_closed - total_accounts_closed)
|
||||
.into_par_iter()
|
||||
.map(|_| {
|
||||
let message = make_close_message(
|
||||
@@ -577,14 +572,14 @@ fn main() {
|
||||
.help("Number of transactions to send per batch"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("close_nth_batch")
|
||||
Arg::with_name("close_nth")
|
||||
.long("close-frequency")
|
||||
.takes_value(true)
|
||||
.value_name("BYTES")
|
||||
.help(
|
||||
"Every `n` batches, create a batch of close transactions for
|
||||
the earliest remaining batch of accounts created.
|
||||
Note: Should be > 1 to avoid situations where the close \
|
||||
"Send close transactions after this many accounts created. \
|
||||
Note: a `close-frequency` value near or below `batch-size` \
|
||||
may result in transaction-simulation errors, as the close \
|
||||
transactions will be submitted before the corresponding \
|
||||
create transactions have been confirmed",
|
||||
),
|
||||
@@ -637,7 +632,7 @@ fn main() {
|
||||
let space = value_t!(matches, "space", u64).ok();
|
||||
let lamports = value_t!(matches, "lamports", u64).ok();
|
||||
let batch_size = value_t!(matches, "batch_size", usize).unwrap_or(4);
|
||||
let close_nth_batch = value_t!(matches, "close_nth_batch", u64).unwrap_or(0);
|
||||
let close_nth = value_t!(matches, "close_nth", u64).unwrap_or(0);
|
||||
let iterations = value_t!(matches, "iterations", usize).unwrap_or(10);
|
||||
let num_instructions = value_t!(matches, "num_instructions", usize).unwrap_or(1);
|
||||
if num_instructions == 0 || num_instructions > 500 {
|
||||
@@ -662,14 +657,14 @@ fn main() {
|
||||
let rpc_addr = if !skip_gossip {
|
||||
info!("Finding cluster entry: {:?}", entrypoint_addr);
|
||||
let (gossip_nodes, _validators) = discover(
|
||||
None, // keypair
|
||||
None,
|
||||
Some(&entrypoint_addr),
|
||||
None, // num_nodes
|
||||
Duration::from_secs(60), // timeout
|
||||
None, // find_node_by_pubkey
|
||||
Some(&entrypoint_addr), // find_node_by_gossip_addr
|
||||
None, // my_gossip_addr
|
||||
0, // my_shred_version
|
||||
None,
|
||||
Some(60),
|
||||
None,
|
||||
Some(&entrypoint_addr),
|
||||
None,
|
||||
0,
|
||||
)
|
||||
.unwrap_or_else(|err| {
|
||||
eprintln!("Failed to discover {} node: {:?}", entrypoint_addr, err);
|
||||
@@ -690,7 +685,7 @@ fn main() {
|
||||
iterations,
|
||||
space,
|
||||
batch_size,
|
||||
close_nth_batch,
|
||||
close_nth,
|
||||
lamports,
|
||||
num_instructions,
|
||||
mint,
|
||||
@@ -725,7 +720,7 @@ pub mod test {
|
||||
let iterations = 10;
|
||||
let maybe_space = None;
|
||||
let batch_size = 100;
|
||||
let close_nth_batch = 100;
|
||||
let close_nth = 100;
|
||||
let maybe_lamports = None;
|
||||
let num_instructions = 2;
|
||||
let mut start = Measure::start("total accounts run");
|
||||
@@ -736,7 +731,7 @@ pub mod test {
|
||||
iterations,
|
||||
maybe_space,
|
||||
batch_size,
|
||||
close_nth_batch,
|
||||
close_nth,
|
||||
maybe_lamports,
|
||||
num_instructions,
|
||||
None,
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-banking-bench"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -14,18 +14,16 @@ crossbeam-channel = "0.4"
|
||||
log = "0.4.11"
|
||||
rand = "0.7.0"
|
||||
rayon = "1.5.0"
|
||||
solana-core = { path = "../core", version = "=1.7.2" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
|
||||
solana-gossip = { path = "../gossip", version = "=1.7.2" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.7.2" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.2" }
|
||||
solana-measure = { path = "../measure", version = "=1.7.2" }
|
||||
solana-perf = { path = "../perf", version = "=1.7.2" }
|
||||
solana-poh = { path = "../poh", version = "=1.7.2" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-version = { path = "../version", version = "=1.7.2" }
|
||||
solana-core = { path = "../core", version = "=1.6.7" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.7" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.7" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.7" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.7" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.7" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.7" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
solana-version = { path = "../version", version = "=1.6.7" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -4,8 +4,13 @@ use crossbeam_channel::unbounded;
|
||||
use log::*;
|
||||
use rand::{thread_rng, Rng};
|
||||
use rayon::prelude::*;
|
||||
use solana_core::banking_stage::BankingStage;
|
||||
use solana_gossip::{cluster_info::ClusterInfo, cluster_info::Node};
|
||||
use solana_core::{
|
||||
banking_stage::{create_test_recorder, BankingStage},
|
||||
cluster_info::ClusterInfo,
|
||||
cluster_info::Node,
|
||||
poh_recorder::PohRecorder,
|
||||
poh_recorder::WorkingBankEntry,
|
||||
};
|
||||
use solana_ledger::{
|
||||
blockstore::Blockstore,
|
||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||
@@ -13,7 +18,6 @@ use solana_ledger::{
|
||||
};
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_perf::packet::to_packets_chunked;
|
||||
use solana_poh::poh_recorder::{create_test_recorder, PohRecorder, WorkingBankEntry};
|
||||
use solana_runtime::{
|
||||
accounts_background_service::AbsRequestSender, bank::Bank, bank_forks::BankForks,
|
||||
};
|
||||
@@ -74,7 +78,7 @@ fn make_accounts_txs(
|
||||
.into_par_iter()
|
||||
.map(|_| {
|
||||
let mut new = dummy.clone();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
||||
if !same_payer {
|
||||
new.message.account_keys[0] = solana_sdk::pubkey::new_rand();
|
||||
}
|
||||
@@ -185,7 +189,7 @@ fn main() {
|
||||
genesis_config.hash(),
|
||||
);
|
||||
// Ignore any pesky duplicate signature errors in the case we are using single-payer
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
||||
fund.signatures = vec![Signature::new(&sig[0..64])];
|
||||
let x = bank.process_transaction(&fund);
|
||||
x.unwrap();
|
||||
@@ -351,7 +355,7 @@ fn main() {
|
||||
if bank.slot() > 0 && bank.slot() % 16 == 0 {
|
||||
for tx in transactions.iter_mut() {
|
||||
tx.message.recent_blockhash = bank.last_blockhash();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
||||
tx.signatures[0] = Signature::new(&sig[0..64]);
|
||||
}
|
||||
verified = to_packets_chunked(&transactions.clone(), packets_per_chunk);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-client"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
description = "Solana banks client"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -15,16 +15,16 @@ borsh = "0.8.1"
|
||||
borsh-derive = "0.8.1"
|
||||
futures = "0.3"
|
||||
mio = "0.7.6"
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.7.2" }
|
||||
solana-program = { path = "../sdk/program", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.6.7" }
|
||||
solana-program = { path = "../sdk/program", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
tarpc = { version = "0.24.1", features = ["full"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-serde = { version = "0.8", features = ["bincode"] }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.7.2" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.7" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.6.7" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-interface"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
description = "Solana banks RPC interface"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -12,7 +12,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
mio = "0.7.6"
|
||||
serde = { version = "1.0.122", features = ["derive"] }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
tarpc = { version = "0.24.1", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-server"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
description = "Solana banks server"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -14,10 +14,10 @@ bincode = "1.3.1"
|
||||
futures = "0.3"
|
||||
log = "0.4.11"
|
||||
mio = "0.7.6"
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.7.2" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.7.2" }
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.6.7" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.7" }
|
||||
tarpc = { version = "0.24.1", features = ["full"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-serde = { version = "0.8", features = ["bincode"] }
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-exchange"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -18,22 +18,21 @@ rand = "0.7.0"
|
||||
rayon = "1.5.0"
|
||||
serde_json = "1.0.56"
|
||||
serde_yaml = "0.8.13"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
|
||||
solana-core = { path = "../core", version = "=1.7.2" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.7.2" }
|
||||
solana-client = { path = "../client", version = "=1.7.2" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "=1.7.2" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.7.2" }
|
||||
solana-gossip = { path = "../gossip", version = "=1.7.2" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.2" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.7.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-version = { path = "../version", version = "=1.7.2" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.7" }
|
||||
solana-core = { path = "../core", version = "=1.6.7" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.6.7" }
|
||||
solana-client = { path = "../client", version = "=1.6.7" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.7" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "=1.6.7" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.7" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.7" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.7" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
solana-version = { path = "../version", version = "=1.6.7" }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.7.2" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.7" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -5,7 +5,7 @@ pub mod order_book;
|
||||
|
||||
use crate::bench::{airdrop_lamports, create_client_accounts_file, do_bench_exchange, Config};
|
||||
use log::*;
|
||||
use solana_gossip::gossip_service::{discover_cluster, get_multi_client};
|
||||
use solana_core::gossip_service::{discover_cluster, get_multi_client};
|
||||
use solana_sdk::signature::Signer;
|
||||
|
||||
fn main() {
|
||||
|
@@ -1,11 +1,13 @@
|
||||
use log::*;
|
||||
use solana_bench_exchange::bench::{airdrop_lamports, do_bench_exchange, Config};
|
||||
use solana_core::validator::ValidatorConfig;
|
||||
use solana_core::{
|
||||
gossip_service::{discover_cluster, get_multi_client},
|
||||
validator::ValidatorConfig,
|
||||
};
|
||||
use solana_exchange_program::{
|
||||
exchange_processor::process_instruction, id, solana_exchange_program,
|
||||
};
|
||||
use solana_faucet::faucet::run_local_faucet_with_port;
|
||||
use solana_gossip::gossip_service::{discover_cluster, get_multi_client};
|
||||
use solana_local_cluster::{
|
||||
local_cluster::{ClusterConfig, LocalCluster},
|
||||
validator_configs::make_identical_validator_configs,
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-streamer"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -10,11 +10,11 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.1"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.7.2" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
|
||||
solana-version = { path = "../version", version = "=1.7.2" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.7" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.7" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.7" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.7" }
|
||||
solana-version = { path = "../version", version = "=1.6.7" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -75,7 +75,7 @@ fn main() -> Result<()> {
|
||||
|
||||
let mut read_channels = Vec::new();
|
||||
let mut read_threads = Vec::new();
|
||||
let recycler = PacketsRecycler::default();
|
||||
let recycler = PacketsRecycler::new_without_limit("bench-streamer-recycler-shrink-stats");
|
||||
for _ in 0..num_sockets {
|
||||
let read = solana_net_utils::bind_to(ip_addr, port, false).unwrap();
|
||||
read.set_read_timeout(Some(Duration::new(1, 0))).unwrap();
|
||||
@@ -92,7 +92,6 @@ fn main() -> Result<()> {
|
||||
recycler.clone(),
|
||||
"bench-streamer-test",
|
||||
1,
|
||||
true,
|
||||
));
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-tps"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -15,23 +15,22 @@ log = "0.4.11"
|
||||
rayon = "1.5.0"
|
||||
serde_json = "1.0.56"
|
||||
serde_yaml = "0.8.13"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
|
||||
solana-core = { path = "../core", version = "=1.7.2" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.7.2" }
|
||||
solana-client = { path = "../client", version = "=1.7.2" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.7.2" }
|
||||
solana-gossip = { path = "../gossip", version = "=1.7.2" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.2" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.7.2" }
|
||||
solana-measure = { path = "../measure", version = "=1.7.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-version = { path = "../version", version = "=1.7.2" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.7" }
|
||||
solana-core = { path = "../core", version = "=1.6.7" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.6.7" }
|
||||
solana-client = { path = "../client", version = "=1.6.7" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.7" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.7" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.7" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.7" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.7" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
solana-version = { path = "../version", version = "=1.6.7" }
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "0.4.0"
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.7.2" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.7" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -2,8 +2,8 @@
|
||||
use log::*;
|
||||
use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs, generate_keypairs};
|
||||
use solana_bench_tps::cli;
|
||||
use solana_core::gossip_service::{discover_cluster, get_client, get_multi_client};
|
||||
use solana_genesis::Base64Account;
|
||||
use solana_gossip::gossip_service::{discover_cluster, get_client, get_multi_client};
|
||||
use solana_sdk::fee_calculator::FeeRateGovernor;
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use solana_sdk::system_program;
|
||||
|
@@ -5,9 +5,8 @@ use solana_bench_tps::{
|
||||
cli::Config,
|
||||
};
|
||||
use solana_client::thin_client::create_client;
|
||||
use solana_core::validator::ValidatorConfig;
|
||||
use solana_core::{cluster_info::VALIDATOR_PORT_RANGE, validator::ValidatorConfig};
|
||||
use solana_faucet::faucet::run_local_faucet_with_port;
|
||||
use solana_gossip::cluster_info::VALIDATOR_PORT_RANGE;
|
||||
use solana_local_cluster::{
|
||||
local_cluster::{ClusterConfig, LocalCluster},
|
||||
validator_configs::make_identical_validator_configs,
|
||||
|
@@ -5,6 +5,9 @@ steps:
|
||||
- command: "ci/publish-tarball.sh"
|
||||
timeout_in_minutes: 60
|
||||
name: "publish tarball"
|
||||
- command: "ci/publish-bpf-sdk.sh"
|
||||
timeout_in_minutes: 5
|
||||
name: "publish bpf sdk"
|
||||
- wait
|
||||
- command: "sdk/docker-solana/build.sh"
|
||||
timeout_in_minutes: 60
|
||||
|
@@ -1,4 +1,4 @@
|
||||
FROM solanalabs/rust:1.52.1
|
||||
FROM solanalabs/rust:1.51.0
|
||||
ARG date
|
||||
|
||||
RUN set -x \
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# Note: when the rust version is changed also modify
|
||||
# ci/rust-version.sh to pick up the new image tag
|
||||
FROM rust:1.52.1
|
||||
FROM rust:1.51.0
|
||||
|
||||
# Add Google Protocol Buffers for Libra's metrics library.
|
||||
ENV PROTOC_VERSION 3.8.0
|
||||
|
27
ci/publish-bpf-sdk.sh
Executable file
27
ci/publish-bpf-sdk.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
eval "$(ci/channel-info.sh)"
|
||||
|
||||
if [[ -n "$CI_TAG" ]]; then
|
||||
CHANNEL_OR_TAG=$CI_TAG
|
||||
else
|
||||
CHANNEL_OR_TAG=$CHANNEL
|
||||
fi
|
||||
|
||||
(
|
||||
set -x
|
||||
sdk/bpf/scripts/package.sh
|
||||
[[ -f bpf-sdk.tar.bz2 ]]
|
||||
)
|
||||
|
||||
source ci/upload-ci-artifact.sh
|
||||
echo --- AWS S3 Store
|
||||
if [[ -z $CHANNEL_OR_TAG ]]; then
|
||||
echo Skipped
|
||||
else
|
||||
upload-s3-artifact "/solana/bpf-sdk.tar.bz2" "s3://solana-sdk/$CHANNEL_OR_TAG/bpf-sdk.tar.bz2"
|
||||
fi
|
||||
|
||||
exit 0
|
@@ -7,7 +7,7 @@ source multinode-demo/common.sh
|
||||
|
||||
rm -rf config/run/init-completed config/ledger config/snapshot-ledger
|
||||
|
||||
SOLANA_RUN_SH_VALIDATOR_ARGS="--snapshot-interval-slots 200" timeout 120 ./run.sh &
|
||||
timeout 120 ./run.sh &
|
||||
pid=$!
|
||||
|
||||
attempts=20
|
||||
@@ -16,8 +16,6 @@ while [[ ! -f config/run/init-completed ]]; do
|
||||
if ((--attempts == 0)); then
|
||||
echo "Error: validator failed to boot"
|
||||
exit 1
|
||||
else
|
||||
echo "Checking init"
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -26,7 +24,6 @@ snapshot_slot=1
|
||||
# wait a bit longer than snapshot_slot
|
||||
while [[ $($solana_cli --url http://localhost:8899 slot --commitment processed) -le $((snapshot_slot + 1)) ]]; do
|
||||
sleep 1
|
||||
echo "Checking slot"
|
||||
done
|
||||
|
||||
$solana_validator --ledger config/ledger exit --force || true
|
||||
|
@@ -18,13 +18,13 @@
|
||||
if [[ -n $RUST_STABLE_VERSION ]]; then
|
||||
stable_version="$RUST_STABLE_VERSION"
|
||||
else
|
||||
stable_version=1.52.1
|
||||
stable_version=1.51.0
|
||||
fi
|
||||
|
||||
if [[ -n $RUST_NIGHTLY_VERSION ]]; then
|
||||
nightly_version="$RUST_NIGHTLY_VERSION"
|
||||
else
|
||||
nightly_version=2021-05-18
|
||||
nightly_version=2021-04-18
|
||||
fi
|
||||
|
||||
|
||||
|
@@ -27,7 +27,7 @@ BENCH_ARTIFACT=current_bench_results.log
|
||||
_ "$cargo" build --manifest-path=keygen/Cargo.toml
|
||||
export PATH="$PWD/target/debug":$PATH
|
||||
|
||||
# Clear the C dependency files, if dependency moves these files are not regenerated
|
||||
# Clear the C dependency files, if dependeny moves these files are not regenerated
|
||||
test -d target/debug/bpf && find target/debug/bpf -name '*.d' -delete
|
||||
test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
|
||||
|
||||
@@ -45,14 +45,6 @@ _ "$cargo" nightly bench --manifest-path sdk/Cargo.toml ${V:+--verbose} \
|
||||
_ "$cargo" nightly bench --manifest-path runtime/Cargo.toml ${V:+--verbose} \
|
||||
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
|
||||
|
||||
# Run gossip benches
|
||||
_ "$cargo" nightly bench --manifest-path gossip/Cargo.toml ${V:+--verbose} \
|
||||
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
|
||||
|
||||
# Run poh benches
|
||||
_ "$cargo" nightly bench --manifest-path poh/Cargo.toml ${V:+--verbose} \
|
||||
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
|
||||
|
||||
# Run core benches
|
||||
_ "$cargo" nightly bench --manifest-path core/Cargo.toml ${V:+--verbose} \
|
||||
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
|
||||
|
@@ -44,7 +44,7 @@ test-stable-perf)
|
||||
./cargo-build-bpf --manifest-path sdk/Cargo.toml
|
||||
|
||||
# BPF Program unit tests
|
||||
"$cargo" test --manifest-path programs/bpf/Cargo.toml
|
||||
"$cargo" stable test --manifest-path programs/bpf/Cargo.toml
|
||||
cargo-build-bpf --manifest-path programs/bpf/Cargo.toml --bpf-sdk sdk/bpf
|
||||
|
||||
# BPF program system tests
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-clap-utils"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
description = "Solana utilities for the clap"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -12,8 +12,8 @@ edition = "2018"
|
||||
[dependencies]
|
||||
clap = "2.33.0"
|
||||
rpassword = "4.0"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
thiserror = "1.0.21"
|
||||
tiny-bip39 = "0.8.0"
|
||||
uriparse = "0.6.3"
|
||||
|
@@ -17,9 +17,6 @@ use {
|
||||
std::{str::FromStr, sync::Arc},
|
||||
};
|
||||
|
||||
// Sentinel value used to indicate to write to screen instead of file
|
||||
pub const STDOUT_OUTFILE_TOKEN: &str = "-";
|
||||
|
||||
// Return parsed values from matches at `name`
|
||||
pub fn values_of<T>(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<T>>
|
||||
where
|
||||
@@ -60,7 +57,7 @@ pub fn keypair_of(matches: &ArgMatches<'_>, name: &str) -> Option<Keypair> {
|
||||
if let Some(value) = matches.value_of(name) {
|
||||
if value == ASK_KEYWORD {
|
||||
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
|
||||
keypair_from_seed_phrase(name, skip_validation, true, None, true).ok()
|
||||
keypair_from_seed_phrase(name, skip_validation, true, None).ok()
|
||||
} else {
|
||||
read_keypair_file(value).ok()
|
||||
}
|
||||
@@ -75,7 +72,7 @@ pub fn keypairs_of(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<Keypair>>
|
||||
.filter_map(|value| {
|
||||
if value == ASK_KEYWORD {
|
||||
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
|
||||
keypair_from_seed_phrase(name, skip_validation, true, None, true).ok()
|
||||
keypair_from_seed_phrase(name, skip_validation, true, None).ok()
|
||||
} else {
|
||||
read_keypair_file(value).ok()
|
||||
}
|
||||
|
@@ -96,26 +96,6 @@ where
|
||||
.map_err(|err| format!("{}", err))
|
||||
}
|
||||
|
||||
// Return an error if a `SignerSourceKind::Prompt` cannot be parsed
|
||||
pub fn is_prompt_signer_source<T>(string: T) -> Result<(), String>
|
||||
where
|
||||
T: AsRef<str> + Display,
|
||||
{
|
||||
if string.as_ref() == ASK_KEYWORD {
|
||||
return Ok(());
|
||||
}
|
||||
match parse_signer_source(string.as_ref())
|
||||
.map_err(|err| format!("{}", err))?
|
||||
.kind
|
||||
{
|
||||
SignerSourceKind::Prompt => Ok(()),
|
||||
_ => Err(format!(
|
||||
"Unable to parse input as `prompt:` URI scheme or `ASK` keyword: {}",
|
||||
string
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
// Return an error if string cannot be parsed as pubkey string or keypair file location
|
||||
pub fn is_pubkey_or_keypair<T>(string: T) -> Result<(), String>
|
||||
where
|
||||
@@ -215,8 +195,8 @@ where
|
||||
pub fn normalize_to_url_if_moniker<T: AsRef<str>>(url_or_moniker: T) -> String {
|
||||
match url_or_moniker.as_ref() {
|
||||
"m" | "mainnet-beta" => "https://api.mainnet-beta.solana.com",
|
||||
"t" | "testnet" => "https://api.testnet.solana.com",
|
||||
"d" | "devnet" => "https://api.devnet.solana.com",
|
||||
"t" | "testnet" => "https://testnet.solana.com",
|
||||
"d" | "devnet" => "https://devnet.solana.com",
|
||||
"l" | "localhost" => "http://localhost:8899",
|
||||
url => url,
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
use {
|
||||
crate::{
|
||||
input_parsers::{pubkeys_sigs_of, STDOUT_OUTFILE_TOKEN},
|
||||
input_parsers::pubkeys_sigs_of,
|
||||
offline::{SIGNER_ARG, SIGN_ONLY_ARG},
|
||||
ArgConstant,
|
||||
},
|
||||
@@ -18,17 +18,14 @@ use {
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
signature::{
|
||||
generate_seed_from_seed_phrase_and_passphrase, keypair_from_seed,
|
||||
keypair_from_seed_and_derivation_path, keypair_from_seed_phrase_and_passphrase,
|
||||
generate_seed_from_seed_phrase_and_passphrase, keypair_from_seed_and_derivation_path,
|
||||
read_keypair, read_keypair_file, Keypair, NullSigner, Presigner, Signature, Signer,
|
||||
},
|
||||
},
|
||||
std::{
|
||||
cell::RefCell,
|
||||
convert::TryFrom,
|
||||
error,
|
||||
io::{stdin, stdout, Write},
|
||||
ops::Deref,
|
||||
process::exit,
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
@@ -92,48 +89,12 @@ impl CliSignerInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct DefaultSigner {
|
||||
pub arg_name: String,
|
||||
pub path: String,
|
||||
is_path_checked: RefCell<bool>,
|
||||
}
|
||||
|
||||
impl DefaultSigner {
|
||||
pub fn new<AN: AsRef<str>, P: AsRef<str>>(arg_name: AN, path: P) -> Self {
|
||||
let arg_name = arg_name.as_ref().to_string();
|
||||
let path = path.as_ref().to_string();
|
||||
Self {
|
||||
arg_name,
|
||||
path,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn path(&self) -> Result<&str, Box<dyn std::error::Error>> {
|
||||
if !self.is_path_checked.borrow().deref() {
|
||||
parse_signer_source(&self.path)
|
||||
.and_then(|s| {
|
||||
if let SignerSourceKind::Filepath(path) = &s.kind {
|
||||
std::fs::metadata(path).map(|_| ()).map_err(|e| e.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
.map_err(|_| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"No default signer found, run \"solana-keygen new -o {}\" to create a new one",
|
||||
self.path
|
||||
),
|
||||
)
|
||||
})?;
|
||||
*self.is_path_checked.borrow_mut() = true;
|
||||
}
|
||||
Ok(&self.path)
|
||||
}
|
||||
|
||||
pub fn generate_unique_signers(
|
||||
&self,
|
||||
bulk_signers: Vec<Option<Box<dyn Signer>>>,
|
||||
@@ -163,7 +124,7 @@ impl DefaultSigner {
|
||||
matches: &ArgMatches,
|
||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||
) -> Result<Box<dyn Signer>, Box<dyn std::error::Error>> {
|
||||
signer_from_path(matches, self.path()?, &self.arg_name, wallet_manager)
|
||||
signer_from_path(matches, &self.path, &self.arg_name, wallet_manager)
|
||||
}
|
||||
|
||||
pub fn signer_from_path_with_config(
|
||||
@@ -172,20 +133,13 @@ impl DefaultSigner {
|
||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||
config: &SignerFromPathConfig,
|
||||
) -> Result<Box<dyn Signer>, Box<dyn std::error::Error>> {
|
||||
signer_from_path_with_config(
|
||||
matches,
|
||||
self.path()?,
|
||||
&self.arg_name,
|
||||
wallet_manager,
|
||||
config,
|
||||
)
|
||||
signer_from_path_with_config(matches, &self.path, &self.arg_name, wallet_manager, config)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SignerSource {
|
||||
pub kind: SignerSourceKind,
|
||||
pub derivation_path: Option<DerivationPath>,
|
||||
pub legacy: bool,
|
||||
}
|
||||
|
||||
impl SignerSource {
|
||||
@@ -193,52 +147,18 @@ impl SignerSource {
|
||||
Self {
|
||||
kind,
|
||||
derivation_path: None,
|
||||
legacy: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_legacy(kind: SignerSourceKind) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
derivation_path: None,
|
||||
legacy: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const SIGNER_SOURCE_PROMPT: &str = "prompt";
|
||||
const SIGNER_SOURCE_FILEPATH: &str = "file";
|
||||
const SIGNER_SOURCE_USB: &str = "usb";
|
||||
const SIGNER_SOURCE_STDIN: &str = "stdin";
|
||||
const SIGNER_SOURCE_PUBKEY: &str = "pubkey";
|
||||
|
||||
pub(crate) enum SignerSourceKind {
|
||||
Prompt,
|
||||
Ask,
|
||||
Filepath(String),
|
||||
Usb(RemoteWalletLocator),
|
||||
Stdin,
|
||||
Pubkey(Pubkey),
|
||||
}
|
||||
|
||||
impl AsRef<str> for SignerSourceKind {
|
||||
fn as_ref(&self) -> &str {
|
||||
match self {
|
||||
Self::Prompt => SIGNER_SOURCE_PROMPT,
|
||||
Self::Filepath(_) => SIGNER_SOURCE_FILEPATH,
|
||||
Self::Usb(_) => SIGNER_SOURCE_USB,
|
||||
Self::Stdin => SIGNER_SOURCE_STDIN,
|
||||
Self::Pubkey(_) => SIGNER_SOURCE_PUBKEY,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SignerSourceKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let s: &str = self.as_ref();
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum SignerSourceError {
|
||||
#[error("unrecognized signer source")]
|
||||
@@ -255,54 +175,36 @@ pub(crate) fn parse_signer_source<S: AsRef<str>>(
|
||||
source: S,
|
||||
) -> Result<SignerSource, SignerSourceError> {
|
||||
let source = source.as_ref();
|
||||
let source = {
|
||||
#[cfg(target_family = "windows")]
|
||||
{
|
||||
source.replace("\\", "/")
|
||||
}
|
||||
#[cfg(not(target_family = "windows"))]
|
||||
{
|
||||
source.to_string()
|
||||
}
|
||||
};
|
||||
match uriparse::URIReference::try_from(source.as_str()) {
|
||||
match uriparse::URIReference::try_from(source) {
|
||||
Err(_) => Err(SignerSourceError::UnrecognizedSource),
|
||||
Ok(uri) => {
|
||||
if let Some(scheme) = uri.scheme() {
|
||||
let scheme = scheme.as_str().to_ascii_lowercase();
|
||||
match scheme.as_str() {
|
||||
SIGNER_SOURCE_PROMPT => Ok(SignerSource {
|
||||
kind: SignerSourceKind::Prompt,
|
||||
"ask" => Ok(SignerSource {
|
||||
kind: SignerSourceKind::Ask,
|
||||
derivation_path: DerivationPath::from_uri_any_query(&uri)?,
|
||||
legacy: false,
|
||||
}),
|
||||
SIGNER_SOURCE_FILEPATH => Ok(SignerSource::new(SignerSourceKind::Filepath(
|
||||
"file" => Ok(SignerSource::new(SignerSourceKind::Filepath(
|
||||
uri.path().to_string(),
|
||||
))),
|
||||
SIGNER_SOURCE_USB => Ok(SignerSource {
|
||||
"stdin" => Ok(SignerSource::new(SignerSourceKind::Stdin)),
|
||||
"usb" => Ok(SignerSource {
|
||||
kind: SignerSourceKind::Usb(RemoteWalletLocator::new_from_uri(&uri)?),
|
||||
derivation_path: DerivationPath::from_uri_key_query(&uri)?,
|
||||
legacy: false,
|
||||
}),
|
||||
SIGNER_SOURCE_STDIN => Ok(SignerSource::new(SignerSourceKind::Stdin)),
|
||||
_ => {
|
||||
#[cfg(target_family = "windows")]
|
||||
// On Windows, an absolute path's drive letter will be parsed as the URI
|
||||
// scheme. Assume a filepath source in case of a single character shceme.
|
||||
if scheme.len() == 1 {
|
||||
return Ok(SignerSource::new(SignerSourceKind::Filepath(source)));
|
||||
}
|
||||
Err(SignerSourceError::UnrecognizedSource)
|
||||
}
|
||||
_ => Err(SignerSourceError::UnrecognizedSource),
|
||||
}
|
||||
} else {
|
||||
match source.as_str() {
|
||||
STDOUT_OUTFILE_TOKEN => Ok(SignerSource::new(SignerSourceKind::Stdin)),
|
||||
ASK_KEYWORD => Ok(SignerSource::new_legacy(SignerSourceKind::Prompt)),
|
||||
_ => match Pubkey::from_str(source.as_str()) {
|
||||
match source {
|
||||
"-" => Ok(SignerSource::new(SignerSourceKind::Stdin)),
|
||||
ASK_KEYWORD => Ok(SignerSource::new(SignerSourceKind::Ask)),
|
||||
_ => match Pubkey::from_str(source) {
|
||||
Ok(pubkey) => Ok(SignerSource::new(SignerSourceKind::Pubkey(pubkey))),
|
||||
Err(_) => std::fs::metadata(source.as_str())
|
||||
.map(|_| SignerSource::new(SignerSourceKind::Filepath(source)))
|
||||
Err(_) => std::fs::metadata(source)
|
||||
.map(|_| {
|
||||
SignerSource::new(SignerSourceKind::Filepath(source.to_string()))
|
||||
})
|
||||
.map_err(|err| err.into()),
|
||||
},
|
||||
}
|
||||
@@ -357,17 +259,15 @@ pub fn signer_from_path_with_config(
|
||||
let SignerSource {
|
||||
kind,
|
||||
derivation_path,
|
||||
legacy,
|
||||
} = parse_signer_source(path)?;
|
||||
match kind {
|
||||
SignerSourceKind::Prompt => {
|
||||
SignerSourceKind::Ask => {
|
||||
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
|
||||
Ok(Box::new(keypair_from_seed_phrase(
|
||||
keypair_name,
|
||||
skip_validation,
|
||||
false,
|
||||
derivation_path,
|
||||
legacy,
|
||||
)?))
|
||||
}
|
||||
SignerSourceKind::Filepath(path) => match read_keypair_file(&path) {
|
||||
@@ -439,30 +339,18 @@ pub fn resolve_signer_from_path(
|
||||
let SignerSource {
|
||||
kind,
|
||||
derivation_path,
|
||||
legacy,
|
||||
} = parse_signer_source(path)?;
|
||||
match kind {
|
||||
SignerSourceKind::Prompt => {
|
||||
SignerSourceKind::Ask => {
|
||||
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
|
||||
// This method validates the seed phrase, but returns `None` because there is no path
|
||||
// on disk or to a device
|
||||
keypair_from_seed_phrase(
|
||||
keypair_name,
|
||||
skip_validation,
|
||||
false,
|
||||
derivation_path,
|
||||
legacy,
|
||||
)
|
||||
.map(|_| None)
|
||||
keypair_from_seed_phrase(keypair_name, skip_validation, false, derivation_path).map(|_| None)
|
||||
}
|
||||
SignerSourceKind::Filepath(path) => match read_keypair_file(&path) {
|
||||
Err(e) => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"could not read keypair file \"{}\". \
|
||||
Run \"solana-keygen new\" to create a keypair file: {}",
|
||||
path, e
|
||||
),
|
||||
format!("could not read keypair file \"{}\". Run \"solana-keygen new\" to create a keypair file: {}", path, e),
|
||||
)
|
||||
.into()),
|
||||
Ok(_) => Ok(Some(path.to_string())),
|
||||
@@ -495,7 +383,7 @@ pub fn resolve_signer_from_path(
|
||||
}
|
||||
}
|
||||
|
||||
// Keyword used to indicate that the user should be prompted for a keypair seed phrase
|
||||
// Keyword used to indicate that the user should be asked for a keypair seed phrase
|
||||
pub const ASK_KEYWORD: &str = "ASK";
|
||||
|
||||
pub const SKIP_SEED_PHRASE_VALIDATION_ARG: ArgConstant<'static> = ArgConstant {
|
||||
@@ -516,56 +404,6 @@ pub fn prompt_passphrase(prompt: &str) -> Result<String, Box<dyn error::Error>>
|
||||
Ok(passphrase)
|
||||
}
|
||||
|
||||
/// Parses a path into a SignerSource and returns a Keypair for supporting SignerSourceKinds
|
||||
pub fn keypair_from_path(
|
||||
matches: &ArgMatches,
|
||||
path: &str,
|
||||
keypair_name: &str,
|
||||
confirm_pubkey: bool,
|
||||
) -> Result<Keypair, Box<dyn error::Error>> {
|
||||
let SignerSource {
|
||||
kind,
|
||||
derivation_path,
|
||||
legacy,
|
||||
} = parse_signer_source(path)?;
|
||||
match kind {
|
||||
SignerSourceKind::Prompt => {
|
||||
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
|
||||
Ok(keypair_from_seed_phrase(
|
||||
keypair_name,
|
||||
skip_validation,
|
||||
confirm_pubkey,
|
||||
derivation_path,
|
||||
legacy,
|
||||
)?)
|
||||
}
|
||||
SignerSourceKind::Filepath(path) => match read_keypair_file(&path) {
|
||||
Err(e) => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"could not read keypair file \"{}\". \
|
||||
Run \"solana-keygen new\" to create a keypair file: {}",
|
||||
path, e
|
||||
),
|
||||
)
|
||||
.into()),
|
||||
Ok(file) => Ok(file),
|
||||
},
|
||||
SignerSourceKind::Stdin => {
|
||||
let mut stdin = std::io::stdin();
|
||||
Ok(read_keypair(&mut stdin)?)
|
||||
}
|
||||
_ => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"signer of type `{:?}` does not support Keypair output",
|
||||
kind
|
||||
),
|
||||
)
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads user input from stdin to retrieve a seed phrase and passphrase for keypair derivation
|
||||
/// Optionally skips validation of seed phrase
|
||||
/// Optionally confirms recovered public key
|
||||
@@ -574,7 +412,6 @@ pub fn keypair_from_seed_phrase(
|
||||
skip_validation: bool,
|
||||
confirm_pubkey: bool,
|
||||
derivation_path: Option<DerivationPath>,
|
||||
legacy: bool,
|
||||
) -> Result<Keypair, Box<dyn error::Error>> {
|
||||
let seed_phrase = prompt_password_stderr(&format!("[{}] seed phrase: ", keypair_name))?;
|
||||
let seed_phrase = seed_phrase.trim();
|
||||
@@ -585,12 +422,8 @@ pub fn keypair_from_seed_phrase(
|
||||
|
||||
let keypair = if skip_validation {
|
||||
let passphrase = prompt_passphrase(&passphrase_prompt)?;
|
||||
if legacy {
|
||||
keypair_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase)?
|
||||
} else {
|
||||
let seed = generate_seed_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase);
|
||||
keypair_from_seed_and_derivation_path(&seed, derivation_path)?
|
||||
}
|
||||
let seed = generate_seed_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase);
|
||||
keypair_from_seed_and_derivation_path(&seed, derivation_path)?
|
||||
} else {
|
||||
let sanitized = sanitize_seed_phrase(seed_phrase);
|
||||
let parse_language_fn = || {
|
||||
@@ -613,11 +446,7 @@ pub fn keypair_from_seed_phrase(
|
||||
let mnemonic = parse_language_fn()?;
|
||||
let passphrase = prompt_passphrase(&passphrase_prompt)?;
|
||||
let seed = Seed::new(&mnemonic, &passphrase);
|
||||
if legacy {
|
||||
keypair_from_seed(seed.as_bytes())?
|
||||
} else {
|
||||
keypair_from_seed_and_derivation_path(&seed.as_bytes(), derivation_path)?
|
||||
}
|
||||
keypair_from_seed_and_derivation_path(&seed.as_bytes(), derivation_path)?
|
||||
};
|
||||
|
||||
if confirm_pubkey {
|
||||
@@ -692,28 +521,25 @@ mod tests {
|
||||
#[test]
|
||||
fn test_parse_signer_source() {
|
||||
assert!(matches!(
|
||||
parse_signer_source(STDOUT_OUTFILE_TOKEN).unwrap(),
|
||||
parse_signer_source("-").unwrap(),
|
||||
SignerSource {
|
||||
kind: SignerSourceKind::Stdin,
|
||||
derivation_path: None,
|
||||
legacy: false,
|
||||
}
|
||||
));
|
||||
let stdin = "stdin:".to_string();
|
||||
let ask = "stdin:".to_string();
|
||||
assert!(matches!(
|
||||
parse_signer_source(&stdin).unwrap(),
|
||||
parse_signer_source(&ask).unwrap(),
|
||||
SignerSource {
|
||||
kind: SignerSourceKind::Stdin,
|
||||
derivation_path: None,
|
||||
legacy: false,
|
||||
}
|
||||
));
|
||||
assert!(matches!(
|
||||
parse_signer_source(ASK_KEYWORD).unwrap(),
|
||||
SignerSource {
|
||||
kind: SignerSourceKind::Prompt,
|
||||
kind: SignerSourceKind::Ask,
|
||||
derivation_path: None,
|
||||
legacy: true,
|
||||
}
|
||||
));
|
||||
let pubkey = Pubkey::new_unique();
|
||||
@@ -721,7 +547,6 @@ mod tests {
|
||||
matches!(parse_signer_source(&pubkey.to_string()).unwrap(), SignerSource {
|
||||
kind: SignerSourceKind::Pubkey(p),
|
||||
derivation_path: None,
|
||||
legacy: false,
|
||||
}
|
||||
if p == pubkey)
|
||||
);
|
||||
@@ -742,14 +567,12 @@ mod tests {
|
||||
matches!(parse_signer_source(absolute_path_str).unwrap(), SignerSource {
|
||||
kind: SignerSourceKind::Filepath(p),
|
||||
derivation_path: None,
|
||||
legacy: false,
|
||||
} if p == absolute_path_str)
|
||||
);
|
||||
assert!(
|
||||
matches!(parse_signer_source(&relative_path_str).unwrap(), SignerSource {
|
||||
kind: SignerSourceKind::Filepath(p),
|
||||
derivation_path: None,
|
||||
legacy: false,
|
||||
} if p == relative_path_str)
|
||||
);
|
||||
|
||||
@@ -761,7 +584,6 @@ mod tests {
|
||||
assert!(matches!(parse_signer_source(&usb).unwrap(), SignerSource {
|
||||
kind: SignerSourceKind::Usb(u),
|
||||
derivation_path: None,
|
||||
legacy: false,
|
||||
} if u == expected_locator));
|
||||
let usb = "usb://ledger?key=0/0".to_string();
|
||||
let expected_locator = RemoteWalletLocator {
|
||||
@@ -772,7 +594,6 @@ mod tests {
|
||||
assert!(matches!(parse_signer_source(&usb).unwrap(), SignerSource {
|
||||
kind: SignerSourceKind::Usb(u),
|
||||
derivation_path: d,
|
||||
legacy: false,
|
||||
} if u == expected_locator && d == expected_derivation_path));
|
||||
// Catchall into SignerSource::Filepath fails
|
||||
let junk = "sometextthatisnotapubkeyorfile".to_string();
|
||||
@@ -782,27 +603,24 @@ mod tests {
|
||||
Err(SignerSourceError::IoError(_))
|
||||
));
|
||||
|
||||
let prompt = "prompt:".to_string();
|
||||
let ask = "ask:".to_string();
|
||||
assert!(matches!(
|
||||
parse_signer_source(&prompt).unwrap(),
|
||||
parse_signer_source(&ask).unwrap(),
|
||||
SignerSource {
|
||||
kind: SignerSourceKind::Prompt,
|
||||
kind: SignerSourceKind::Ask,
|
||||
derivation_path: None,
|
||||
legacy: false,
|
||||
}
|
||||
));
|
||||
assert!(
|
||||
matches!(parse_signer_source(&format!("file:{}", absolute_path_str)).unwrap(), SignerSource {
|
||||
kind: SignerSourceKind::Filepath(p),
|
||||
derivation_path: None,
|
||||
legacy: false,
|
||||
} if p == absolute_path_str)
|
||||
);
|
||||
assert!(
|
||||
matches!(parse_signer_source(&format!("file:{}", relative_path_str)).unwrap(), SignerSource {
|
||||
kind: SignerSourceKind::Filepath(p),
|
||||
derivation_path: None,
|
||||
legacy: false,
|
||||
} if p == relative_path_str)
|
||||
);
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli-config"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
|
@@ -107,13 +107,13 @@ mod test {
|
||||
#[test]
|
||||
fn compute_websocket_url() {
|
||||
assert_eq!(
|
||||
Config::compute_websocket_url(&"http://api.devnet.solana.com"),
|
||||
"ws://api.devnet.solana.com/".to_string()
|
||||
Config::compute_websocket_url(&"http://devnet.solana.com"),
|
||||
"ws://devnet.solana.com/".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Config::compute_websocket_url(&"https://api.devnet.solana.com"),
|
||||
"wss://api.devnet.solana.com/".to_string()
|
||||
Config::compute_websocket_url(&"https://devnet.solana.com"),
|
||||
"wss://devnet.solana.com/".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli-output"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -12,19 +12,20 @@ documentation = "https://docs.rs/solana-cli-output"
|
||||
[dependencies]
|
||||
base64 = "0.13.0"
|
||||
chrono = { version = "0.4.11", features = ["serde"] }
|
||||
console = "0.14.1"
|
||||
console = "0.11.3"
|
||||
humantime = "2.0.1"
|
||||
Inflector = "0.11.4"
|
||||
indicatif = "0.15.0"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
|
||||
solana-client = { path = "../client", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.7" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.7" }
|
||||
solana-client = { path = "../client", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.7" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.7" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.7" }
|
||||
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
|
@@ -15,8 +15,8 @@ use {
|
||||
solana_account_decoder::parse_token::UiTokenAccount,
|
||||
solana_clap_utils::keypair::SignOnly,
|
||||
solana_client::rpc_response::{
|
||||
RpcAccountBalance, RpcContactInfo, RpcInflationGovernor, RpcInflationRate, RpcKeyedAccount,
|
||||
RpcSupply, RpcVoteAccountInfo,
|
||||
RpcAccountBalance, RpcInflationGovernor, RpcInflationRate, RpcKeyedAccount, RpcSupply,
|
||||
RpcVoteAccountInfo,
|
||||
},
|
||||
solana_sdk::{
|
||||
clock::{Epoch, Slot, UnixTimestamp},
|
||||
@@ -25,10 +25,10 @@ use {
|
||||
native_token::lamports_to_sol,
|
||||
pubkey::Pubkey,
|
||||
signature::Signature,
|
||||
stake::state::{Authorized, Lockup},
|
||||
stake_history::StakeHistoryEntry,
|
||||
transaction::{Transaction, TransactionError},
|
||||
},
|
||||
solana_stake_program::stake_state::{Authorized, Lockup},
|
||||
solana_transaction_status::{
|
||||
EncodedConfirmedBlock, EncodedTransaction, TransactionConfirmationStatus,
|
||||
UiTransactionStatusMeta,
|
||||
@@ -2126,9 +2126,6 @@ impl fmt::Display for CliBlock {
|
||||
if let Some(block_time) = self.encoded_confirmed_block.block_time {
|
||||
writeln!(f, "Block Time: {:?}", Local.timestamp(block_time, 0))?;
|
||||
}
|
||||
if let Some(block_height) = self.encoded_confirmed_block.block_height {
|
||||
writeln!(f, "Block Height: {:?}", block_height)?;
|
||||
}
|
||||
if !self.encoded_confirmed_block.rewards.is_empty() {
|
||||
let mut rewards = self.encoded_confirmed_block.rewards.clone();
|
||||
rewards.sort_by(|a, b| a.pubkey.cmp(&b.pubkey));
|
||||
@@ -2286,97 +2283,6 @@ impl fmt::Display for CliTransactionConfirmation {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliGossipNode {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ip_address: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub identity_label: Option<String>,
|
||||
pub identity_pubkey: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub gossip_port: Option<u16>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tpu_port: Option<u16>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rpc_host: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub version: Option<String>,
|
||||
}
|
||||
|
||||
impl CliGossipNode {
|
||||
pub fn new(info: RpcContactInfo, labels: &HashMap<String, String>) -> Self {
|
||||
Self {
|
||||
ip_address: info.gossip.map(|addr| addr.ip().to_string()),
|
||||
identity_label: labels.get(&info.pubkey).cloned(),
|
||||
identity_pubkey: info.pubkey,
|
||||
gossip_port: info.gossip.map(|addr| addr.port()),
|
||||
tpu_port: info.tpu.map(|addr| addr.port()),
|
||||
rpc_host: info.rpc.map(|addr| addr.to_string()),
|
||||
version: info.version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_to_string_or_none<T>(option: Option<T>) -> String
|
||||
where
|
||||
T: std::string::ToString,
|
||||
{
|
||||
unwrap_to_string_or_default(option, "none")
|
||||
}
|
||||
|
||||
fn unwrap_to_string_or_default<T>(option: Option<T>, default: &str) -> String
|
||||
where
|
||||
T: std::string::ToString,
|
||||
{
|
||||
option
|
||||
.as_ref()
|
||||
.map(|v| v.to_string())
|
||||
.unwrap_or_else(|| default.to_string())
|
||||
}
|
||||
|
||||
impl fmt::Display for CliGossipNode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{:15} | {:44} | {:6} | {:5} | {:21} | {}",
|
||||
unwrap_to_string_or_none(self.ip_address.as_ref()),
|
||||
self.identity_label
|
||||
.as_ref()
|
||||
.unwrap_or(&self.identity_pubkey),
|
||||
unwrap_to_string_or_none(self.gossip_port.as_ref()),
|
||||
unwrap_to_string_or_none(self.tpu_port.as_ref()),
|
||||
unwrap_to_string_or_none(self.rpc_host.as_ref()),
|
||||
unwrap_to_string_or_default(self.version.as_ref(), "unknown"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl QuietDisplay for CliGossipNode {}
|
||||
impl VerboseDisplay for CliGossipNode {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CliGossipNodes(pub Vec<CliGossipNode>);
|
||||
|
||||
impl fmt::Display for CliGossipNodes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln!(
|
||||
f,
|
||||
"IP Address | Node identifier \
|
||||
| Gossip | TPU | RPC Address | Version\n\
|
||||
----------------+----------------------------------------------+\
|
||||
--------+-------+-----------------------+----------------",
|
||||
)?;
|
||||
for node in self.0.iter() {
|
||||
writeln!(f, "{}", node)?;
|
||||
}
|
||||
writeln!(f, "Nodes: {}", self.0.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl QuietDisplay for CliGossipNodes {}
|
||||
impl VerboseDisplay for CliGossipNodes {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@@ -5,7 +5,7 @@ use {
|
||||
indicatif::{ProgressBar, ProgressStyle},
|
||||
solana_sdk::{
|
||||
clock::UnixTimestamp, hash::Hash, message::Message, native_token::lamports_to_sol,
|
||||
program_utils::limited_deserialize, pubkey::Pubkey, stake, transaction::Transaction,
|
||||
program_utils::limited_deserialize, pubkey::Pubkey, transaction::Transaction,
|
||||
},
|
||||
solana_transaction_status::UiTransactionStatusMeta,
|
||||
spl_memo::id as spl_memo_id,
|
||||
@@ -244,9 +244,10 @@ pub fn write_transaction<W: io::Write>(
|
||||
writeln!(w, "{} {:?}", prefix, vote_instruction)?;
|
||||
raw = false;
|
||||
}
|
||||
} else if program_pubkey == stake::program::id() {
|
||||
if let Ok(stake_instruction) =
|
||||
limited_deserialize::<stake::instruction::StakeInstruction>(&instruction.data)
|
||||
} else if program_pubkey == solana_stake_program::id() {
|
||||
if let Ok(stake_instruction) = limited_deserialize::<
|
||||
solana_stake_program::stake_instruction::StakeInstruction,
|
||||
>(&instruction.data)
|
||||
{
|
||||
writeln!(w, "{} {:?}", prefix, stake_instruction)?;
|
||||
raw = false;
|
||||
@@ -321,38 +322,7 @@ pub fn write_transaction<W: io::Write>(
|
||||
if !log_messages.is_empty() {
|
||||
writeln!(w, "{}Log Messages:", prefix,)?;
|
||||
for log_message in log_messages {
|
||||
writeln!(w, "{} {}", prefix, log_message)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(rewards) = &transaction_status.rewards {
|
||||
if !rewards.is_empty() {
|
||||
writeln!(w, "{}Rewards:", prefix,)?;
|
||||
writeln!(
|
||||
w,
|
||||
"{} {:<44} {:^15} {:<15} {:<20}",
|
||||
prefix, "Address", "Type", "Amount", "New Balance"
|
||||
)?;
|
||||
for reward in rewards {
|
||||
let sign = if reward.lamports < 0 { "-" } else { "" };
|
||||
writeln!(
|
||||
w,
|
||||
"{} {:<44} {:^15} {:<15} {}",
|
||||
prefix,
|
||||
reward.pubkey,
|
||||
if let Some(reward_type) = reward.reward_type {
|
||||
format!("{}", reward_type)
|
||||
} else {
|
||||
"-".to_string()
|
||||
},
|
||||
format!(
|
||||
"{}◎{:<14.9}",
|
||||
sign,
|
||||
lamports_to_sol(reward.lamports.abs() as u64)
|
||||
),
|
||||
format!("◎{:<18.9}", lamports_to_sol(reward.post_balance),)
|
||||
)?;
|
||||
writeln!(w, "{} {}", prefix, log_message,)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -16,7 +16,7 @@ chrono = { version = "0.4.11", features = ["serde"] }
|
||||
clap = "2.33.1"
|
||||
criterion-stats = "0.3.0"
|
||||
ctrlc = { version = "3.1.5", features = ["termination"] }
|
||||
console = "0.14.1"
|
||||
console = "0.11.3"
|
||||
dirs-next = "2.0.0"
|
||||
log = "0.4.11"
|
||||
Inflector = "0.11.4"
|
||||
@@ -28,29 +28,30 @@ reqwest = { version = "0.11.2", default-features = false, features = ["blocking"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.7.2" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.7.2" }
|
||||
solana-cli-output = { path = "../cli-output", version = "=1.7.2" }
|
||||
solana-client = { path = "../client", version = "=1.7.2" }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.7.2" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.7.2" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
|
||||
solana_rbpf = "=0.2.11"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
||||
solana-version = { path = "../version", version = "=1.7.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.7" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.6.7" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.7" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.6.7" }
|
||||
solana-cli-output = { path = "../cli-output", version = "=1.6.7" }
|
||||
solana-client = { path = "../client", version = "=1.6.7" }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.7" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.7" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.7" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.7" }
|
||||
solana_rbpf = "=0.2.8"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.7" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.7" }
|
||||
solana-version = { path = "../version", version = "=1.6.7" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.7" }
|
||||
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
|
||||
thiserror = "1.0.21"
|
||||
tiny-bip39 = "0.7.0"
|
||||
url = "2.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-core = { path = "../core", version = "=1.7.2" }
|
||||
solana-core = { path = "../core", version = "=1.6.7" }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[[bin]]
|
||||
|
@@ -231,9 +231,18 @@ mod tests {
|
||||
mocks.insert(RpcRequest::GetBalance, account_balance_response);
|
||||
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
|
||||
|
||||
assert!(check_account_for_balance(&rpc_client, &pubkey, 1).unwrap());
|
||||
assert!(check_account_for_balance(&rpc_client, &pubkey, account_balance).unwrap());
|
||||
assert!(!check_account_for_balance(&rpc_client, &pubkey, account_balance + 1).unwrap());
|
||||
assert_eq!(
|
||||
check_account_for_balance(&rpc_client, &pubkey, 1).unwrap(),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
check_account_for_balance(&rpc_client, &pubkey, account_balance).unwrap(),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
check_account_for_balance(&rpc_client, &pubkey, account_balance + 1).unwrap(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@@ -29,11 +29,10 @@ use solana_client::{
|
||||
nonce_utils,
|
||||
rpc_client::RpcClient,
|
||||
rpc_config::{
|
||||
RpcLargestAccountsFilter, RpcSendTransactionConfig, RpcTransactionConfig,
|
||||
RpcConfirmedTransactionConfig, RpcLargestAccountsFilter, RpcSendTransactionConfig,
|
||||
RpcTransactionLogsFilter,
|
||||
},
|
||||
rpc_request::{RpcError, RpcResponseErrorData},
|
||||
rpc_response::{RpcKeyedAccount, RpcSimulateTransactionResult},
|
||||
rpc_response::RpcKeyedAccount,
|
||||
};
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
@@ -45,15 +44,14 @@ use solana_sdk::{
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
signature::{Signature, Signer, SignerError},
|
||||
stake::{
|
||||
self,
|
||||
instruction::LockupArgs,
|
||||
state::{Lockup, StakeAuthorize},
|
||||
},
|
||||
system_instruction::{self, SystemError},
|
||||
system_program,
|
||||
transaction::{Transaction, TransactionError},
|
||||
};
|
||||
use solana_stake_program::{
|
||||
stake_instruction::LockupArgs,
|
||||
stake_state::{Lockup, StakeAuthorize},
|
||||
};
|
||||
use solana_transaction_status::{EncodedTransaction, UiTransactionEncoding};
|
||||
use solana_vote_program::vote_state::VoteAuthorize;
|
||||
use std::{
|
||||
@@ -278,7 +276,6 @@ pub enum CliCommand {
|
||||
memo: Option<String>,
|
||||
fee_payer: SignerIndex,
|
||||
custodian: Option<SignerIndex>,
|
||||
no_wait: bool,
|
||||
},
|
||||
StakeSetLockup {
|
||||
stake_account_pubkey: Pubkey,
|
||||
@@ -933,7 +930,7 @@ pub type ProcessResult = Result<String, Box<dyn std::error::Error>>;
|
||||
fn resolve_derived_address_program_id(matches: &ArgMatches<'_>, arg_name: &str) -> Option<Pubkey> {
|
||||
matches.value_of(arg_name).and_then(|v| match v {
|
||||
"NONCE" => Some(system_program::id()),
|
||||
"STAKE" => Some(stake::program::id()),
|
||||
"STAKE" => Some(solana_stake_program::id()),
|
||||
"VOTE" => Some(solana_vote_program::id()),
|
||||
_ => pubkey_of(matches, arg_name),
|
||||
})
|
||||
@@ -1043,9 +1040,9 @@ fn process_confirm(
|
||||
let mut transaction = None;
|
||||
let mut get_transaction_error = None;
|
||||
if config.verbose {
|
||||
match rpc_client.get_transaction_with_config(
|
||||
match rpc_client.get_confirmed_transaction_with_config(
|
||||
signature,
|
||||
RpcTransactionConfig {
|
||||
RpcConfirmedTransactionConfig {
|
||||
encoding: Some(UiTransactionEncoding::Base64),
|
||||
commitment: Some(CommitmentConfig::confirmed()),
|
||||
},
|
||||
@@ -1125,7 +1122,7 @@ fn process_show_account(
|
||||
pubkey: account_pubkey.to_string(),
|
||||
account: UiAccount::encode(
|
||||
account_pubkey,
|
||||
&account,
|
||||
account,
|
||||
UiAccountEncoding::Base64,
|
||||
None,
|
||||
None,
|
||||
@@ -1682,7 +1679,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
memo,
|
||||
fee_payer,
|
||||
custodian,
|
||||
no_wait,
|
||||
} => process_stake_authorize(
|
||||
&rpc_client,
|
||||
config,
|
||||
@@ -1696,7 +1692,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
*nonce_authority,
|
||||
memo.as_ref(),
|
||||
*fee_payer,
|
||||
*no_wait,
|
||||
),
|
||||
CliCommand::StakeSetLockup {
|
||||
stake_account_pubkey,
|
||||
@@ -1958,28 +1953,6 @@ where
|
||||
{
|
||||
match result {
|
||||
Err(err) => {
|
||||
// If transaction simulation returns a known Custom InstructionError, decode it
|
||||
if let ClientErrorKind::RpcError(RpcError::RpcResponseError {
|
||||
data:
|
||||
RpcResponseErrorData::SendTransactionPreflightFailure(
|
||||
RpcSimulateTransactionResult {
|
||||
err:
|
||||
Some(TransactionError::InstructionError(
|
||||
_,
|
||||
InstructionError::Custom(code),
|
||||
)),
|
||||
..
|
||||
},
|
||||
),
|
||||
..
|
||||
}) = err.kind()
|
||||
{
|
||||
if let Some(specific_error) = E::decode_custom_error_to_enum(*code) {
|
||||
return Err(specific_error.into());
|
||||
}
|
||||
}
|
||||
// If the transaction was instead submitted and returned a known Custom
|
||||
// InstructionError, decode it
|
||||
if let ClientErrorKind::TransactionError(TransactionError::InstructionError(
|
||||
_,
|
||||
InstructionError::Custom(code),
|
||||
@@ -2323,7 +2296,10 @@ mod tests {
|
||||
let default_keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &default_keypair_file).unwrap();
|
||||
|
||||
let default_signer = DefaultSigner::new("keypair", &default_keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
arg_name: "keypair".to_string(),
|
||||
path: default_keypair_file,
|
||||
};
|
||||
|
||||
let signer_info = default_signer
|
||||
.generate_unique_signers(vec![], &matches, &mut None)
|
||||
@@ -2401,7 +2377,10 @@ mod tests {
|
||||
let keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &keypair_file).unwrap();
|
||||
let keypair = read_keypair_file(&keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: keypair_file.clone(),
|
||||
arg_name: "".to_string(),
|
||||
};
|
||||
// Test Airdrop Subcommand
|
||||
let test_airdrop =
|
||||
test_commands
|
||||
@@ -2488,7 +2467,7 @@ mod tests {
|
||||
let from_pubkey = Some(solana_sdk::pubkey::new_rand());
|
||||
let from_str = from_pubkey.unwrap().to_string();
|
||||
for (name, program_id) in &[
|
||||
("STAKE", stake::program::id()),
|
||||
("STAKE", solana_stake_program::id()),
|
||||
("VOTE", solana_vote_program::id()),
|
||||
("NONCE", system_program::id()),
|
||||
] {
|
||||
@@ -2524,7 +2503,7 @@ mod tests {
|
||||
command: CliCommand::CreateAddressWithSeed {
|
||||
from_pubkey: None,
|
||||
seed: "seed".to_string(),
|
||||
program_id: stake::program::id(),
|
||||
program_id: solana_stake_program::id(),
|
||||
},
|
||||
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
||||
}
|
||||
@@ -2787,11 +2766,11 @@ mod tests {
|
||||
config.command = CliCommand::CreateAddressWithSeed {
|
||||
from_pubkey: Some(from_pubkey),
|
||||
seed: "seed".to_string(),
|
||||
program_id: stake::program::id(),
|
||||
program_id: solana_stake_program::id(),
|
||||
};
|
||||
let address = process_command(&config);
|
||||
let expected_address =
|
||||
Pubkey::create_with_seed(&from_pubkey, "seed", &stake::program::id()).unwrap();
|
||||
Pubkey::create_with_seed(&from_pubkey, "seed", &solana_stake_program::id()).unwrap();
|
||||
assert_eq!(address.unwrap(), expected_address.to_string());
|
||||
|
||||
// Need airdrop cases
|
||||
@@ -2929,7 +2908,10 @@ mod tests {
|
||||
let default_keypair = Keypair::new();
|
||||
let default_keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &default_keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &default_keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: default_keypair_file.clone(),
|
||||
arg_name: "".to_string(),
|
||||
};
|
||||
|
||||
//Test Transfer Subcommand, SOL
|
||||
let from_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||
@@ -3178,7 +3160,7 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
derived_address_seed: Some(derived_address_seed),
|
||||
derived_address_program_id: Some(stake::program::id()),
|
||||
derived_address_program_id: Some(solana_stake_program::id()),
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
|
||||
}
|
||||
|
@@ -24,9 +24,9 @@ use solana_client::{
|
||||
pubsub_client::PubsubClient,
|
||||
rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient},
|
||||
rpc_config::{
|
||||
RpcAccountInfoConfig, RpcBlockConfig, RpcLargestAccountsConfig, RpcLargestAccountsFilter,
|
||||
RpcProgramAccountsConfig, RpcTransactionConfig, RpcTransactionLogsConfig,
|
||||
RpcTransactionLogsFilter,
|
||||
RpcAccountInfoConfig, RpcConfirmedBlockConfig, RpcConfirmedTransactionConfig,
|
||||
RpcLargestAccountsConfig, RpcLargestAccountsFilter, RpcProgramAccountsConfig,
|
||||
RpcTransactionLogsConfig, RpcTransactionLogsFilter,
|
||||
},
|
||||
rpc_filter,
|
||||
rpc_response::SlotInfo,
|
||||
@@ -46,9 +46,7 @@ use solana_sdk::{
|
||||
rent::Rent,
|
||||
rpc_port::DEFAULT_RPC_PORT_STR,
|
||||
signature::Signature,
|
||||
slot_history,
|
||||
stake::{self, state::StakeState},
|
||||
system_instruction, system_program,
|
||||
slot_history, system_instruction, system_program,
|
||||
sysvar::{
|
||||
self,
|
||||
slot_history::SlotHistory,
|
||||
@@ -57,11 +55,13 @@ use solana_sdk::{
|
||||
timing,
|
||||
transaction::Transaction,
|
||||
};
|
||||
use solana_stake_program::stake_state::StakeState;
|
||||
use solana_transaction_status::UiTransactionEncoding;
|
||||
use solana_vote_program::vote_state::VoteState;
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap, VecDeque},
|
||||
fmt,
|
||||
net::SocketAddr,
|
||||
str::FromStr,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
@@ -1028,12 +1028,12 @@ pub fn process_get_block(
|
||||
};
|
||||
|
||||
let encoded_confirmed_block = rpc_client
|
||||
.get_block_with_config(
|
||||
.get_confirmed_block_with_config(
|
||||
slot,
|
||||
RpcBlockConfig {
|
||||
RpcConfirmedBlockConfig {
|
||||
encoding: Some(UiTransactionEncoding::Base64),
|
||||
commitment: Some(CommitmentConfig::confirmed()),
|
||||
..RpcBlockConfig::default()
|
||||
..RpcConfirmedBlockConfig::default()
|
||||
},
|
||||
)?
|
||||
.into();
|
||||
@@ -1094,8 +1094,8 @@ pub fn process_get_slot(rpc_client: &RpcClient, _config: &CliConfig) -> ProcessR
|
||||
}
|
||||
|
||||
pub fn process_get_block_height(rpc_client: &RpcClient, _config: &CliConfig) -> ProcessResult {
|
||||
let block_height = rpc_client.get_block_height()?;
|
||||
Ok(block_height.to_string())
|
||||
let epoch_info = rpc_client.get_epoch_info()?;
|
||||
Ok(epoch_info.block_height.to_string())
|
||||
}
|
||||
|
||||
pub fn parse_show_block_production(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
@@ -1185,7 +1185,7 @@ pub fn process_show_block_production(
|
||||
start_slot = minimum_ledger_slot;
|
||||
}
|
||||
|
||||
let confirmed_blocks = rpc_client.get_blocks(start_slot, Some(end_slot))?;
|
||||
let confirmed_blocks = rpc_client.get_confirmed_blocks(start_slot, Some(end_slot))?;
|
||||
(confirmed_blocks, start_slot)
|
||||
};
|
||||
|
||||
@@ -1655,14 +1655,40 @@ pub fn process_live_slots(config: &CliConfig) -> ProcessResult {
|
||||
pub fn process_show_gossip(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult {
|
||||
let cluster_nodes = rpc_client.get_cluster_nodes()?;
|
||||
|
||||
let nodes: Vec<_> = cluster_nodes
|
||||
fn format_port(addr: Option<SocketAddr>) -> String {
|
||||
addr.map(|addr| addr.port().to_string())
|
||||
.unwrap_or_else(|| "none".to_string())
|
||||
}
|
||||
|
||||
let s: Vec<_> = cluster_nodes
|
||||
.into_iter()
|
||||
.map(|node| CliGossipNode::new(node, &config.address_labels))
|
||||
.map(|node| {
|
||||
format!(
|
||||
"{:15} | {:44} | {:6} | {:5} | {:21} | {}",
|
||||
node.gossip
|
||||
.map(|addr| addr.ip().to_string())
|
||||
.unwrap_or_else(|| "none".to_string()),
|
||||
format_labeled_address(&node.pubkey, &config.address_labels),
|
||||
format_port(node.gossip),
|
||||
format_port(node.tpu),
|
||||
node.rpc
|
||||
.map(|addr| addr.to_string())
|
||||
.unwrap_or_else(|| "none".to_string()),
|
||||
node.version.unwrap_or_else(|| "unknown".to_string()),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(config
|
||||
.output_format
|
||||
.formatted_string(&CliGossipNodes(nodes)))
|
||||
Ok(format!(
|
||||
"IP Address | Node identifier \
|
||||
| Gossip | TPU | RPC Address | Version\n\
|
||||
----------------+----------------------------------------------+\
|
||||
--------+-------+-----------------------+----------------\n\
|
||||
{}\n\
|
||||
Nodes: {}",
|
||||
s.join("\n"),
|
||||
s.len(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn process_show_stakes(
|
||||
@@ -1677,11 +1703,11 @@ pub fn process_show_stakes(
|
||||
progress_bar.set_message("Fetching stake accounts...");
|
||||
|
||||
let mut program_accounts_config = RpcProgramAccountsConfig {
|
||||
filters: None,
|
||||
account_config: RpcAccountInfoConfig {
|
||||
encoding: Some(solana_account_decoder::UiAccountEncoding::Base64),
|
||||
..RpcAccountInfoConfig::default()
|
||||
},
|
||||
..RpcProgramAccountsConfig::default()
|
||||
};
|
||||
|
||||
if let Some(vote_account_pubkeys) = vote_account_pubkeys {
|
||||
@@ -1708,7 +1734,7 @@ pub fn process_show_stakes(
|
||||
}
|
||||
}
|
||||
let all_stake_accounts = rpc_client
|
||||
.get_program_accounts_with_config(&stake::program::id(), program_accounts_config)?;
|
||||
.get_program_accounts_with_config(&solana_stake_program::id(), program_accounts_config)?;
|
||||
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
|
||||
let clock_account = rpc_client.get_account(&sysvar::clock::id())?;
|
||||
let clock: Clock = from_account(&clock_account).ok_or_else(|| {
|
||||
@@ -1915,7 +1941,7 @@ pub fn process_transaction_history(
|
||||
limit: usize,
|
||||
show_transactions: bool,
|
||||
) -> ProcessResult {
|
||||
let results = rpc_client.get_signatures_for_address_with_config(
|
||||
let results = rpc_client.get_confirmed_signatures_for_address2_with_config(
|
||||
address,
|
||||
GetConfirmedSignaturesForAddress2Config {
|
||||
before,
|
||||
@@ -1954,9 +1980,9 @@ pub fn process_transaction_history(
|
||||
|
||||
if show_transactions {
|
||||
if let Ok(signature) = result.signature.parse::<Signature>() {
|
||||
match rpc_client.get_transaction_with_config(
|
||||
match rpc_client.get_confirmed_transaction_with_config(
|
||||
&signature,
|
||||
RpcTransactionConfig {
|
||||
RpcConfirmedTransactionConfig {
|
||||
encoding: Some(UiTransactionEncoding::Base64),
|
||||
commitment: Some(CommitmentConfig::confirmed()),
|
||||
},
|
||||
@@ -2099,7 +2125,10 @@ mod tests {
|
||||
let default_keypair = Keypair::new();
|
||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &default_keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: default_keypair_file,
|
||||
arg_name: String::new(),
|
||||
};
|
||||
|
||||
let test_cluster_version = test_commands
|
||||
.clone()
|
||||
|
@@ -10,6 +10,7 @@ macro_rules! ACCOUNT_STRING {
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
macro_rules! pubkey {
|
||||
($arg:expr, $help:expr) => {
|
||||
$arg.takes_value(true)
|
||||
|
@@ -179,7 +179,10 @@ pub fn parse_args<'a>(
|
||||
&config.keypair_path,
|
||||
);
|
||||
|
||||
let default_signer = DefaultSigner::new(default_signer_arg_name, &default_signer_path);
|
||||
let default_signer = DefaultSigner {
|
||||
arg_name: default_signer_arg_name,
|
||||
path: default_signer_path.clone(),
|
||||
};
|
||||
|
||||
let CliCommandInfo {
|
||||
command,
|
||||
|
@@ -596,7 +596,10 @@ mod tests {
|
||||
let default_keypair = Keypair::new();
|
||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &default_keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: default_keypair_file.clone(),
|
||||
arg_name: String::new(),
|
||||
};
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let nonce_account_keypair = Keypair::new();
|
||||
write_keypair(&nonce_account_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
|
@@ -150,7 +150,7 @@ impl ProgramSubCommands for App<'_, '_> {
|
||||
pubkey!(Arg::with_name("program_id")
|
||||
.long("program-id")
|
||||
.value_name("PROGRAM_ID"),
|
||||
"Executable program's address, must be a keypair for initial deploys, can be a pubkey for upgrades \
|
||||
"Executable program's address, must be a signer for initial deploys, can be a pubkey for upgrades \
|
||||
[default: address of keypair at /path/to/program-keypair.json if present, otherwise a random address]"),
|
||||
)
|
||||
.arg(
|
||||
@@ -886,11 +886,6 @@ fn process_program_deploy(
|
||||
)?;
|
||||
|
||||
let result = if do_deploy {
|
||||
if program_signer.is_none() {
|
||||
return Err(
|
||||
"Initial deployments require a keypair be provided for the program id".into(),
|
||||
);
|
||||
}
|
||||
do_process_program_write_and_deploy(
|
||||
rpc_client.clone(),
|
||||
config,
|
||||
@@ -1107,7 +1102,6 @@ fn get_buffers(
|
||||
data_slice: Some(UiDataSliceConfig { offset: 0, length }),
|
||||
..RpcAccountInfoConfig::default()
|
||||
},
|
||||
..RpcProgramAccountsConfig::default()
|
||||
},
|
||||
)?;
|
||||
Ok(results)
|
||||
@@ -1412,7 +1406,6 @@ fn process_close(
|
||||
data_slice: Some(UiDataSliceConfig { offset: 0, length }),
|
||||
..RpcAccountInfoConfig::default()
|
||||
},
|
||||
..RpcProgramAccountsConfig::default()
|
||||
},
|
||||
)?;
|
||||
|
||||
@@ -2136,7 +2129,10 @@ mod tests {
|
||||
let default_keypair = Keypair::new();
|
||||
let keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: keypair_file.clone(),
|
||||
arg_name: "".to_string(),
|
||||
};
|
||||
|
||||
let test_command = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
@@ -2344,7 +2340,10 @@ mod tests {
|
||||
let default_keypair = Keypair::new();
|
||||
let keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: keypair_file.clone(),
|
||||
arg_name: "".to_string(),
|
||||
};
|
||||
|
||||
// defaults
|
||||
let test_command = test_commands.clone().get_matches_from(vec![
|
||||
@@ -2492,7 +2491,10 @@ mod tests {
|
||||
let default_keypair = Keypair::new();
|
||||
let keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: keypair_file.clone(),
|
||||
arg_name: "".to_string(),
|
||||
};
|
||||
|
||||
let program_pubkey = Pubkey::new_unique();
|
||||
let new_authority_pubkey = Pubkey::new_unique();
|
||||
@@ -2600,7 +2602,10 @@ mod tests {
|
||||
let default_keypair = Keypair::new();
|
||||
let keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: keypair_file.clone(),
|
||||
arg_name: "".to_string(),
|
||||
};
|
||||
|
||||
let buffer_pubkey = Pubkey::new_unique();
|
||||
let new_authority_pubkey = Pubkey::new_unique();
|
||||
@@ -2657,7 +2662,10 @@ mod tests {
|
||||
let default_keypair = Keypair::new();
|
||||
let keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: keypair_file,
|
||||
arg_name: "".to_string(),
|
||||
};
|
||||
|
||||
// defaults
|
||||
let buffer_pubkey = Pubkey::new_unique();
|
||||
@@ -2756,7 +2764,10 @@ mod tests {
|
||||
let default_keypair = Keypair::new();
|
||||
let keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: keypair_file.clone(),
|
||||
arg_name: "".to_string(),
|
||||
};
|
||||
|
||||
// defaults
|
||||
let buffer_pubkey = Pubkey::new_unique();
|
||||
|
@@ -36,11 +36,6 @@ use solana_sdk::{
|
||||
feature, feature_set,
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
stake::{
|
||||
self,
|
||||
instruction::{self as stake_instruction, LockupArgs, StakeError},
|
||||
state::{Authorized, Lockup, Meta, StakeAuthorize, StakeState},
|
||||
},
|
||||
system_instruction::SystemError,
|
||||
sysvar::{
|
||||
clock,
|
||||
@@ -48,6 +43,10 @@ use solana_sdk::{
|
||||
},
|
||||
transaction::Transaction,
|
||||
};
|
||||
use solana_stake_program::{
|
||||
stake_instruction::{self, LockupArgs, StakeError},
|
||||
stake_state::{Authorized, Lockup, Meta, StakeAuthorize, StakeState},
|
||||
};
|
||||
use solana_vote_program::vote_state::VoteState;
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
@@ -239,12 +238,6 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
.nonce_args(false)
|
||||
.arg(fee_payer_arg())
|
||||
.arg(custodian_arg())
|
||||
.arg(
|
||||
Arg::with_name("no_wait")
|
||||
.long("no-wait")
|
||||
.takes_value(false)
|
||||
.help("Return signature immediately after submitting the transaction, instead of waiting for confirmations"),
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("deactivate-stake")
|
||||
@@ -634,7 +627,6 @@ pub fn parse_stake_authorize(
|
||||
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
||||
let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?;
|
||||
let (custodian, custodian_pubkey) = signer_of(matches, "custodian", wallet_manager)?;
|
||||
let no_wait = matches.is_present("no_wait");
|
||||
|
||||
bulk_signers.push(fee_payer);
|
||||
if nonce_account.is_some() {
|
||||
@@ -671,7 +663,6 @@ pub fn parse_stake_authorize(
|
||||
memo,
|
||||
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
||||
custodian: custodian_pubkey.and_then(|_| signer_info.index_of(custodian_pubkey)),
|
||||
no_wait,
|
||||
},
|
||||
signers: signer_info.signers,
|
||||
})
|
||||
@@ -972,7 +963,7 @@ pub fn process_create_stake_account(
|
||||
) -> ProcessResult {
|
||||
let stake_account = config.signers[stake_account];
|
||||
let stake_account_address = if let Some(seed) = seed {
|
||||
Pubkey::create_with_seed(&stake_account.pubkey(), &seed, &stake::program::id())?
|
||||
Pubkey::create_with_seed(&stake_account.pubkey(), &seed, &solana_stake_program::id())?
|
||||
} else {
|
||||
stake_account.pubkey()
|
||||
};
|
||||
@@ -1040,7 +1031,7 @@ pub fn process_create_stake_account(
|
||||
|
||||
if !sign_only {
|
||||
if let Ok(stake_account) = rpc_client.get_account(&stake_account_address) {
|
||||
let err_msg = if stake_account.owner == stake::program::id() {
|
||||
let err_msg = if stake_account.owner == solana_stake_program::id() {
|
||||
format!("Stake account {} already exists", stake_account_address)
|
||||
} else {
|
||||
format!(
|
||||
@@ -1103,7 +1094,6 @@ pub fn process_stake_authorize(
|
||||
nonce_authority: SignerIndex,
|
||||
memo: Option<&String>,
|
||||
fee_payer: SignerIndex,
|
||||
no_wait: bool,
|
||||
) -> ProcessResult {
|
||||
let mut ixs = Vec::new();
|
||||
let custodian = custodian.map(|index| config.signers[index]);
|
||||
@@ -1167,11 +1157,7 @@ pub fn process_stake_authorize(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = if no_wait {
|
||||
rpc_client.send_transaction(&tx)
|
||||
} else {
|
||||
rpc_client.send_and_confirm_transaction_with_spinner(&tx)
|
||||
};
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<StakeError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -1196,7 +1182,7 @@ pub fn process_deactivate_stake_account(
|
||||
let stake_authority = config.signers[stake_authority];
|
||||
|
||||
let stake_account_address = if let Some(seed) = seed {
|
||||
Pubkey::create_with_seed(&stake_account_pubkey, seed, &stake::program::id())?
|
||||
Pubkey::create_with_seed(&stake_account_pubkey, seed, &solana_stake_program::id())?
|
||||
} else {
|
||||
*stake_account_pubkey
|
||||
};
|
||||
@@ -1274,7 +1260,7 @@ pub fn process_withdraw_stake(
|
||||
let custodian = custodian.map(|index| config.signers[index]);
|
||||
|
||||
let stake_account_address = if let Some(seed) = seed {
|
||||
Pubkey::create_with_seed(&stake_account_pubkey, seed, &stake::program::id())?
|
||||
Pubkey::create_with_seed(&stake_account_pubkey, seed, &solana_stake_program::id())?
|
||||
} else {
|
||||
*stake_account_pubkey
|
||||
};
|
||||
@@ -1395,14 +1381,18 @@ pub fn process_split_stake(
|
||||
let stake_authority = config.signers[stake_authority];
|
||||
|
||||
let split_stake_account_address = if let Some(seed) = split_stake_account_seed {
|
||||
Pubkey::create_with_seed(&split_stake_account.pubkey(), &seed, &stake::program::id())?
|
||||
Pubkey::create_with_seed(
|
||||
&split_stake_account.pubkey(),
|
||||
&seed,
|
||||
&solana_stake_program::id(),
|
||||
)?
|
||||
} else {
|
||||
split_stake_account.pubkey()
|
||||
};
|
||||
|
||||
if !sign_only {
|
||||
if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) {
|
||||
let err_msg = if stake_account.owner == stake::program::id() {
|
||||
let err_msg = if stake_account.owner == solana_stake_program::id() {
|
||||
format!(
|
||||
"Stake account {} already exists",
|
||||
split_stake_account_address
|
||||
@@ -1537,7 +1527,7 @@ pub fn process_merge_stake(
|
||||
if !sign_only {
|
||||
for stake_account_address in &[stake_account_pubkey, source_stake_account_pubkey] {
|
||||
if let Ok(stake_account) = rpc_client.get_account(stake_account_address) {
|
||||
if stake_account.owner != stake::program::id() {
|
||||
if stake_account.owner != solana_stake_program::id() {
|
||||
return Err(CliError::BadParameter(format!(
|
||||
"Account {} is not a stake account",
|
||||
stake_account_address
|
||||
@@ -1873,7 +1863,7 @@ pub fn process_show_stake_account(
|
||||
with_rewards: Option<usize>,
|
||||
) -> ProcessResult {
|
||||
let stake_account = rpc_client.get_account(stake_account_address)?;
|
||||
if stake_account.owner != stake::program::id() {
|
||||
if stake_account.owner != solana_stake_program::id() {
|
||||
return Err(CliError::RpcRequestError(format!(
|
||||
"{:?} is not a stake account",
|
||||
stake_account_address,
|
||||
@@ -2114,7 +2104,10 @@ mod tests {
|
||||
let default_keypair = Keypair::new();
|
||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &default_keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: default_keypair_file.clone(),
|
||||
arg_name: String::new(),
|
||||
};
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let stake_account_keypair = Keypair::new();
|
||||
write_keypair(&stake_account_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
@@ -2158,7 +2151,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
|
||||
},
|
||||
@@ -2196,7 +2188,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2238,7 +2229,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2269,7 +2259,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
|
||||
},
|
||||
@@ -2297,7 +2286,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2331,7 +2319,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2366,7 +2353,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
|
||||
},
|
||||
@@ -2398,7 +2384,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2409,35 +2394,6 @@ mod tests {
|
||||
},
|
||||
);
|
||||
|
||||
// Test Authorize Subcommand w/ no-wait
|
||||
let test_authorize = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"stake-authorize",
|
||||
&stake_account_string,
|
||||
"--new-stake-authority",
|
||||
&stake_account_string,
|
||||
"--no-wait",
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, stake_account_pubkey, 0)],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: true,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
);
|
||||
|
||||
// Test Authorize Subcommand w/ sign-only
|
||||
let blockhash = Hash::default();
|
||||
let blockhash_string = format!("{}", blockhash);
|
||||
@@ -2465,7 +2421,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
@@ -2505,7 +2460,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 1,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2555,7 +2509,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 1,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2591,7 +2544,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
@@ -2632,7 +2584,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2669,7 +2620,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 1,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2710,7 +2660,6 @@ mod tests {
|
||||
memo: None,
|
||||
fee_payer: 1,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
|
@@ -826,7 +826,10 @@ mod tests {
|
||||
let default_keypair = Keypair::new();
|
||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &default_keypair_file);
|
||||
let default_signer = DefaultSigner {
|
||||
path: default_keypair_file.clone(),
|
||||
arg_name: String::new(),
|
||||
};
|
||||
|
||||
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
|
@@ -72,7 +72,7 @@ fn test_cli_program_deploy_non_upgradeable() {
|
||||
let account0 = rpc_client.get_account(&program_id).unwrap();
|
||||
assert_eq!(account0.lamports, minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account0.owner, bpf_loader::id());
|
||||
assert!(account0.executable);
|
||||
assert_eq!(account0.executable, true);
|
||||
let mut file = File::open(pathbuf.to_str().unwrap().to_string()).unwrap();
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
@@ -93,7 +93,7 @@ fn test_cli_program_deploy_non_upgradeable() {
|
||||
.unwrap();
|
||||
assert_eq!(account1.lamports, minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account1.owner, bpf_loader::id());
|
||||
assert!(account1.executable);
|
||||
assert_eq!(account1.executable, true);
|
||||
assert_eq!(account1.data, account0.data);
|
||||
|
||||
// Attempt to redeploy to the same address
|
||||
@@ -129,7 +129,7 @@ fn test_cli_program_deploy_non_upgradeable() {
|
||||
.unwrap();
|
||||
assert_eq!(account2.lamports, 2 * minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account2.owner, bpf_loader::id());
|
||||
assert!(account2.executable);
|
||||
assert_eq!(account2.executable, true);
|
||||
assert_eq!(account2.data, account0.data);
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
let program_account = rpc_client.get_account(&program_keypair.pubkey()).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(program_account.executable);
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) = Pubkey::find_program_address(
|
||||
&[program_keypair.pubkey().as_ref()],
|
||||
&bpf_loader_upgradeable::id(),
|
||||
@@ -300,7 +300,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(!programdata_account.executable);
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
@@ -332,7 +332,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(program_account.executable);
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) =
|
||||
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
@@ -341,7 +341,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(!programdata_account.executable);
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
@@ -364,7 +364,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(program_account.executable);
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) =
|
||||
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
@@ -373,7 +373,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(!programdata_account.executable);
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
@@ -418,7 +418,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(program_account.executable);
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) =
|
||||
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
@@ -427,7 +427,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(!programdata_account.executable);
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
|
@@ -17,11 +17,10 @@ use solana_sdk::{
|
||||
nonce::State as NonceState,
|
||||
pubkey::Pubkey,
|
||||
signature::{keypair_from_seed, Keypair, Signer},
|
||||
stake::{
|
||||
self,
|
||||
instruction::LockupArgs,
|
||||
state::{Lockup, StakeAuthorize, StakeState},
|
||||
},
|
||||
};
|
||||
use solana_stake_program::{
|
||||
stake_instruction::LockupArgs,
|
||||
stake_state::{Lockup, StakeAuthorize, StakeState},
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -140,7 +139,7 @@ fn test_seed_stake_delegation_and_deactivation() {
|
||||
let stake_address = Pubkey::create_with_seed(
|
||||
&config_validator.signers[0].pubkey(),
|
||||
"hi there",
|
||||
&stake::program::id(),
|
||||
&solana_stake_program::id(),
|
||||
)
|
||||
.expect("bad seed");
|
||||
|
||||
@@ -609,7 +608,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
@@ -640,7 +638,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
@@ -666,7 +663,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
@@ -692,7 +688,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
config_offline.output_format = OutputFormat::JsonCompact;
|
||||
let sign_reply = process_command(&config_offline).unwrap();
|
||||
@@ -711,7 +706,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
@@ -762,7 +756,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
let sign_reply = process_command(&config_offline).unwrap();
|
||||
let sign_only = parse_sign_only_reply_string(&sign_reply);
|
||||
@@ -785,7 +778,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
@@ -889,7 +881,6 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
memo: None,
|
||||
fee_payer: 1,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
// `config` balance has not changed, despite submitting the TX
|
||||
@@ -911,7 +902,6 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
config_offline.output_format = OutputFormat::JsonCompact;
|
||||
let sign_reply = process_command(&config_offline).unwrap();
|
||||
@@ -930,7 +920,6 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
// `config`'s balance again has not changed
|
||||
@@ -1134,7 +1123,7 @@ fn test_stake_set_lockup() {
|
||||
stake_account: 1,
|
||||
seed: None,
|
||||
staker: Some(offline_pubkey),
|
||||
withdrawer: Some(config.signers[0].pubkey()),
|
||||
withdrawer: Some(offline_pubkey),
|
||||
lockup,
|
||||
amount: SpendAmount::Some(10 * minimum_stake_balance),
|
||||
sign_only: false,
|
||||
@@ -1558,6 +1547,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let seed_address =
|
||||
Pubkey::create_with_seed(&stake_pubkey, seed, &stake::program::id()).unwrap();
|
||||
Pubkey::create_with_seed(&stake_pubkey, seed, &solana_stake_program::id()).unwrap();
|
||||
check_recent_balance(50_000, &rpc_client, &seed_address);
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@ use solana_sdk::{
|
||||
nonce::State as NonceState,
|
||||
pubkey::Pubkey,
|
||||
signature::{keypair_from_seed, Keypair, NullSigner, Signer},
|
||||
stake,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -514,7 +513,7 @@ fn test_transfer_with_seed() {
|
||||
let sender_pubkey = config.signers[0].pubkey();
|
||||
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
|
||||
let derived_address_seed = "seed".to_string();
|
||||
let derived_address_program_id = stake::program::id();
|
||||
let derived_address_program_id = solana_stake_program::id();
|
||||
let derived_address = Pubkey::create_with_seed(
|
||||
&sender_pubkey,
|
||||
&derived_address_seed,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-client"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
description = "Solana Client"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -24,14 +24,14 @@ semver = "0.11.0"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.7.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
||||
solana-version = { path = "../version", version = "=1.7.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.7" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.7" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.7" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.7" }
|
||||
solana-version = { path = "../version", version = "=1.6.7" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.7" }
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tungstenite = "0.10.1"
|
||||
@@ -40,7 +40,7 @@ url = "2.1.1"
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
jsonrpc-http-server = "17.0.0"
|
||||
solana-logger = { path = "../logger", version = "=1.7.2" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.7" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -361,7 +361,7 @@ mod tests {
|
||||
let nonce_pubkey = Pubkey::new(&[4u8; 32]);
|
||||
let rpc_nonce_account = UiAccount::encode(
|
||||
&nonce_pubkey,
|
||||
&nonce_account,
|
||||
nonce_account,
|
||||
UiAccountEncoding::Base64,
|
||||
None,
|
||||
None,
|
||||
|
@@ -7,11 +7,7 @@ use {
|
||||
rpc_sender::RpcSender,
|
||||
},
|
||||
log::*,
|
||||
reqwest::{
|
||||
self,
|
||||
header::{CONTENT_TYPE, RETRY_AFTER},
|
||||
StatusCode,
|
||||
},
|
||||
reqwest::{self, header::CONTENT_TYPE, StatusCode},
|
||||
std::{
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
@@ -87,24 +83,14 @@ impl RpcSender for HttpSender {
|
||||
if response.status() == StatusCode::TOO_MANY_REQUESTS
|
||||
&& too_many_requests_retries > 0
|
||||
{
|
||||
let mut duration = Duration::from_millis(500);
|
||||
if let Some(retry_after) = response.headers().get(RETRY_AFTER) {
|
||||
if let Ok(retry_after) = retry_after.to_str() {
|
||||
if let Ok(retry_after) = retry_after.parse::<u64>() {
|
||||
if retry_after < 120 {
|
||||
duration = Duration::from_secs(retry_after);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
too_many_requests_retries -= 1;
|
||||
debug!(
|
||||
"Too many requests: server responded with {:?}, {} retries left, pausing for {:?}",
|
||||
response, too_many_requests_retries, duration
|
||||
"Server responded with {:?}, {} retries left",
|
||||
response, too_many_requests_retries
|
||||
);
|
||||
|
||||
sleep(duration);
|
||||
// Sleep for 500ms to give the server a break
|
||||
sleep(Duration::from_millis(500));
|
||||
continue;
|
||||
}
|
||||
return Err(response.error_for_status().unwrap_err().into());
|
||||
|
@@ -13,7 +13,6 @@ pub mod rpc_cache;
|
||||
pub mod rpc_client;
|
||||
pub mod rpc_config;
|
||||
pub mod rpc_custom_error;
|
||||
pub mod rpc_deprecated_config;
|
||||
pub mod rpc_filter;
|
||||
pub mod rpc_request;
|
||||
pub mod rpc_response;
|
||||
|
@@ -1,8 +1,3 @@
|
||||
#[allow(deprecated)]
|
||||
use crate::rpc_deprecated_config::{
|
||||
RpcConfirmedBlockConfig, RpcConfirmedTransactionConfig,
|
||||
RpcGetConfirmedSignaturesForAddress2Config,
|
||||
};
|
||||
use {
|
||||
crate::{
|
||||
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
|
||||
@@ -182,23 +177,6 @@ impl RpcClient {
|
||||
Ok(requested_commitment)
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
fn maybe_map_request(&self, mut request: RpcRequest) -> Result<RpcRequest, RpcError> {
|
||||
if self.get_node_version()? < semver::Version::new(1, 7, 0) {
|
||||
request = match request {
|
||||
RpcRequest::GetBlock => RpcRequest::GetConfirmedBlock,
|
||||
RpcRequest::GetBlocks => RpcRequest::GetConfirmedBlocks,
|
||||
RpcRequest::GetBlocksWithLimit => RpcRequest::GetConfirmedBlocksWithLimit,
|
||||
RpcRequest::GetSignaturesForAddress => {
|
||||
RpcRequest::GetConfirmedSignaturesForAddress2
|
||||
}
|
||||
RpcRequest::GetTransaction => RpcRequest::GetConfirmedTransaction,
|
||||
_ => request,
|
||||
};
|
||||
}
|
||||
Ok(request)
|
||||
}
|
||||
|
||||
pub fn confirm_transaction(&self, signature: &Signature) -> ClientResult<bool> {
|
||||
Ok(self
|
||||
.confirm_transaction_with_commitment(signature, self.commitment_config)?
|
||||
@@ -426,20 +404,6 @@ impl RpcClient {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_block_height(&self) -> ClientResult<u64> {
|
||||
self.get_block_height_with_commitment(self.commitment_config)
|
||||
}
|
||||
|
||||
pub fn get_block_height_with_commitment(
|
||||
&self,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ClientResult<u64> {
|
||||
self.send(
|
||||
RpcRequest::GetBlockHeight,
|
||||
json!([self.maybe_map_commitment(commitment_config)?]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_slot_leaders(&self, start_slot: Slot, limit: u64) -> ClientResult<Vec<Pubkey>> {
|
||||
self.send(RpcRequest::GetSlotLeaders, json!([start_slot, limit]))
|
||||
.and_then(|slot_leaders: Vec<String>| {
|
||||
@@ -501,6 +465,27 @@ impl RpcClient {
|
||||
)
|
||||
}
|
||||
|
||||
#[deprecated(since = "1.5.19", note = "Please use RpcClient::supply() instead")]
|
||||
#[allow(deprecated)]
|
||||
pub fn total_supply(&self) -> ClientResult<u64> {
|
||||
self.total_supply_with_commitment(self.commitment_config)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.5.19",
|
||||
note = "Please use RpcClient::supply_with_commitment() instead"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub fn total_supply_with_commitment(
|
||||
&self,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ClientResult<u64> {
|
||||
self.send(
|
||||
RpcRequest::GetTotalSupply,
|
||||
json!([self.maybe_map_commitment(commitment_config)?]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_largest_accounts_with_config(
|
||||
&self,
|
||||
config: RpcLargestAccountsConfig,
|
||||
@@ -571,43 +556,10 @@ impl RpcClient {
|
||||
self.send(RpcRequest::GetClusterNodes, Value::Null)
|
||||
}
|
||||
|
||||
pub fn get_block(&self, slot: Slot) -> ClientResult<EncodedConfirmedBlock> {
|
||||
self.get_block_with_encoding(slot, UiTransactionEncoding::Json)
|
||||
}
|
||||
|
||||
pub fn get_block_with_encoding(
|
||||
&self,
|
||||
slot: Slot,
|
||||
encoding: UiTransactionEncoding,
|
||||
) -> ClientResult<EncodedConfirmedBlock> {
|
||||
self.send(
|
||||
self.maybe_map_request(RpcRequest::GetBlock)?,
|
||||
json!([slot, encoding]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_block_with_config(
|
||||
&self,
|
||||
slot: Slot,
|
||||
config: RpcBlockConfig,
|
||||
) -> ClientResult<UiConfirmedBlock> {
|
||||
self.send(
|
||||
self.maybe_map_request(RpcRequest::GetBlock)?,
|
||||
json!([slot, config]),
|
||||
)
|
||||
}
|
||||
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcClient::get_block() instead")]
|
||||
#[allow(deprecated)]
|
||||
pub fn get_confirmed_block(&self, slot: Slot) -> ClientResult<EncodedConfirmedBlock> {
|
||||
self.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Json)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcClient::get_block_with_encoding() instead"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub fn get_confirmed_block_with_encoding(
|
||||
&self,
|
||||
slot: Slot,
|
||||
@@ -616,11 +568,6 @@ impl RpcClient {
|
||||
self.send(RpcRequest::GetConfirmedBlock, json!([slot, encoding]))
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcClient::get_block_with_config() instead"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub fn get_confirmed_block_with_config(
|
||||
&self,
|
||||
slot: Slot,
|
||||
@@ -629,56 +576,6 @@ impl RpcClient {
|
||||
self.send(RpcRequest::GetConfirmedBlock, json!([slot, config]))
|
||||
}
|
||||
|
||||
pub fn get_blocks(&self, start_slot: Slot, end_slot: Option<Slot>) -> ClientResult<Vec<Slot>> {
|
||||
self.send(
|
||||
self.maybe_map_request(RpcRequest::GetBlocks)?,
|
||||
json!([start_slot, end_slot]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_blocks_with_commitment(
|
||||
&self,
|
||||
start_slot: Slot,
|
||||
end_slot: Option<Slot>,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ClientResult<Vec<Slot>> {
|
||||
let json = if end_slot.is_some() {
|
||||
json!([
|
||||
start_slot,
|
||||
end_slot,
|
||||
self.maybe_map_commitment(commitment_config)?
|
||||
])
|
||||
} else {
|
||||
json!([start_slot, self.maybe_map_commitment(commitment_config)?])
|
||||
};
|
||||
self.send(self.maybe_map_request(RpcRequest::GetBlocks)?, json)
|
||||
}
|
||||
|
||||
pub fn get_blocks_with_limit(&self, start_slot: Slot, limit: usize) -> ClientResult<Vec<Slot>> {
|
||||
self.send(
|
||||
self.maybe_map_request(RpcRequest::GetBlocksWithLimit)?,
|
||||
json!([start_slot, limit]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_blocks_with_limit_and_commitment(
|
||||
&self,
|
||||
start_slot: Slot,
|
||||
limit: usize,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ClientResult<Vec<Slot>> {
|
||||
self.send(
|
||||
self.maybe_map_request(RpcRequest::GetBlocksWithLimit)?,
|
||||
json!([
|
||||
start_slot,
|
||||
limit,
|
||||
self.maybe_map_commitment(commitment_config)?
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcClient::get_blocks() instead")]
|
||||
#[allow(deprecated)]
|
||||
pub fn get_confirmed_blocks(
|
||||
&self,
|
||||
start_slot: Slot,
|
||||
@@ -690,11 +587,6 @@ impl RpcClient {
|
||||
)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcClient::get_blocks_with_commitment() instead"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub fn get_confirmed_blocks_with_commitment(
|
||||
&self,
|
||||
start_slot: Slot,
|
||||
@@ -713,11 +605,6 @@ impl RpcClient {
|
||||
self.send(RpcRequest::GetConfirmedBlocks, json)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcClient::get_blocks_with_limit() instead"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub fn get_confirmed_blocks_with_limit(
|
||||
&self,
|
||||
start_slot: Slot,
|
||||
@@ -729,11 +616,6 @@ impl RpcClient {
|
||||
)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcClient::get_blocks_with_limit_and_commitment() instead"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub fn get_confirmed_blocks_with_limit_and_commitment(
|
||||
&self,
|
||||
start_slot: Slot,
|
||||
@@ -750,41 +632,33 @@ impl RpcClient {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_signatures_for_address(
|
||||
&self,
|
||||
address: &Pubkey,
|
||||
) -> ClientResult<Vec<RpcConfirmedTransactionStatusWithSignature>> {
|
||||
self.get_signatures_for_address_with_config(
|
||||
address,
|
||||
GetConfirmedSignaturesForAddress2Config::default(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_signatures_for_address_with_config(
|
||||
&self,
|
||||
address: &Pubkey,
|
||||
config: GetConfirmedSignaturesForAddress2Config,
|
||||
) -> ClientResult<Vec<RpcConfirmedTransactionStatusWithSignature>> {
|
||||
let config = RpcSignaturesForAddressConfig {
|
||||
before: config.before.map(|signature| signature.to_string()),
|
||||
until: config.until.map(|signature| signature.to_string()),
|
||||
limit: config.limit,
|
||||
commitment: config.commitment,
|
||||
};
|
||||
|
||||
let result: Vec<RpcConfirmedTransactionStatusWithSignature> = self.send(
|
||||
self.maybe_map_request(RpcRequest::GetSignaturesForAddress)?,
|
||||
json!([address.to_string(), config]),
|
||||
)?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcClient::get_signatures_for_address() instead"
|
||||
since = "1.5.19",
|
||||
note = "Please use RpcClient::get_confirmed_signatures_for_address2() instead"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub fn get_confirmed_signatures_for_address(
|
||||
&self,
|
||||
address: &Pubkey,
|
||||
start_slot: Slot,
|
||||
end_slot: Slot,
|
||||
) -> ClientResult<Vec<Signature>> {
|
||||
let signatures_base58_str: Vec<String> = self.send(
|
||||
RpcRequest::GetConfirmedSignaturesForAddress,
|
||||
json!([address.to_string(), start_slot, end_slot]),
|
||||
)?;
|
||||
|
||||
let mut signatures = vec![];
|
||||
for signature_base58_str in signatures_base58_str {
|
||||
signatures.push(
|
||||
signature_base58_str.parse::<Signature>().map_err(|err| {
|
||||
Into::<ClientError>::into(RpcError::ParseError(err.to_string()))
|
||||
})?,
|
||||
);
|
||||
}
|
||||
Ok(signatures)
|
||||
}
|
||||
|
||||
pub fn get_confirmed_signatures_for_address2(
|
||||
&self,
|
||||
address: &Pubkey,
|
||||
@@ -795,11 +669,6 @@ impl RpcClient {
|
||||
)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcClient::get_signatures_for_address_with_config() instead"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub fn get_confirmed_signatures_for_address2_with_config(
|
||||
&self,
|
||||
address: &Pubkey,
|
||||
@@ -820,33 +689,6 @@ impl RpcClient {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn get_transaction(
|
||||
&self,
|
||||
signature: &Signature,
|
||||
encoding: UiTransactionEncoding,
|
||||
) -> ClientResult<EncodedConfirmedTransaction> {
|
||||
self.send(
|
||||
self.maybe_map_request(RpcRequest::GetTransaction)?,
|
||||
json!([signature.to_string(), encoding]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_transaction_with_config(
|
||||
&self,
|
||||
signature: &Signature,
|
||||
config: RpcTransactionConfig,
|
||||
) -> ClientResult<EncodedConfirmedTransaction> {
|
||||
self.send(
|
||||
self.maybe_map_request(RpcRequest::GetTransaction)?,
|
||||
json!([signature.to_string(), config]),
|
||||
)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcClient::get_transaction() instead"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub fn get_confirmed_transaction(
|
||||
&self,
|
||||
signature: &Signature,
|
||||
@@ -858,11 +700,6 @@ impl RpcClient {
|
||||
)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcClient::get_transaction_with_config() instead"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub fn get_confirmed_transaction_with_config(
|
||||
&self,
|
||||
signature: &Signature,
|
||||
@@ -1056,7 +893,7 @@ impl RpcClient {
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> RpcResult<Option<Account>> {
|
||||
let config = RpcAccountInfoConfig {
|
||||
encoding: Some(UiAccountEncoding::Base64Zstd),
|
||||
encoding: Some(UiAccountEncoding::Base64),
|
||||
commitment: Some(self.maybe_map_commitment(commitment_config)?),
|
||||
data_slice: None,
|
||||
};
|
||||
@@ -1111,7 +948,7 @@ impl RpcClient {
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> RpcResult<Vec<Option<Account>>> {
|
||||
let config = RpcAccountInfoConfig {
|
||||
encoding: Some(UiAccountEncoding::Base64Zstd),
|
||||
encoding: Some(UiAccountEncoding::Base64),
|
||||
commitment: Some(self.maybe_map_commitment(commitment_config)?),
|
||||
data_slice: None,
|
||||
};
|
||||
@@ -1177,11 +1014,12 @@ impl RpcClient {
|
||||
self.get_program_accounts_with_config(
|
||||
pubkey,
|
||||
RpcProgramAccountsConfig {
|
||||
filters: None,
|
||||
account_config: RpcAccountInfoConfig {
|
||||
encoding: Some(UiAccountEncoding::Base64Zstd),
|
||||
encoding: Some(UiAccountEncoding::Base64),
|
||||
commitment: Some(self.commitment_config),
|
||||
..RpcAccountInfoConfig::default()
|
||||
},
|
||||
..RpcProgramAccountsConfig::default()
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -1191,10 +1029,7 @@ impl RpcClient {
|
||||
pubkey: &Pubkey,
|
||||
config: RpcProgramAccountsConfig,
|
||||
) -> ClientResult<Vec<(Pubkey, Account)>> {
|
||||
let commitment = config
|
||||
.account_config
|
||||
.commitment
|
||||
.unwrap_or_else(|| self.commitment());
|
||||
let commitment = config.account_config.commitment.unwrap_or_default();
|
||||
let commitment = self.maybe_map_commitment(commitment)?;
|
||||
let account_config = RpcAccountInfoConfig {
|
||||
commitment: Some(commitment),
|
||||
@@ -1244,7 +1079,6 @@ impl RpcClient {
|
||||
blockhash,
|
||||
fee_calculator,
|
||||
last_valid_slot,
|
||||
..
|
||||
},
|
||||
}) = self
|
||||
.send::<Response<RpcFees>>(
|
||||
@@ -1252,19 +1086,6 @@ impl RpcClient {
|
||||
json!([self.maybe_map_commitment(commitment_config)?]),
|
||||
) {
|
||||
(context, blockhash, fee_calculator, last_valid_slot)
|
||||
} else if let Ok(Response {
|
||||
context,
|
||||
value:
|
||||
DeprecatedRpcFees {
|
||||
blockhash,
|
||||
fee_calculator,
|
||||
last_valid_slot,
|
||||
},
|
||||
}) = self.send::<Response<DeprecatedRpcFees>>(
|
||||
RpcRequest::GetFees,
|
||||
json!([self.maybe_map_commitment(commitment_config)?]),
|
||||
) {
|
||||
(context, blockhash, fee_calculator, last_valid_slot)
|
||||
} else if let Ok(Response {
|
||||
context,
|
||||
value:
|
||||
@@ -2062,7 +1883,7 @@ mod tests {
|
||||
// Send erroneous parameter
|
||||
let blockhash: ClientResult<String> =
|
||||
rpc_client.send(RpcRequest::GetRecentBlockhash, json!(["parameter"]));
|
||||
assert!(blockhash.is_err());
|
||||
assert_eq!(blockhash.is_err(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@@ -23,24 +23,14 @@ pub struct RpcSendTransactionConfig {
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcSimulateTransactionAccountsConfig {
|
||||
pub encoding: Option<UiAccountEncoding>,
|
||||
pub addresses: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcSimulateTransactionConfig {
|
||||
#[serde(default)]
|
||||
pub sig_verify: bool,
|
||||
#[serde(default)]
|
||||
pub replace_recent_blockhash: bool,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
pub accounts: Option<RpcSimulateTransactionAccountsConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
||||
@@ -137,7 +127,6 @@ pub struct RpcProgramAccountsConfig {
|
||||
pub filters: Option<Vec<RpcFilterType>>,
|
||||
#[serde(flatten)]
|
||||
pub account_config: RpcAccountInfoConfig,
|
||||
pub with_context: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
@@ -172,7 +161,7 @@ pub struct RpcSignatureSubscribeConfig {
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcSignaturesForAddressConfig {
|
||||
pub struct RpcGetConfirmedSignaturesForAddress2Config {
|
||||
pub before: Option<String>, // Signature as base-58 string
|
||||
pub until: Option<String>, // Signature as base-58 string
|
||||
pub limit: Option<usize>,
|
||||
@@ -194,17 +183,6 @@ impl<T: EncodingConfig + Default + Copy> RpcEncodingConfigWrapper<T> {
|
||||
RpcEncodingConfigWrapper::Current(config) => config.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert<U: EncodingConfig + From<T>>(&self) -> RpcEncodingConfigWrapper<U> {
|
||||
match self {
|
||||
RpcEncodingConfigWrapper::Deprecated(encoding) => {
|
||||
RpcEncodingConfigWrapper::Deprecated(*encoding)
|
||||
}
|
||||
RpcEncodingConfigWrapper::Current(config) => {
|
||||
RpcEncodingConfigWrapper::Current(config.map(|config| config.into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait EncodingConfig {
|
||||
@@ -213,7 +191,7 @@ pub trait EncodingConfig {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcBlockConfig {
|
||||
pub struct RpcConfirmedBlockConfig {
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
pub transaction_details: Option<TransactionDetails>,
|
||||
pub rewards: Option<bool>,
|
||||
@@ -221,7 +199,7 @@ pub struct RpcBlockConfig {
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
impl EncodingConfig for RpcBlockConfig {
|
||||
impl EncodingConfig for RpcConfirmedBlockConfig {
|
||||
fn new_with_encoding(encoding: &Option<UiTransactionEncoding>) -> Self {
|
||||
Self {
|
||||
encoding: *encoding,
|
||||
@@ -230,7 +208,7 @@ impl EncodingConfig for RpcBlockConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl RpcBlockConfig {
|
||||
impl RpcConfirmedBlockConfig {
|
||||
pub fn rewards_only() -> Self {
|
||||
Self {
|
||||
transaction_details: Some(TransactionDetails::None),
|
||||
@@ -247,21 +225,21 @@ impl RpcBlockConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RpcBlockConfig> for RpcEncodingConfigWrapper<RpcBlockConfig> {
|
||||
fn from(config: RpcBlockConfig) -> Self {
|
||||
impl From<RpcConfirmedBlockConfig> for RpcEncodingConfigWrapper<RpcConfirmedBlockConfig> {
|
||||
fn from(config: RpcConfirmedBlockConfig) -> Self {
|
||||
RpcEncodingConfigWrapper::Current(Some(config))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransactionConfig {
|
||||
pub struct RpcConfirmedTransactionConfig {
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
impl EncodingConfig for RpcTransactionConfig {
|
||||
impl EncodingConfig for RpcConfirmedTransactionConfig {
|
||||
fn new_with_encoding(encoding: &Option<UiTransactionEncoding>) -> Self {
|
||||
Self {
|
||||
encoding: *encoding,
|
||||
@@ -272,16 +250,16 @@ impl EncodingConfig for RpcTransactionConfig {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum RpcBlocksConfigWrapper {
|
||||
pub enum RpcConfirmedBlocksConfigWrapper {
|
||||
EndSlotOnly(Option<Slot>),
|
||||
CommitmentOnly(Option<CommitmentConfig>),
|
||||
}
|
||||
|
||||
impl RpcBlocksConfigWrapper {
|
||||
impl RpcConfirmedBlocksConfigWrapper {
|
||||
pub fn unzip(&self) -> (Option<Slot>, Option<CommitmentConfig>) {
|
||||
match &self {
|
||||
RpcBlocksConfigWrapper::EndSlotOnly(end_slot) => (*end_slot, None),
|
||||
RpcBlocksConfigWrapper::CommitmentOnly(commitment) => (None, *commitment),
|
||||
RpcConfirmedBlocksConfigWrapper::EndSlotOnly(end_slot) => (*end_slot, None),
|
||||
RpcConfirmedBlocksConfigWrapper::CommitmentOnly(commitment) => (None, *commitment),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,8 +15,6 @@ pub const JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: i64
|
||||
pub const JSON_RPC_SERVER_ERROR_SLOT_SKIPPED: i64 = -32007;
|
||||
pub const JSON_RPC_SERVER_ERROR_NO_SNAPSHOT: i64 = -32008;
|
||||
pub const JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED: i64 = -32009;
|
||||
pub const JSON_RPC_SERVER_ERROR_KEY_EXCLUDED_FROM_SECONDARY_INDEX: i64 = -32010;
|
||||
pub const JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE: i64 = -32011;
|
||||
|
||||
pub enum RpcCustomError {
|
||||
BlockCleanedUp {
|
||||
@@ -42,10 +40,6 @@ pub enum RpcCustomError {
|
||||
LongTermStorageSlotSkipped {
|
||||
slot: Slot,
|
||||
},
|
||||
KeyExcludedFromSecondaryIndex {
|
||||
index_key: String,
|
||||
},
|
||||
TransactionHistoryNotAvailable,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@@ -123,24 +117,6 @@ impl From<RpcCustomError> for Error {
|
||||
message: format!("Slot {} was skipped, or missing in long-term storage", slot),
|
||||
data: None,
|
||||
},
|
||||
RpcCustomError::KeyExcludedFromSecondaryIndex { index_key } => Self {
|
||||
code: ErrorCode::ServerError(
|
||||
JSON_RPC_SERVER_ERROR_KEY_EXCLUDED_FROM_SECONDARY_INDEX,
|
||||
),
|
||||
message: format!(
|
||||
"{} excluded from account secondary indexes; \
|
||||
this RPC method unavailable for key",
|
||||
index_key
|
||||
),
|
||||
data: None,
|
||||
},
|
||||
RpcCustomError::TransactionHistoryNotAvailable => Self {
|
||||
code: ErrorCode::ServerError(
|
||||
JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE,
|
||||
),
|
||||
message: "Transaction history is not available from this node".to_string(),
|
||||
data: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,120 +0,0 @@
|
||||
#![allow(deprecated)]
|
||||
use {
|
||||
crate::rpc_config::{
|
||||
EncodingConfig, RpcBlockConfig, RpcEncodingConfigWrapper, RpcTransactionConfig,
|
||||
},
|
||||
solana_sdk::{clock::Slot, commitment_config::CommitmentConfig},
|
||||
solana_transaction_status::{TransactionDetails, UiTransactionEncoding},
|
||||
};
|
||||
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcSignaturesForAddressConfig instead"
|
||||
)]
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcGetConfirmedSignaturesForAddress2Config {
|
||||
pub before: Option<String>, // Signature as base-58 string
|
||||
pub until: Option<String>, // Signature as base-58 string
|
||||
pub limit: Option<usize>,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcBlockConfig instead")]
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcConfirmedBlockConfig {
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
pub transaction_details: Option<TransactionDetails>,
|
||||
pub rewards: Option<bool>,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
impl EncodingConfig for RpcConfirmedBlockConfig {
|
||||
fn new_with_encoding(encoding: &Option<UiTransactionEncoding>) -> Self {
|
||||
Self {
|
||||
encoding: *encoding,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RpcConfirmedBlockConfig {
|
||||
pub fn rewards_only() -> Self {
|
||||
Self {
|
||||
transaction_details: Some(TransactionDetails::None),
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rewards_with_commitment(commitment: Option<CommitmentConfig>) -> Self {
|
||||
Self {
|
||||
transaction_details: Some(TransactionDetails::None),
|
||||
commitment,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RpcConfirmedBlockConfig> for RpcEncodingConfigWrapper<RpcConfirmedBlockConfig> {
|
||||
fn from(config: RpcConfirmedBlockConfig) -> Self {
|
||||
RpcEncodingConfigWrapper::Current(Some(config))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RpcConfirmedBlockConfig> for RpcBlockConfig {
|
||||
fn from(config: RpcConfirmedBlockConfig) -> Self {
|
||||
Self {
|
||||
encoding: config.encoding,
|
||||
transaction_details: config.transaction_details,
|
||||
rewards: config.rewards,
|
||||
commitment: config.commitment,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcTransactionConfig instead")]
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcConfirmedTransactionConfig {
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
impl EncodingConfig for RpcConfirmedTransactionConfig {
|
||||
fn new_with_encoding(encoding: &Option<UiTransactionEncoding>) -> Self {
|
||||
Self {
|
||||
encoding: *encoding,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RpcConfirmedTransactionConfig> for RpcTransactionConfig {
|
||||
fn from(config: RpcConfirmedTransactionConfig) -> Self {
|
||||
Self {
|
||||
encoding: config.encoding,
|
||||
commitment: config.commitment,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcBlocksConfigWrapper instead")]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum RpcConfirmedBlocksConfigWrapper {
|
||||
EndSlotOnly(Option<Slot>),
|
||||
CommitmentOnly(Option<CommitmentConfig>),
|
||||
}
|
||||
|
||||
impl RpcConfirmedBlocksConfigWrapper {
|
||||
pub fn unzip(&self) -> (Option<Slot>, Option<CommitmentConfig>) {
|
||||
match &self {
|
||||
RpcConfirmedBlocksConfigWrapper::EndSlotOnly(end_slot) => (*end_slot, None),
|
||||
RpcConfirmedBlocksConfigWrapper::CommitmentOnly(commitment) => (None, *commitment),
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,34 +11,21 @@ pub enum RpcRequest {
|
||||
DeregisterNode,
|
||||
GetAccountInfo,
|
||||
GetBalance,
|
||||
GetBlock,
|
||||
GetBlockHeight,
|
||||
GetBlockProduction,
|
||||
GetBlocks,
|
||||
GetBlocksWithLimit,
|
||||
GetBlockTime,
|
||||
GetClusterNodes,
|
||||
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcRequest::GetBlock instead")]
|
||||
GetConfirmedBlock,
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcRequest::GetBlocks instead")]
|
||||
GetConfirmedBlocks,
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcRequest::GetBlocksWithLimit instead"
|
||||
)]
|
||||
GetConfirmedBlocksWithLimit,
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcRequest::GetSignaturesForAddress instead"
|
||||
)]
|
||||
GetConfirmedSignaturesForAddress2,
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcRequest::GetTransaction instead"
|
||||
)]
|
||||
GetConfirmedTransaction,
|
||||
|
||||
#[deprecated(
|
||||
since = "1.5.19",
|
||||
note = "Please use RpcRequest::GetConfirmedSignaturesForAddress2 instead"
|
||||
)]
|
||||
GetConfirmedSignaturesForAddress,
|
||||
|
||||
GetConfirmedSignaturesForAddress2,
|
||||
GetConfirmedTransaction,
|
||||
GetEpochInfo,
|
||||
GetEpochSchedule,
|
||||
GetFeeCalculatorForBlockhash,
|
||||
@@ -61,7 +48,6 @@ pub enum RpcRequest {
|
||||
GetRecentBlockhash,
|
||||
GetRecentPerformanceSamples,
|
||||
GetSnapshotSlot,
|
||||
GetSignaturesForAddress,
|
||||
GetSignatureStatuses,
|
||||
GetSlot,
|
||||
GetSlotLeader,
|
||||
@@ -76,7 +62,10 @@ pub enum RpcRequest {
|
||||
GetTokenAccountsByDelegate,
|
||||
GetTokenAccountsByOwner,
|
||||
GetTokenSupply,
|
||||
GetTransaction,
|
||||
|
||||
#[deprecated(since = "1.5.19", note = "Please use RpcRequest::GetSupply instead")]
|
||||
GetTotalSupply,
|
||||
|
||||
GetTransactionCount,
|
||||
GetVersion,
|
||||
GetVoteAccounts,
|
||||
@@ -95,16 +84,13 @@ impl fmt::Display for RpcRequest {
|
||||
RpcRequest::DeregisterNode => "deregisterNode",
|
||||
RpcRequest::GetAccountInfo => "getAccountInfo",
|
||||
RpcRequest::GetBalance => "getBalance",
|
||||
RpcRequest::GetBlock => "getBlock",
|
||||
RpcRequest::GetBlockHeight => "getBlockHeight",
|
||||
RpcRequest::GetBlockProduction => "getBlockProduction",
|
||||
RpcRequest::GetBlocks => "getBlocks",
|
||||
RpcRequest::GetBlocksWithLimit => "getBlocksWithLimit",
|
||||
RpcRequest::GetBlockTime => "getBlockTime",
|
||||
RpcRequest::GetClusterNodes => "getClusterNodes",
|
||||
RpcRequest::GetConfirmedBlock => "getConfirmedBlock",
|
||||
RpcRequest::GetConfirmedBlocks => "getConfirmedBlocks",
|
||||
RpcRequest::GetConfirmedBlocksWithLimit => "getConfirmedBlocksWithLimit",
|
||||
RpcRequest::GetConfirmedSignaturesForAddress => "getConfirmedSignaturesForAddress",
|
||||
RpcRequest::GetConfirmedSignaturesForAddress2 => "getConfirmedSignaturesForAddress2",
|
||||
RpcRequest::GetConfirmedTransaction => "getConfirmedTransaction",
|
||||
RpcRequest::GetEpochInfo => "getEpochInfo",
|
||||
@@ -129,7 +115,6 @@ impl fmt::Display for RpcRequest {
|
||||
RpcRequest::GetRecentBlockhash => "getRecentBlockhash",
|
||||
RpcRequest::GetRecentPerformanceSamples => "getRecentPerformanceSamples",
|
||||
RpcRequest::GetSnapshotSlot => "getSnapshotSlot",
|
||||
RpcRequest::GetSignaturesForAddress => "getSignaturesForAddress",
|
||||
RpcRequest::GetSignatureStatuses => "getSignatureStatuses",
|
||||
RpcRequest::GetSlot => "getSlot",
|
||||
RpcRequest::GetSlotLeader => "getSlotLeader",
|
||||
@@ -144,7 +129,7 @@ impl fmt::Display for RpcRequest {
|
||||
RpcRequest::GetTokenAccountsByDelegate => "getTokenAccountsByDelegate",
|
||||
RpcRequest::GetTokenAccountsByOwner => "getTokenAccountsByOwner",
|
||||
RpcRequest::GetTokenSupply => "getTokenSupply",
|
||||
RpcRequest::GetTransaction => "getTransaction",
|
||||
RpcRequest::GetTotalSupply => "getTotalSupply",
|
||||
RpcRequest::GetTransactionCount => "getTransactionCount",
|
||||
RpcRequest::GetVersion => "getVersion",
|
||||
RpcRequest::GetVoteAccounts => "getVoteAccounts",
|
||||
|
@@ -46,15 +46,6 @@ pub struct RpcFees {
|
||||
pub blockhash: String,
|
||||
pub fee_calculator: FeeCalculator,
|
||||
pub last_valid_slot: Slot,
|
||||
pub last_valid_block_height: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeprecatedRpcFees {
|
||||
pub blockhash: String,
|
||||
pub fee_calculator: FeeCalculator,
|
||||
pub last_valid_slot: Slot,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
@@ -215,8 +206,6 @@ pub struct RpcContactInfo {
|
||||
pub version: Option<String>,
|
||||
/// First 4 bytes of the FeatureSet identifier
|
||||
pub feature_set: Option<u32>,
|
||||
/// Shred version
|
||||
pub shred_version: Option<u16>,
|
||||
}
|
||||
|
||||
/// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot
|
||||
@@ -318,7 +307,6 @@ pub struct RpcSignatureConfirmation {
|
||||
pub struct RpcSimulateTransactionResult {
|
||||
pub err: Option<TransactionError>,
|
||||
pub logs: Option<Vec<String>>,
|
||||
pub accounts: Option<Vec<Option<UiAccount>>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
|
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "solana-core"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.7.2"
|
||||
version = "1.6.7"
|
||||
homepage = "https://solana.com/"
|
||||
documentation = "https://docs.rs/solana-core"
|
||||
readme = "../README.md"
|
||||
@@ -22,12 +22,19 @@ bv = { version = "0.11.1", features = ["serde"] }
|
||||
bs58 = "0.3.1"
|
||||
byteorder = "1.3.4"
|
||||
chrono = { version = "0.4.11", features = ["serde"] }
|
||||
core_affinity = "0.5.10"
|
||||
crossbeam-channel = "0.4"
|
||||
ed25519-dalek = "=1.0.1"
|
||||
fs_extra = "1.2.0"
|
||||
flate2 = "1.0"
|
||||
indexmap = { version = "1.5", features = ["rayon"] }
|
||||
itertools = "0.9.0"
|
||||
jsonrpc-core = "17.0.0"
|
||||
jsonrpc-core-client = { version = "17.0.0", features = ["ipc", "ws"] }
|
||||
jsonrpc-derive = "17.0.0"
|
||||
jsonrpc-http-server = "17.0.0"
|
||||
jsonrpc-pubsub = "17.0.0"
|
||||
jsonrpc-ws-server = "17.0.0"
|
||||
libc = "0.2.81"
|
||||
log = "0.4.11"
|
||||
lru = "0.6.1"
|
||||
@@ -39,52 +46,52 @@ rand_chacha = "0.2.2"
|
||||
rand_core = "0.6.2"
|
||||
raptorq = "1.4.2"
|
||||
rayon = "1.5.0"
|
||||
regex = "1.3.9"
|
||||
retain_mut = "0.1.2"
|
||||
serde = "1.0.122"
|
||||
serde_bytes = "0.11"
|
||||
serde_derive = "1.0.103"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.7.2" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
|
||||
solana-client = { path = "../client", version = "=1.7.2" }
|
||||
solana-gossip = { path = "../gossip", version = "=1.7.2" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.7.2" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.2" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "=1.7.2" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.7.2" }
|
||||
solana-measure = { path = "../measure", version = "=1.7.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
|
||||
solana-perf = { path = "../perf", version = "=1.7.2" }
|
||||
solana-poh = { path = "../poh", version = "=1.7.2" }
|
||||
solana-program-test = { path = "../program-test", version = "=1.7.2" }
|
||||
solana-rpc = { path = "../rpc", version = "=1.7.2" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||
solana-frozen-abi = { path = "../frozen-abi", version = "=1.7.2" }
|
||||
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.7.2" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.7.2" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
||||
solana-version = { path = "../version", version = "=1.7.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.7" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.6.7" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.7" }
|
||||
solana-client = { path = "../client", version = "=1.6.7" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.7" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.7" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.7" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "=1.6.7" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.7" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.7" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.7" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.7" }
|
||||
solana-program-test = { path = "../program-test", version = "=1.6.7" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.7" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.7" }
|
||||
solana-frozen-abi = { path = "../frozen-abi", version = "=1.6.7" }
|
||||
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.6.7" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.7" }
|
||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.6.7" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.7" }
|
||||
solana-sys-tuner = { path = "../sys-tuner", version = "=1.6.7" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.7" }
|
||||
solana-version = { path = "../version", version = "=1.6.7" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.7" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.0", features = ["no-entrypoint"] }
|
||||
tempfile = "3.1.0"
|
||||
thiserror = "1.0"
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.7.2" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio_02 = { version = "0.2", package = "tokio", features = ["full"] }
|
||||
tokio-util = { version = "0.3", features = ["codec"] } # This crate needs to stay in sync with tokio_02, until that dependency can be removed
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.6.7" }
|
||||
trees = "0.2.1"
|
||||
|
||||
[dev-dependencies]
|
||||
jsonrpc-core = "17.1.0"
|
||||
jsonrpc-core-client = { version = "17.1.0", features = ["ipc", "ws"] }
|
||||
matches = "0.1.6"
|
||||
num_cpus = "1.13.0"
|
||||
reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
serde_json = "1.0.56"
|
||||
serial_test = "0.4.0"
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
||||
solana-version = { path = "../version", version = "=1.7.2" }
|
||||
symlink = "0.1.0"
|
||||
systemstat = "0.1.5"
|
||||
tokio_02 = { version = "0.2", package = "tokio", features = ["full"] }
|
||||
|
||||
[build-dependencies]
|
||||
rustc_version = "0.2"
|
||||
@@ -96,7 +103,13 @@ name = "banking_stage"
|
||||
name = "blockstore"
|
||||
|
||||
[[bench]]
|
||||
name = "cluster_info"
|
||||
name = "crds"
|
||||
|
||||
[[bench]]
|
||||
name = "crds_gossip_pull"
|
||||
|
||||
[[bench]]
|
||||
name = "crds_shards"
|
||||
|
||||
[[bench]]
|
||||
name = "gen_keys"
|
||||
@@ -104,8 +117,14 @@ name = "gen_keys"
|
||||
[[bench]]
|
||||
name = "sigverify_stage"
|
||||
|
||||
[[bench]]
|
||||
name = "poh"
|
||||
|
||||
[[bench]]
|
||||
name = "retransmit_stage"
|
||||
|
||||
[[bench]]
|
||||
name = "cluster_info"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -7,16 +7,16 @@ use crossbeam_channel::unbounded;
|
||||
use log::*;
|
||||
use rand::{thread_rng, Rng};
|
||||
use rayon::prelude::*;
|
||||
use solana_core::banking_stage::{BankingStage, BankingStageStats};
|
||||
use solana_gossip::cluster_info::ClusterInfo;
|
||||
use solana_gossip::cluster_info::Node;
|
||||
use solana_core::banking_stage::{create_test_recorder, BankingStage, BankingStageStats};
|
||||
use solana_core::cluster_info::ClusterInfo;
|
||||
use solana_core::cluster_info::Node;
|
||||
use solana_core::poh_recorder::WorkingBankEntry;
|
||||
use solana_ledger::blockstore_processor::process_entries;
|
||||
use solana_ledger::entry::{next_hash, Entry};
|
||||
use solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo};
|
||||
use solana_ledger::{blockstore::Blockstore, get_tmp_ledger_path};
|
||||
use solana_perf::packet::to_packets_chunked;
|
||||
use solana_perf::test_tx::test_tx;
|
||||
use solana_poh::poh_recorder::{create_test_recorder, WorkingBankEntry};
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_sdk::genesis_config::GenesisConfig;
|
||||
use solana_sdk::hash::Hash;
|
||||
|
@@ -5,8 +5,8 @@ extern crate test;
|
||||
use rand::{thread_rng, Rng};
|
||||
use solana_core::broadcast_stage::broadcast_metrics::TransmitShredsStats;
|
||||
use solana_core::broadcast_stage::{broadcast_shreds, get_broadcast_peers};
|
||||
use solana_gossip::cluster_info::{ClusterInfo, Node};
|
||||
use solana_gossip::contact_info::ContactInfo;
|
||||
use solana_core::cluster_info::{ClusterInfo, Node};
|
||||
use solana_core::contact_info::ContactInfo;
|
||||
use solana_ledger::shred::Shred;
|
||||
use solana_sdk::pubkey;
|
||||
use solana_sdk::timing::timestamp;
|
||||
|
@@ -2,16 +2,14 @@
|
||||
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
rand::{thread_rng, Rng},
|
||||
rayon::ThreadPoolBuilder,
|
||||
solana_gossip::{
|
||||
crds::Crds, crds_gossip_pull::CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS, crds_value::CrdsValue,
|
||||
},
|
||||
solana_sdk::pubkey::Pubkey,
|
||||
std::collections::HashMap,
|
||||
test::Bencher,
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use solana_core::crds::Crds;
|
||||
use solana_core::crds_gossip_pull::CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS;
|
||||
use solana_core::crds_value::CrdsValue;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use std::collections::HashMap;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_find_old_labels(bencher: &mut Bencher) {
|
@@ -2,18 +2,14 @@
|
||||
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
rand::{thread_rng, Rng},
|
||||
rayon::ThreadPoolBuilder,
|
||||
solana_gossip::{
|
||||
cluster_info::MAX_BLOOM_SIZE,
|
||||
crds::Crds,
|
||||
crds_gossip_pull::{CrdsFilter, CrdsGossipPull},
|
||||
crds_value::CrdsValue,
|
||||
},
|
||||
solana_sdk::hash,
|
||||
test::Bencher,
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use solana_core::cluster_info::MAX_BLOOM_SIZE;
|
||||
use solana_core::crds::Crds;
|
||||
use solana_core::crds_gossip_pull::{CrdsFilter, CrdsGossipPull};
|
||||
use solana_core::crds_value::CrdsValue;
|
||||
use solana_sdk::hash;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_hash_as_u64(bencher: &mut Bencher) {
|
||||
@@ -33,8 +29,13 @@ fn bench_hash_as_u64(bencher: &mut Bencher) {
|
||||
fn bench_build_crds_filters(bencher: &mut Bencher) {
|
||||
let thread_pool = ThreadPoolBuilder::new().build().unwrap();
|
||||
let mut rng = thread_rng();
|
||||
let crds_gossip_pull = CrdsGossipPull::default();
|
||||
let mut crds_gossip_pull = CrdsGossipPull::default();
|
||||
let mut crds = Crds::default();
|
||||
for _ in 0..50_000 {
|
||||
crds_gossip_pull
|
||||
.purged_values
|
||||
.push_back((solana_sdk::hash::new_rand(&mut rng), rng.gen()));
|
||||
}
|
||||
let mut num_inserts = 0;
|
||||
for _ in 0..90_000 {
|
||||
if crds
|
@@ -2,17 +2,15 @@
|
||||
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
rand::{thread_rng, Rng},
|
||||
solana_gossip::{
|
||||
crds::{Crds, VersionedCrdsValue},
|
||||
crds_shards::CrdsShards,
|
||||
crds_value::CrdsValue,
|
||||
},
|
||||
solana_sdk::timing::timestamp,
|
||||
std::iter::repeat_with,
|
||||
test::Bencher,
|
||||
use rand::{thread_rng, Rng};
|
||||
use solana_core::{
|
||||
crds::{Crds, VersionedCrdsValue},
|
||||
crds_shards::CrdsShards,
|
||||
crds_value::CrdsValue,
|
||||
};
|
||||
use solana_sdk::timing::timestamp;
|
||||
use std::iter::repeat_with;
|
||||
use test::Bencher;
|
||||
|
||||
const CRDS_SHARDS_BITS: u32 = 8;
|
||||
|
||||
@@ -21,7 +19,7 @@ fn new_test_crds_value<R: Rng>(rng: &mut R) -> VersionedCrdsValue {
|
||||
let label = value.label();
|
||||
let mut crds = Crds::default();
|
||||
crds.insert(value, timestamp()).unwrap();
|
||||
crds.get(&label).cloned().unwrap()
|
||||
crds.remove(&label).unwrap()
|
||||
}
|
||||
|
||||
fn bench_crds_shards_find(bencher: &mut Bencher, num_values: usize, mask_bits: u32) {
|
@@ -3,16 +3,12 @@
|
||||
#![feature(test)]
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
solana_ledger::poh::Poh,
|
||||
solana_poh::poh_service::DEFAULT_HASHES_PER_BATCH,
|
||||
solana_sdk::hash::Hash,
|
||||
std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Mutex,
|
||||
},
|
||||
test::Bencher,
|
||||
};
|
||||
use solana_core::poh_service::DEFAULT_HASHES_PER_BATCH;
|
||||
use solana_ledger::poh::Poh;
|
||||
use solana_sdk::hash::Hash;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use test::Bencher;
|
||||
|
||||
const NUM_HASHES: u64 = 30_000; // Should require ~10ms on a 2017 MacBook Pro
|
||||
|
@@ -1,15 +1,11 @@
|
||||
#![feature(test)]
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
solana_ledger::entry::{next_entry_mut, Entry, EntrySlice},
|
||||
solana_sdk::{
|
||||
hash::{hash, Hash},
|
||||
signature::{Keypair, Signer},
|
||||
system_transaction,
|
||||
},
|
||||
test::Bencher,
|
||||
};
|
||||
use solana_ledger::entry::{next_entry_mut, Entry, EntrySlice};
|
||||
use solana_sdk::hash::{hash, Hash};
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use solana_sdk::system_transaction;
|
||||
use test::Bencher;
|
||||
|
||||
const NUM_HASHES: u64 = 400;
|
||||
const NUM_ENTRIES: usize = 800;
|
@@ -4,16 +4,16 @@ extern crate solana_core;
|
||||
extern crate test;
|
||||
|
||||
use log::*;
|
||||
use solana_core::cluster_info::{ClusterInfo, Node};
|
||||
use solana_core::contact_info::ContactInfo;
|
||||
use solana_core::max_slots::MaxSlots;
|
||||
use solana_core::retransmit_stage::retransmitter;
|
||||
use solana_gossip::cluster_info::{ClusterInfo, Node};
|
||||
use solana_gossip::contact_info::ContactInfo;
|
||||
use solana_ledger::entry::Entry;
|
||||
use solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo};
|
||||
use solana_ledger::leader_schedule_cache::LeaderScheduleCache;
|
||||
use solana_ledger::shred::Shredder;
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_perf::packet::{Packet, Packets};
|
||||
use solana_rpc::max_slots::MaxSlots;
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_runtime::bank_forks::BankForks;
|
||||
use solana_sdk::hash::Hash;
|
||||
@@ -39,12 +39,7 @@ fn bench_retransmitter(bencher: &mut Bencher) {
|
||||
const NUM_PEERS: usize = 4;
|
||||
let mut peer_sockets = Vec::new();
|
||||
for _ in 0..NUM_PEERS {
|
||||
// This ensures that cluster_info.id() is the root of turbine
|
||||
// retransmit tree and so the shreds are retransmited to all other
|
||||
// nodes in the cluster.
|
||||
let id = std::iter::repeat_with(pubkey::new_rand)
|
||||
.find(|pk| cluster_info.id() < *pk)
|
||||
.unwrap();
|
||||
let id = pubkey::new_rand();
|
||||
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
let mut contact_info = ContactInfo::new_localhost(&id, timestamp());
|
||||
contact_info.tvu = socket.local_addr().unwrap();
|
||||
|
@@ -8,7 +8,7 @@ use raptorq::{Decoder, Encoder};
|
||||
use solana_ledger::entry::{create_ticks, Entry};
|
||||
use solana_ledger::shred::{
|
||||
max_entries_per_n_shred, max_ticks_per_n_shreds, ProcessShredsStats, Shred, Shredder,
|
||||
MAX_DATA_SHREDS_PER_FEC_BLOCK, SHRED_PAYLOAD_SIZE, SIZE_OF_CODING_SHRED_HEADERS,
|
||||
MAX_DATA_SHREDS_PER_FEC_BLOCK, SHRED_PAYLOAD_SIZE, SIZE_OF_DATA_SHRED_IGNORED_TAIL,
|
||||
SIZE_OF_DATA_SHRED_PAYLOAD,
|
||||
};
|
||||
use solana_perf::test_tx;
|
||||
@@ -55,7 +55,7 @@ fn make_shreds(num_shreds: usize) -> Vec<Shred> {
|
||||
|
||||
fn make_concatenated_shreds(num_shreds: usize) -> Vec<u8> {
|
||||
let data_shreds = make_shreds(num_shreds);
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_CODING_SHRED_HEADERS) as usize;
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_DATA_SHRED_IGNORED_TAIL) as usize;
|
||||
let mut data: Vec<u8> = vec![0; num_shreds * valid_shred_data_len];
|
||||
for (i, shred) in (data_shreds[0..num_shreds]).iter().enumerate() {
|
||||
data[i * valid_shred_data_len..(i + 1) * valid_shred_data_len]
|
||||
@@ -163,7 +163,7 @@ fn bench_shredder_decoding(bencher: &mut Bencher) {
|
||||
fn bench_shredder_coding_raptorq(bencher: &mut Bencher) {
|
||||
let symbol_count = MAX_DATA_SHREDS_PER_FEC_BLOCK;
|
||||
let data = make_concatenated_shreds(symbol_count as usize);
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_CODING_SHRED_HEADERS) as usize;
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_DATA_SHRED_IGNORED_TAIL) as usize;
|
||||
bencher.iter(|| {
|
||||
let encoder = Encoder::with_defaults(&data, valid_shred_data_len as u16);
|
||||
encoder.get_encoded_packets(symbol_count);
|
||||
@@ -174,7 +174,7 @@ fn bench_shredder_coding_raptorq(bencher: &mut Bencher) {
|
||||
fn bench_shredder_decoding_raptorq(bencher: &mut Bencher) {
|
||||
let symbol_count = MAX_DATA_SHREDS_PER_FEC_BLOCK;
|
||||
let data = make_concatenated_shreds(symbol_count as usize);
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_CODING_SHRED_HEADERS) as usize;
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_DATA_SHRED_IGNORED_TAIL) as usize;
|
||||
let encoder = Encoder::with_defaults(&data, valid_shred_data_len as u16);
|
||||
let mut packets = encoder.get_encoded_packets(symbol_count as u32);
|
||||
packets.shuffle(&mut rand::thread_rng());
|
||||
|
@@ -4,9 +4,11 @@
|
||||
// hash on gossip. Monitor gossip for messages from validators in the --trusted-validators
|
||||
// set and halt the node if a mismatch is detected.
|
||||
|
||||
use crate::snapshot_packager_service::PendingSnapshotPackage;
|
||||
use crate::{
|
||||
cluster_info::{ClusterInfo, MAX_SNAPSHOT_HASHES},
|
||||
snapshot_packager_service::PendingSnapshotPackage,
|
||||
};
|
||||
use rayon::ThreadPool;
|
||||
use solana_gossip::cluster_info::{ClusterInfo, MAX_SNAPSHOT_HASHES};
|
||||
use solana_runtime::{
|
||||
accounts_db,
|
||||
snapshot_package::{AccountsPackage, AccountsPackagePre, AccountsPackageReceiver},
|
||||
@@ -41,7 +43,7 @@ impl AccountsHashVerifier {
|
||||
let exit = exit.clone();
|
||||
let cluster_info = cluster_info.clone();
|
||||
let t_accounts_hash_verifier = Builder::new()
|
||||
.name("solana-hash-accounts".to_string())
|
||||
.name("solana-accounts-hash".to_string())
|
||||
.spawn(move || {
|
||||
let mut hashes = vec![];
|
||||
let mut thread_pool_storage = None;
|
||||
@@ -216,7 +218,8 @@ impl AccountsHashVerifier {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use solana_gossip::{cluster_info::make_accounts_hashes_message, contact_info::ContactInfo};
|
||||
use crate::cluster_info::make_accounts_hashes_message;
|
||||
use crate::contact_info::ContactInfo;
|
||||
use solana_runtime::bank_forks::ArchiveFormat;
|
||||
use solana_runtime::snapshot_utils::SnapshotVersion;
|
||||
use solana_sdk::{
|
||||
|
@@ -1,21 +1,27 @@
|
||||
//! The `banking_stage` processes Transaction messages. It is intended to be used
|
||||
//! to contruct a software pipeline. The stage uses all available CPU cores and
|
||||
//! can do its processing in parallel with signature verification on the GPU.
|
||||
use crate::packet_hasher::PacketHasher;
|
||||
use crate::{
|
||||
cluster_info::ClusterInfo,
|
||||
packet_hasher::PacketHasher,
|
||||
poh_recorder::{PohRecorder, PohRecorderError, TransactionRecorder, WorkingBankEntry},
|
||||
poh_service::{self, PohService},
|
||||
};
|
||||
use crossbeam_channel::{Receiver as CrossbeamReceiver, RecvTimeoutError};
|
||||
use itertools::Itertools;
|
||||
use lru::LruCache;
|
||||
use retain_mut::RetainMut;
|
||||
use solana_gossip::cluster_info::ClusterInfo;
|
||||
use solana_ledger::{blockstore_processor::TransactionStatusSender, entry::hash_transactions};
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_ledger::{
|
||||
blockstore::Blockstore, blockstore_processor::TransactionStatusSender,
|
||||
entry::hash_transactions, leader_schedule_cache::LeaderScheduleCache,
|
||||
};
|
||||
use solana_measure::{measure::Measure, thread_mem_usage};
|
||||
use solana_metrics::{inc_new_counter_debug, inc_new_counter_info};
|
||||
use solana_perf::{
|
||||
cuda_runtime::PinnedVec,
|
||||
packet::{limited_deserialize, Packet, Packets, PACKETS_PER_BATCH},
|
||||
perf_libs,
|
||||
};
|
||||
use solana_poh::poh_recorder::{PohRecorder, PohRecorderError, TransactionRecorder};
|
||||
use solana_runtime::{
|
||||
accounts_db::ErrorCounters,
|
||||
bank::{
|
||||
@@ -33,6 +39,7 @@ use solana_sdk::{
|
||||
MAX_TRANSACTION_FORWARDING_DELAY_GPU,
|
||||
},
|
||||
message::Message,
|
||||
poh_config::PohConfig,
|
||||
pubkey::Pubkey,
|
||||
short_vec::decode_shortu16_len,
|
||||
signature::Signature,
|
||||
@@ -50,7 +57,8 @@ use std::{
|
||||
mem::size_of,
|
||||
net::UdpSocket,
|
||||
ops::DerefMut,
|
||||
sync::atomic::{AtomicU64, AtomicUsize, Ordering},
|
||||
sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering},
|
||||
sync::mpsc::Receiver,
|
||||
sync::{Arc, Mutex},
|
||||
thread::{self, Builder, JoinHandle},
|
||||
time::Duration,
|
||||
@@ -271,6 +279,7 @@ impl BankingStage {
|
||||
Builder::new()
|
||||
.name("solana-banking-stage-tx".to_string())
|
||||
.spawn(move || {
|
||||
thread_mem_usage::datapoint("solana-banking-stage-tx");
|
||||
Self::process_loop(
|
||||
my_pubkey,
|
||||
&verified_receiver,
|
||||
@@ -807,7 +816,6 @@ impl BankingStage {
|
||||
TransactionTokenBalancesSet::new(pre_token_balances, post_token_balances),
|
||||
inner_instructions,
|
||||
transaction_logs,
|
||||
tx_results.rent_debits,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1384,29 +1392,65 @@ fn next_leader_tpu_forwards(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_test_recorder(
|
||||
bank: &Arc<Bank>,
|
||||
blockstore: &Arc<Blockstore>,
|
||||
poh_config: Option<PohConfig>,
|
||||
) -> (
|
||||
Arc<AtomicBool>,
|
||||
Arc<Mutex<PohRecorder>>,
|
||||
PohService,
|
||||
Receiver<WorkingBankEntry>,
|
||||
) {
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
let poh_config = Arc::new(poh_config.unwrap_or_default());
|
||||
let (mut poh_recorder, entry_receiver, record_receiver) = PohRecorder::new(
|
||||
bank.tick_height(),
|
||||
bank.last_blockhash(),
|
||||
bank.slot(),
|
||||
Some((4, 4)),
|
||||
bank.ticks_per_slot(),
|
||||
&Pubkey::default(),
|
||||
blockstore,
|
||||
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
||||
&poh_config,
|
||||
exit.clone(),
|
||||
);
|
||||
poh_recorder.set_bank(&bank);
|
||||
|
||||
let poh_recorder = Arc::new(Mutex::new(poh_recorder));
|
||||
let poh_service = PohService::new(
|
||||
poh_recorder.clone(),
|
||||
&poh_config,
|
||||
&exit,
|
||||
bank.ticks_per_slot(),
|
||||
poh_service::DEFAULT_PINNED_CPU_CORE,
|
||||
poh_service::DEFAULT_HASHES_PER_BATCH,
|
||||
record_receiver,
|
||||
);
|
||||
|
||||
(exit, poh_recorder, poh_service, entry_receiver)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
cluster_info::Node, poh_recorder::Record, poh_recorder::WorkingBank,
|
||||
transaction_status_service::TransactionStatusService,
|
||||
};
|
||||
use crossbeam_channel::unbounded;
|
||||
use itertools::Itertools;
|
||||
use solana_gossip::cluster_info::Node;
|
||||
use solana_ledger::{
|
||||
blockstore::{entries_to_test_shreds, Blockstore},
|
||||
blockstore::entries_to_test_shreds,
|
||||
entry::{next_entry, Entry, EntrySlice},
|
||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||
get_tmp_ledger_path,
|
||||
leader_schedule_cache::LeaderScheduleCache,
|
||||
};
|
||||
use solana_perf::packet::to_packets_chunked;
|
||||
use solana_poh::{
|
||||
poh_recorder::{create_test_recorder, Record, WorkingBank, WorkingBankEntry},
|
||||
poh_service::PohService,
|
||||
};
|
||||
use solana_rpc::transaction_status_service::TransactionStatusService;
|
||||
use solana_sdk::{
|
||||
hash::Hash,
|
||||
instruction::InstructionError,
|
||||
poh_config::PohConfig,
|
||||
signature::{Keypair, Signer},
|
||||
system_instruction::SystemError,
|
||||
system_transaction,
|
||||
@@ -1416,10 +1460,7 @@ mod tests {
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
path::Path,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc::Receiver,
|
||||
},
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
thread::sleep,
|
||||
};
|
||||
|
||||
@@ -1507,7 +1548,7 @@ mod tests {
|
||||
.collect();
|
||||
trace!("done");
|
||||
assert_eq!(entries.len(), genesis_config.ticks_per_slot as usize);
|
||||
assert!(entries.verify(&start_hash));
|
||||
assert_eq!(entries.verify(&start_hash), true);
|
||||
assert_eq!(entries[entries.len() - 1].hash, bank.last_blockhash());
|
||||
banking_stage.join().unwrap();
|
||||
}
|
||||
@@ -1616,7 +1657,7 @@ mod tests {
|
||||
.map(|(_bank, (entry, _tick_height))| entry)
|
||||
.collect();
|
||||
|
||||
assert!(entries.verify(&blockhash));
|
||||
assert_eq!(entries.verify(&blockhash), true);
|
||||
if !entries.is_empty() {
|
||||
blockhash = entries.last().unwrap().hash;
|
||||
for entry in entries {
|
||||
@@ -2084,7 +2125,7 @@ mod tests {
|
||||
}
|
||||
trace!("done ticking");
|
||||
|
||||
assert!(done);
|
||||
assert_eq!(done, true);
|
||||
|
||||
let transactions = vec![system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
|
@@ -1,19 +1,17 @@
|
||||
use {
|
||||
crate::{bigtable_upload, blockstore::Blockstore},
|
||||
solana_runtime::commitment::BlockCommitmentCache,
|
||||
std::{
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
sync::{Arc, RwLock},
|
||||
thread::{self, Builder, JoinHandle},
|
||||
},
|
||||
tokio::runtime::Runtime,
|
||||
use solana_ledger::blockstore::Blockstore;
|
||||
use solana_runtime::commitment::BlockCommitmentCache;
|
||||
use std::{
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
sync::{Arc, RwLock},
|
||||
thread::{self, Builder, JoinHandle},
|
||||
};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
// Delay uploading the largest confirmed root for this many slots. This is done in an attempt to
|
||||
// ensure that the `CacheBlockMetaService` has had enough time to add the block time for the root
|
||||
// ensure that the `CacheBlockTimeService` has had enough time to add the block time for the root
|
||||
// before it's uploaded to BigTable.
|
||||
//
|
||||
// A more direct connection between CacheBlockMetaService and BigTableUploadService would be
|
||||
// A more direct connection between CacheBlockTimeService and BigTableUploadService would be
|
||||
// preferable...
|
||||
const LARGEST_CONFIRMED_ROOT_UPLOAD_DELAY: usize = 100;
|
||||
|
||||
@@ -70,7 +68,7 @@ impl BigTableUploadService {
|
||||
continue;
|
||||
}
|
||||
|
||||
let result = runtime.block_on(bigtable_upload::upload_confirmed_blocks(
|
||||
let result = runtime.block_on(solana_ledger::bigtable_upload::upload_confirmed_blocks(
|
||||
blockstore.clone(),
|
||||
bigtable_ledger_storage.clone(),
|
||||
start_slot,
|
@@ -1,26 +1,25 @@
|
||||
//! A stage to broadcast data from a leader node to validators
|
||||
#![allow(clippy::rc_buffer)]
|
||||
use self::{
|
||||
broadcast_duplicates_run::BroadcastDuplicatesRun,
|
||||
broadcast_fake_shreds_run::BroadcastFakeShredsRun, broadcast_metrics::*,
|
||||
fail_entry_verification_broadcast_run::FailEntryVerificationBroadcastRun,
|
||||
standard_broadcast_run::StandardBroadcastRun,
|
||||
};
|
||||
use crate::result::{Error, Result};
|
||||
use crate::contact_info::ContactInfo;
|
||||
use crate::crds_gossip_pull::CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS;
|
||||
use crate::weighted_shuffle::weighted_best;
|
||||
use crate::{
|
||||
cluster_info::{ClusterInfo, ClusterInfoError},
|
||||
poh_recorder::WorkingBankEntry,
|
||||
result::{Error, Result},
|
||||
};
|
||||
use crossbeam_channel::{
|
||||
Receiver as CrossbeamReceiver, RecvTimeoutError as CrossbeamRecvTimeoutError,
|
||||
Sender as CrossbeamSender,
|
||||
};
|
||||
use solana_gossip::{
|
||||
cluster_info::{self, ClusterInfo, ClusterInfoError},
|
||||
contact_info::ContactInfo,
|
||||
crds_gossip_pull::CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS,
|
||||
weighted_shuffle::weighted_best,
|
||||
};
|
||||
use solana_ledger::{blockstore::Blockstore, shred::Shred};
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_metrics::{inc_new_counter_error, inc_new_counter_info};
|
||||
use solana_poh::poh_recorder::WorkingBankEntry;
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_sdk::timing::timestamp;
|
||||
use solana_sdk::{clock::Slot, pubkey::Pubkey};
|
||||
@@ -36,7 +35,6 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
mod broadcast_duplicates_run;
|
||||
mod broadcast_fake_shreds_run;
|
||||
pub mod broadcast_metrics;
|
||||
pub(crate) mod broadcast_utils;
|
||||
@@ -54,20 +52,11 @@ pub enum BroadcastStageReturnType {
|
||||
ChannelDisconnected,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub struct BroadcastDuplicatesConfig {
|
||||
/// Percentage of stake to send different version of slots to
|
||||
pub stake_partition: u8,
|
||||
/// Number of slots to wait before sending duplicate shreds
|
||||
pub duplicate_send_delay: usize,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub enum BroadcastStageType {
|
||||
Standard,
|
||||
FailEntryVerification,
|
||||
BroadcastFakeShreds,
|
||||
BroadcastDuplicates(BroadcastDuplicatesConfig),
|
||||
}
|
||||
|
||||
impl BroadcastStageType {
|
||||
@@ -112,16 +101,6 @@ impl BroadcastStageType {
|
||||
blockstore,
|
||||
BroadcastFakeShredsRun::new(keypair, 0, shred_version),
|
||||
),
|
||||
|
||||
BroadcastStageType::BroadcastDuplicates(config) => BroadcastStage::new(
|
||||
sock,
|
||||
cluster_info,
|
||||
receiver,
|
||||
retransmit_slots_receiver,
|
||||
exit_sender,
|
||||
blockstore,
|
||||
BroadcastDuplicatesRun::new(keypair, shred_version, config.clone()),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -384,6 +363,7 @@ pub fn get_broadcast_peers(
|
||||
cluster_info: &ClusterInfo,
|
||||
stakes: Option<&HashMap<Pubkey, u64>>,
|
||||
) -> (Vec<ContactInfo>, Vec<(u64, usize)>) {
|
||||
use crate::cluster_info;
|
||||
let mut peers = cluster_info.tvu_peers();
|
||||
let peers_and_stakes = cluster_info::stake_weight_peers(&mut peers, stakes);
|
||||
(peers, peers_and_stakes)
|
||||
@@ -460,8 +440,8 @@ fn num_live_peers(peers: &[ContactInfo]) -> i64 {
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use super::*;
|
||||
use crate::cluster_info::{ClusterInfo, Node};
|
||||
use crossbeam_channel::unbounded;
|
||||
use solana_gossip::cluster_info::{ClusterInfo, Node};
|
||||
use solana_ledger::{
|
||||
blockstore::{make_slot_entries, Blockstore},
|
||||
entry::create_ticks,
|
||||
|
@@ -1,333 +0,0 @@
|
||||
use super::broadcast_utils::ReceiveResults;
|
||||
use super::*;
|
||||
use log::*;
|
||||
use solana_ledger::entry::{create_ticks, Entry, EntrySlice};
|
||||
use solana_ledger::shred::Shredder;
|
||||
use solana_runtime::blockhash_queue::BlockhashQueue;
|
||||
use solana_sdk::clock::Slot;
|
||||
use solana_sdk::fee_calculator::FeeCalculator;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use solana_sdk::transaction::Transaction;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::Mutex;
|
||||
|
||||
// Queue which facilitates delivering shreds with a delay
|
||||
type DelayedQueue = VecDeque<(Option<Pubkey>, Option<Vec<Shred>>)>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(super) struct BroadcastDuplicatesRun {
|
||||
config: BroadcastDuplicatesConfig,
|
||||
// Local queue for broadcast to track which duplicate blockhashes we've sent
|
||||
duplicate_queue: BlockhashQueue,
|
||||
// Shared queue between broadcast and transmit threads
|
||||
delayed_queue: Arc<Mutex<DelayedQueue>>,
|
||||
// Buffer for duplicate entries
|
||||
duplicate_entries_buffer: Vec<Entry>,
|
||||
last_duplicate_entry_hash: Hash,
|
||||
last_broadcast_slot: Slot,
|
||||
next_shred_index: u32,
|
||||
shred_version: u16,
|
||||
keypair: Arc<Keypair>,
|
||||
}
|
||||
|
||||
impl BroadcastDuplicatesRun {
|
||||
pub(super) fn new(
|
||||
keypair: Arc<Keypair>,
|
||||
shred_version: u16,
|
||||
config: BroadcastDuplicatesConfig,
|
||||
) -> Self {
|
||||
let mut delayed_queue = DelayedQueue::new();
|
||||
delayed_queue.resize(config.duplicate_send_delay, (None, None));
|
||||
Self {
|
||||
config,
|
||||
delayed_queue: Arc::new(Mutex::new(delayed_queue)),
|
||||
duplicate_queue: BlockhashQueue::default(),
|
||||
duplicate_entries_buffer: vec![],
|
||||
next_shred_index: u32::MAX,
|
||||
last_broadcast_slot: 0,
|
||||
last_duplicate_entry_hash: Hash::default(),
|
||||
shred_version,
|
||||
keypair,
|
||||
}
|
||||
}
|
||||
|
||||
fn queue_or_create_duplicate_entries(
|
||||
&mut self,
|
||||
bank: &Arc<Bank>,
|
||||
receive_results: &ReceiveResults,
|
||||
) -> (Vec<Entry>, u32) {
|
||||
// If the last entry hash is default, grab the last blockhash from the parent bank
|
||||
if self.last_duplicate_entry_hash == Hash::default() {
|
||||
self.last_duplicate_entry_hash = bank.last_blockhash();
|
||||
}
|
||||
|
||||
// Create duplicate entries by..
|
||||
// 1) rearranging real entries so that all transaction entries are moved to
|
||||
// the front and tick entries are moved to the back.
|
||||
// 2) setting all transaction entries to zero hashes and all tick entries to `hashes_per_tick`.
|
||||
// 3) removing any transactions which reference blockhashes which aren't in the
|
||||
// duplicate blockhash queue.
|
||||
let (duplicate_entries, next_shred_index) = if bank.slot() > MINIMUM_DUPLICATE_SLOT {
|
||||
let mut tx_entries: Vec<Entry> = receive_results
|
||||
.entries
|
||||
.iter()
|
||||
.filter_map(|entry| {
|
||||
if entry.is_tick() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let transactions: Vec<Transaction> = entry
|
||||
.transactions
|
||||
.iter()
|
||||
.filter(|tx| {
|
||||
self.duplicate_queue
|
||||
.get_hash_age(&tx.message.recent_blockhash)
|
||||
.is_some()
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
if !transactions.is_empty() {
|
||||
Some(Entry::new_mut(
|
||||
&mut self.last_duplicate_entry_hash,
|
||||
&mut 0,
|
||||
transactions,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let mut tick_entries = create_ticks(
|
||||
receive_results.entries.tick_count(),
|
||||
bank.hashes_per_tick().unwrap_or_default(),
|
||||
self.last_duplicate_entry_hash,
|
||||
);
|
||||
self.duplicate_entries_buffer.append(&mut tx_entries);
|
||||
self.duplicate_entries_buffer.append(&mut tick_entries);
|
||||
|
||||
// Only send out duplicate entries when the block is finished otherwise the
|
||||
// recipient will start repairing for shreds they haven't received yet and
|
||||
// hit duplicate slot issues before we want them to.
|
||||
let entries = if receive_results.last_tick_height == bank.max_tick_height() {
|
||||
self.duplicate_entries_buffer.drain(..).collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
// Set next shred index to 0 since we are sending the full slot
|
||||
(entries, 0)
|
||||
} else {
|
||||
// Send real entries until we hit min duplicate slot
|
||||
(receive_results.entries.clone(), self.next_shred_index)
|
||||
};
|
||||
|
||||
// Save last duplicate entry hash to avoid invalid entry hash errors
|
||||
if let Some(last_duplicate_entry) = duplicate_entries.last() {
|
||||
self.last_duplicate_entry_hash = last_duplicate_entry.hash;
|
||||
}
|
||||
|
||||
(duplicate_entries, next_shred_index)
|
||||
}
|
||||
}
|
||||
|
||||
/// Duplicate slots should only be sent once all validators have started.
|
||||
/// This constant is intended to be used as a buffer so that all validators
|
||||
/// are live before sending duplicate slots.
|
||||
pub const MINIMUM_DUPLICATE_SLOT: Slot = 20;
|
||||
|
||||
impl BroadcastRun for BroadcastDuplicatesRun {
|
||||
fn run(
|
||||
&mut self,
|
||||
blockstore: &Arc<Blockstore>,
|
||||
receiver: &Receiver<WorkingBankEntry>,
|
||||
socket_sender: &Sender<(TransmitShreds, Option<BroadcastShredBatchInfo>)>,
|
||||
blockstore_sender: &Sender<(Arc<Vec<Shred>>, Option<BroadcastShredBatchInfo>)>,
|
||||
) -> Result<()> {
|
||||
// 1) Pull entries from banking stage
|
||||
let receive_results = broadcast_utils::recv_slot_entries(receiver)?;
|
||||
let bank = receive_results.bank.clone();
|
||||
let last_tick_height = receive_results.last_tick_height;
|
||||
|
||||
if self.next_shred_index == u32::MAX {
|
||||
self.next_shred_index = blockstore
|
||||
.meta(bank.slot())
|
||||
.expect("Database error")
|
||||
.map(|meta| meta.consumed)
|
||||
.unwrap_or(0) as u32
|
||||
}
|
||||
|
||||
// We were not the leader, but just became leader again
|
||||
if bank.slot() > self.last_broadcast_slot + 1 {
|
||||
self.last_duplicate_entry_hash = Hash::default();
|
||||
}
|
||||
self.last_broadcast_slot = bank.slot();
|
||||
|
||||
let shredder = Shredder::new(
|
||||
bank.slot(),
|
||||
bank.parent().unwrap().slot(),
|
||||
self.keypair.clone(),
|
||||
(bank.tick_height() % bank.ticks_per_slot()) as u8,
|
||||
self.shred_version,
|
||||
)
|
||||
.expect("Expected to create a new shredder");
|
||||
|
||||
let (data_shreds, coding_shreds, last_shred_index) = shredder.entries_to_shreds(
|
||||
&receive_results.entries,
|
||||
last_tick_height == bank.max_tick_height(),
|
||||
self.next_shred_index,
|
||||
);
|
||||
|
||||
let (duplicate_entries, next_duplicate_shred_index) =
|
||||
self.queue_or_create_duplicate_entries(&bank, &receive_results);
|
||||
let (duplicate_data_shreds, duplicate_coding_shreds, _) = if !duplicate_entries.is_empty() {
|
||||
shredder.entries_to_shreds(
|
||||
&duplicate_entries,
|
||||
last_tick_height == bank.max_tick_height(),
|
||||
next_duplicate_shred_index,
|
||||
)
|
||||
} else {
|
||||
(vec![], vec![], 0)
|
||||
};
|
||||
|
||||
// Manually track the shred index because relying on slot meta consumed is racy
|
||||
if last_tick_height == bank.max_tick_height() {
|
||||
self.next_shred_index = 0;
|
||||
self.duplicate_queue
|
||||
.register_hash(&self.last_duplicate_entry_hash, &FeeCalculator::default());
|
||||
} else {
|
||||
self.next_shred_index = last_shred_index;
|
||||
}
|
||||
|
||||
// Partition network with duplicate and real shreds based on stake
|
||||
let bank_epoch = bank.get_leader_schedule_epoch(bank.slot());
|
||||
let mut duplicate_recipients = HashMap::new();
|
||||
let mut real_recipients = HashMap::new();
|
||||
|
||||
let mut stakes: Vec<(Pubkey, u64)> = bank
|
||||
.epoch_staked_nodes(bank_epoch)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.filter(|(pubkey, _)| *pubkey != self.keypair.pubkey())
|
||||
.collect();
|
||||
stakes.sort_by(|(l_key, l_stake), (r_key, r_stake)| {
|
||||
if r_stake == l_stake {
|
||||
l_key.cmp(&r_key)
|
||||
} else {
|
||||
r_stake.cmp(&l_stake)
|
||||
}
|
||||
});
|
||||
|
||||
let highest_staked_node = stakes.first().cloned().map(|x| x.0);
|
||||
let stake_total: u64 = stakes.iter().map(|(_, stake)| *stake).sum();
|
||||
let mut cumulative_stake: u64 = 0;
|
||||
for (pubkey, stake) in stakes.into_iter().rev() {
|
||||
cumulative_stake += stake;
|
||||
if (100 * cumulative_stake / stake_total) as u8 <= self.config.stake_partition {
|
||||
duplicate_recipients.insert(pubkey, stake);
|
||||
} else {
|
||||
real_recipients.insert(pubkey, stake);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(highest_staked_node) = highest_staked_node {
|
||||
if bank.slot() > MINIMUM_DUPLICATE_SLOT && last_tick_height == bank.max_tick_height() {
|
||||
warn!(
|
||||
"{} sent duplicate slot {} to nodes: {:?}",
|
||||
self.keypair.pubkey(),
|
||||
bank.slot(),
|
||||
&duplicate_recipients,
|
||||
);
|
||||
warn!(
|
||||
"Duplicate shreds for slot {} will be broadcast in {} slot(s)",
|
||||
bank.slot(),
|
||||
self.config.duplicate_send_delay
|
||||
);
|
||||
|
||||
let delayed_shreds: Option<Vec<Shred>> = vec![
|
||||
duplicate_data_shreds.last().cloned(),
|
||||
data_shreds.last().cloned(),
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
self.delayed_queue
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push_back((Some(highest_staked_node), delayed_shreds));
|
||||
}
|
||||
}
|
||||
|
||||
let duplicate_recipients = Arc::new(duplicate_recipients);
|
||||
let real_recipients = Arc::new(real_recipients);
|
||||
|
||||
let data_shreds = Arc::new(data_shreds);
|
||||
blockstore_sender.send((data_shreds.clone(), None))?;
|
||||
|
||||
// 3) Start broadcast step
|
||||
socket_sender.send((
|
||||
(
|
||||
Some(duplicate_recipients.clone()),
|
||||
Arc::new(duplicate_data_shreds),
|
||||
),
|
||||
None,
|
||||
))?;
|
||||
socket_sender.send((
|
||||
(
|
||||
Some(duplicate_recipients),
|
||||
Arc::new(duplicate_coding_shreds),
|
||||
),
|
||||
None,
|
||||
))?;
|
||||
socket_sender.send(((Some(real_recipients.clone()), data_shreds), None))?;
|
||||
socket_sender.send(((Some(real_recipients), Arc::new(coding_shreds)), None))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn transmit(
|
||||
&mut self,
|
||||
receiver: &Arc<Mutex<TransmitReceiver>>,
|
||||
cluster_info: &ClusterInfo,
|
||||
sock: &UdpSocket,
|
||||
) -> Result<()> {
|
||||
// Check the delay queue for shreds that are ready to be sent
|
||||
let (delayed_recipient, delayed_shreds) = {
|
||||
let mut delayed_deque = self.delayed_queue.lock().unwrap();
|
||||
if delayed_deque.len() > self.config.duplicate_send_delay {
|
||||
delayed_deque.pop_front().unwrap()
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
};
|
||||
|
||||
let ((stakes, shreds), _) = receiver.lock().unwrap().recv()?;
|
||||
let stakes = stakes.unwrap();
|
||||
for peer in cluster_info.tvu_peers() {
|
||||
// Forward shreds to circumvent gossip
|
||||
if stakes.get(&peer.id).is_some() {
|
||||
shreds.iter().for_each(|shred| {
|
||||
sock.send_to(&shred.payload, &peer.tvu_forwards).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
// After a delay, broadcast duplicate shreds to a single node
|
||||
if let Some(shreds) = delayed_shreds.as_ref() {
|
||||
if Some(peer.id) == delayed_recipient {
|
||||
shreds.iter().for_each(|shred| {
|
||||
sock.send_to(&shred.payload, &peer.tvu).unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn record(
|
||||
&mut self,
|
||||
receiver: &Arc<Mutex<RecordReceiver>>,
|
||||
blockstore: &Arc<Blockstore>,
|
||||
) -> Result<()> {
|
||||
let (data_shreds, _) = receiver.lock().unwrap().recv()?;
|
||||
blockstore.insert_shreds(data_shreds.to_vec(), None, true)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
@@ -138,7 +138,7 @@ impl BroadcastRun for BroadcastFakeShredsRun {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use solana_gossip::contact_info::ContactInfo;
|
||||
use crate::contact_info::ContactInfo;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
|
||||
#[test]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
use crate::poh_recorder::WorkingBankEntry;
|
||||
use crate::result::Result;
|
||||
use solana_ledger::{entry::Entry, shred::Shred};
|
||||
use solana_poh::poh_recorder::WorkingBankEntry;
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_sdk::clock::Slot;
|
||||
use std::{
|
||||
|
@@ -494,7 +494,7 @@ impl BroadcastRun for StandardBroadcastRun {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use solana_gossip::cluster_info::{ClusterInfo, Node};
|
||||
use crate::cluster_info::{ClusterInfo, Node};
|
||||
use solana_ledger::genesis_utils::create_genesis_config;
|
||||
use solana_ledger::{
|
||||
blockstore::Blockstore, entry::create_ticks, get_tmp_ledger_path,
|
||||
|
@@ -1,74 +0,0 @@
|
||||
pub use solana_ledger::blockstore_processor::CacheBlockMetaSender;
|
||||
use {
|
||||
crossbeam_channel::{Receiver, RecvTimeoutError},
|
||||
solana_ledger::blockstore::Blockstore,
|
||||
solana_measure::measure::Measure,
|
||||
solana_runtime::bank::Bank,
|
||||
std::{
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
},
|
||||
thread::{self, Builder, JoinHandle},
|
||||
time::Duration,
|
||||
},
|
||||
};
|
||||
|
||||
pub type CacheBlockMetaReceiver = Receiver<Arc<Bank>>;
|
||||
|
||||
pub struct CacheBlockMetaService {
|
||||
thread_hdl: JoinHandle<()>,
|
||||
}
|
||||
|
||||
const CACHE_BLOCK_TIME_WARNING_MS: u64 = 150;
|
||||
|
||||
impl CacheBlockMetaService {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(
|
||||
cache_block_meta_receiver: CacheBlockMetaReceiver,
|
||||
blockstore: Arc<Blockstore>,
|
||||
exit: &Arc<AtomicBool>,
|
||||
) -> Self {
|
||||
let exit = exit.clone();
|
||||
let thread_hdl = Builder::new()
|
||||
.name("solana-cache-block-time".to_string())
|
||||
.spawn(move || loop {
|
||||
if exit.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
let recv_result = cache_block_meta_receiver.recv_timeout(Duration::from_secs(1));
|
||||
match recv_result {
|
||||
Err(RecvTimeoutError::Disconnected) => {
|
||||
break;
|
||||
}
|
||||
Ok(bank) => {
|
||||
let mut cache_block_meta_timer = Measure::start("cache_block_meta_timer");
|
||||
Self::cache_block_meta(bank, &blockstore);
|
||||
cache_block_meta_timer.stop();
|
||||
if cache_block_meta_timer.as_ms() > CACHE_BLOCK_TIME_WARNING_MS {
|
||||
warn!(
|
||||
"cache_block_meta operation took: {}ms",
|
||||
cache_block_meta_timer.as_ms()
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
Self { thread_hdl }
|
||||
}
|
||||
|
||||
fn cache_block_meta(bank: Arc<Bank>, blockstore: &Arc<Blockstore>) {
|
||||
if let Err(e) = blockstore.cache_block_time(bank.slot(), bank.clock().unix_timestamp) {
|
||||
error!("cache_block_time failed: slot {:?} {:?}", bank.slot(), e);
|
||||
}
|
||||
if let Err(e) = blockstore.cache_block_height(bank.slot(), bank.block_height()) {
|
||||
error!("cache_block_height failed: slot {:?} {:?}", bank.slot(), e);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) -> thread::Result<()> {
|
||||
self.thread_hdl.join()
|
||||
}
|
||||
}
|
69
core/src/cache_block_time_service.rs
Normal file
69
core/src/cache_block_time_service.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use crossbeam_channel::{Receiver, RecvTimeoutError, Sender};
|
||||
use solana_ledger::blockstore::Blockstore;
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_runtime::bank::Bank;
|
||||
use std::{
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
},
|
||||
thread::{self, Builder, JoinHandle},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
pub type CacheBlockTimeReceiver = Receiver<Arc<Bank>>;
|
||||
pub type CacheBlockTimeSender = Sender<Arc<Bank>>;
|
||||
|
||||
pub struct CacheBlockTimeService {
|
||||
thread_hdl: JoinHandle<()>,
|
||||
}
|
||||
|
||||
const CACHE_BLOCK_TIME_WARNING_MS: u64 = 150;
|
||||
|
||||
impl CacheBlockTimeService {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(
|
||||
cache_block_time_receiver: CacheBlockTimeReceiver,
|
||||
blockstore: Arc<Blockstore>,
|
||||
exit: &Arc<AtomicBool>,
|
||||
) -> Self {
|
||||
let exit = exit.clone();
|
||||
let thread_hdl = Builder::new()
|
||||
.name("solana-cache-block-time".to_string())
|
||||
.spawn(move || loop {
|
||||
if exit.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
let recv_result = cache_block_time_receiver.recv_timeout(Duration::from_secs(1));
|
||||
match recv_result {
|
||||
Err(RecvTimeoutError::Disconnected) => {
|
||||
break;
|
||||
}
|
||||
Ok(bank) => {
|
||||
let mut cache_block_time_timer = Measure::start("cache_block_time_timer");
|
||||
Self::cache_block_time(bank, &blockstore);
|
||||
cache_block_time_timer.stop();
|
||||
if cache_block_time_timer.as_ms() > CACHE_BLOCK_TIME_WARNING_MS {
|
||||
warn!(
|
||||
"cache_block_time operation took: {}ms",
|
||||
cache_block_time_timer.as_ms()
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
Self { thread_hdl }
|
||||
}
|
||||
|
||||
fn cache_block_time(bank: Arc<Bank>, blockstore: &Arc<Blockstore>) {
|
||||
if let Err(e) = blockstore.cache_block_time(bank.slot(), bank.clock().unix_timestamp) {
|
||||
error!("cache_block_time failed: slot {:?} {:?}", bank.slot(), e);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) -> thread::Result<()> {
|
||||
self.thread_hdl.join()
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,11 @@
|
||||
use {
|
||||
crate::crds_gossip::CrdsGossip,
|
||||
solana_measure::measure::Measure,
|
||||
solana_sdk::pubkey::Pubkey,
|
||||
std::{
|
||||
collections::HashMap,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
RwLock,
|
||||
},
|
||||
time::Instant,
|
||||
use crate::crds_gossip::CrdsGossip;
|
||||
use solana_measure::measure::Measure;
|
||||
use std::{
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
RwLock,
|
||||
},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -118,24 +114,17 @@ pub(crate) struct GossipStats {
|
||||
pub(crate) trim_crds_table_failed: Counter,
|
||||
pub(crate) trim_crds_table_purged_values_count: Counter,
|
||||
pub(crate) tvu_peers: Counter,
|
||||
pub(crate) verify_gossip_packets_time: Counter,
|
||||
}
|
||||
|
||||
pub(crate) fn submit_gossip_stats(
|
||||
stats: &GossipStats,
|
||||
gossip: &RwLock<CrdsGossip>,
|
||||
stakes: &HashMap<Pubkey, u64>,
|
||||
) {
|
||||
let (table_size, num_nodes, purged_values_size, failed_inserts_size) = {
|
||||
pub(crate) fn submit_gossip_stats(stats: &GossipStats, gossip: &RwLock<CrdsGossip>) {
|
||||
let (table_size, purged_values_size, failed_inserts_size) = {
|
||||
let gossip = gossip.read().unwrap();
|
||||
(
|
||||
gossip.crds.len(),
|
||||
gossip.crds.num_nodes(),
|
||||
gossip.crds.num_purged(),
|
||||
gossip.pull.purged_values.len(),
|
||||
gossip.pull.failed_inserts.len(),
|
||||
)
|
||||
};
|
||||
let num_nodes_staked = stakes.values().filter(|stake| **stake > 0).count();
|
||||
datapoint_info!(
|
||||
"cluster_info_stats",
|
||||
("entrypoint", stats.entrypoint.clear(), i64),
|
||||
@@ -153,8 +142,6 @@ pub(crate) fn submit_gossip_stats(
|
||||
("table_size", table_size as i64, i64),
|
||||
("purged_values_size", purged_values_size as i64, i64),
|
||||
("failed_inserts_size", failed_inserts_size as i64, i64),
|
||||
("num_nodes", num_nodes as i64, i64),
|
||||
("num_nodes_staked", num_nodes_staked as i64, i64),
|
||||
);
|
||||
datapoint_info!(
|
||||
"cluster_info_stats2",
|
||||
@@ -172,11 +159,6 @@ pub(crate) fn submit_gossip_stats(
|
||||
stats.process_gossip_packets_time.clear(),
|
||||
i64
|
||||
),
|
||||
(
|
||||
"verify_gossip_packets_time",
|
||||
stats.verify_gossip_packets_time.clear(),
|
||||
i64
|
||||
),
|
||||
(
|
||||
"handle_batch_ping_messages_time",
|
||||
stats.handle_batch_ping_messages_time.clear(),
|
@@ -1,7 +1,12 @@
|
||||
use crate::{
|
||||
cluster_info::{ClusterInfo, GOSSIP_SLEEP_MILLIS},
|
||||
crds_value::CrdsValueLabel,
|
||||
optimistic_confirmation_verifier::OptimisticConfirmationVerifier,
|
||||
optimistically_confirmed_bank_tracker::{BankNotification, BankNotificationSender},
|
||||
poh_recorder::PohRecorder,
|
||||
replay_stage::DUPLICATE_THRESHOLD,
|
||||
result::{Error, Result},
|
||||
rpc_subscriptions::RpcSubscriptions,
|
||||
sigverify,
|
||||
verified_vote_packets::VerifiedVotePackets,
|
||||
vote_stake_tracker::VoteStakeTracker,
|
||||
@@ -11,19 +16,9 @@ use crossbeam_channel::{
|
||||
};
|
||||
use itertools::izip;
|
||||
use log::*;
|
||||
use solana_gossip::{
|
||||
cluster_info::{ClusterInfo, GOSSIP_SLEEP_MILLIS},
|
||||
crds::Cursor,
|
||||
crds_value::CrdsValueLabel,
|
||||
};
|
||||
use solana_ledger::blockstore::Blockstore;
|
||||
use solana_metrics::inc_new_counter_debug;
|
||||
use solana_perf::packet::{self, Packets};
|
||||
use solana_poh::poh_recorder::PohRecorder;
|
||||
use solana_rpc::{
|
||||
optimistically_confirmed_bank_tracker::{BankNotification, BankNotificationSender},
|
||||
rpc_subscriptions::RpcSubscriptions,
|
||||
};
|
||||
use solana_runtime::{
|
||||
bank::Bank,
|
||||
bank_forks::BankForks,
|
||||
@@ -33,7 +28,7 @@ use solana_runtime::{
|
||||
vote_sender_types::{ReplayVoteReceiver, ReplayedVote},
|
||||
};
|
||||
use solana_sdk::{
|
||||
clock::{Epoch, Slot, DEFAULT_MS_PER_SLOT, DEFAULT_TICKS_PER_SLOT},
|
||||
clock::{Epoch, Slot, DEFAULT_MS_PER_SLOT},
|
||||
epoch_schedule::EpochSchedule,
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
@@ -331,18 +326,23 @@ impl ClusterInfoVoteListener {
|
||||
verified_vote_label_packets_sender: VerifiedLabelVotePacketsSender,
|
||||
verified_vote_transactions_sender: VerifiedVoteTransactionsSender,
|
||||
) -> Result<()> {
|
||||
let mut cursor = Cursor::default();
|
||||
while !exit.load(Ordering::Relaxed) {
|
||||
let (labels, votes) = cluster_info.get_votes(&mut cursor);
|
||||
let mut last_ts = 0;
|
||||
loop {
|
||||
if exit.load(Ordering::Relaxed) {
|
||||
return Ok(());
|
||||
}
|
||||
let (labels, votes, new_ts) = cluster_info.get_votes(last_ts);
|
||||
inc_new_counter_debug!("cluster_info_vote_listener-recv_count", votes.len());
|
||||
|
||||
last_ts = new_ts;
|
||||
if !votes.is_empty() {
|
||||
let (vote_txs, packets) = Self::verify_votes(votes, labels);
|
||||
verified_vote_transactions_sender.send(vote_txs)?;
|
||||
verified_vote_label_packets_sender.send(packets)?;
|
||||
}
|
||||
|
||||
sleep(Duration::from_millis(GOSSIP_SLEEP_MILLIS));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
@@ -384,14 +384,9 @@ impl ClusterInfoVoteListener {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let would_be_leader = poh_recorder
|
||||
.lock()
|
||||
.unwrap()
|
||||
.would_be_leader(20 * DEFAULT_TICKS_PER_SLOT);
|
||||
if let Err(e) = verified_vote_packets.receive_and_process_vote_packets(
|
||||
&verified_vote_label_packets_receiver,
|
||||
&mut update_version,
|
||||
would_be_leader,
|
||||
) {
|
||||
match e {
|
||||
Error::CrossbeamRecvTimeoutError(RecvTimeoutError::Disconnected) => {
|
||||
@@ -833,8 +828,8 @@ impl ClusterInfoVoteListener {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::optimistically_confirmed_bank_tracker::OptimisticallyConfirmedBank;
|
||||
use solana_perf::packet;
|
||||
use solana_rpc::optimistically_confirmed_bank_tracker::OptimisticallyConfirmedBank;
|
||||
use solana_runtime::{
|
||||
bank::Bank,
|
||||
commitment::BlockCommitmentCache,
|
||||
|
@@ -3,9 +3,8 @@ use crate::{
|
||||
progress_map::ProgressMap,
|
||||
};
|
||||
use solana_sdk::{clock::Slot, hash::Hash};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
|
||||
pub(crate) type DuplicateSlotsTracker = BTreeSet<Slot>;
|
||||
pub(crate) type GossipDuplicateConfirmedSlots = BTreeMap<Slot, Hash>;
|
||||
type SlotStateHandler = fn(Slot, &Hash, Option<&Hash>, bool, bool) -> Vec<ResultingStateChange>;
|
||||
|
||||
@@ -201,12 +200,19 @@ fn get_cluster_duplicate_confirmed_hash<'a>(
|
||||
|
||||
fn apply_state_changes(
|
||||
slot: Slot,
|
||||
progress: &mut ProgressMap,
|
||||
fork_choice: &mut HeaviestSubtreeForkChoice,
|
||||
ancestors: &HashMap<Slot, HashSet<Slot>>,
|
||||
descendants: &HashMap<Slot, HashSet<Slot>>,
|
||||
state_changes: Vec<ResultingStateChange>,
|
||||
) {
|
||||
for state_change in state_changes {
|
||||
match state_change {
|
||||
ResultingStateChange::MarkSlotDuplicate(bank_frozen_hash) => {
|
||||
progress.set_unconfirmed_duplicate_slot(
|
||||
slot,
|
||||
descendants.get(&slot).unwrap_or(&HashSet::default()),
|
||||
);
|
||||
fork_choice.mark_fork_invalid_candidate(&(slot, bank_frozen_hash));
|
||||
}
|
||||
ResultingStateChange::RepairDuplicateConfirmedVersion(
|
||||
@@ -217,20 +223,25 @@ fn apply_state_changes(
|
||||
repair_correct_version(slot, &cluster_duplicate_confirmed_hash);
|
||||
}
|
||||
ResultingStateChange::DuplicateConfirmedSlotMatchesCluster(bank_frozen_hash) => {
|
||||
progress.set_confirmed_duplicate_slot(
|
||||
slot,
|
||||
ancestors.get(&slot).unwrap_or(&HashSet::default()),
|
||||
descendants.get(&slot).unwrap_or(&HashSet::default()),
|
||||
);
|
||||
fork_choice.mark_fork_valid_candidate(&(slot, bank_frozen_hash));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn check_slot_agrees_with_cluster(
|
||||
slot: Slot,
|
||||
root: Slot,
|
||||
frozen_hash: Option<Hash>,
|
||||
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
||||
gossip_duplicate_confirmed_slots: &GossipDuplicateConfirmedSlots,
|
||||
progress: &ProgressMap,
|
||||
ancestors: &HashMap<Slot, HashSet<Slot>>,
|
||||
descendants: &HashMap<Slot, HashSet<Slot>>,
|
||||
progress: &mut ProgressMap,
|
||||
fork_choice: &mut HeaviestSubtreeForkChoice,
|
||||
slot_state_update: SlotStateUpdate,
|
||||
) {
|
||||
@@ -247,15 +258,6 @@ pub(crate) fn check_slot_agrees_with_cluster(
|
||||
return;
|
||||
}
|
||||
|
||||
// Needs to happen before the frozen_hash.is_none() check below to account for duplicate
|
||||
// signals arriving before the bank is constructed in replay.
|
||||
if matches!(slot_state_update, SlotStateUpdate::Duplicate) {
|
||||
// If this slot has already been processed before, return
|
||||
if !duplicate_slots_tracker.insert(slot) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if frozen_hash.is_none() {
|
||||
// If the bank doesn't even exist in BankForks yet,
|
||||
// then there's nothing to do as replay of the slot
|
||||
@@ -266,18 +268,25 @@ pub(crate) fn check_slot_agrees_with_cluster(
|
||||
let frozen_hash = frozen_hash.unwrap();
|
||||
let gossip_duplicate_confirmed_hash = gossip_duplicate_confirmed_slots.get(&slot);
|
||||
|
||||
// If the bank hasn't been frozen yet, then we haven't duplicate confirmed a local version
|
||||
// this slot through replay yet.
|
||||
let is_local_replay_duplicate_confirmed = fork_choice
|
||||
.is_duplicate_confirmed(&(slot, frozen_hash))
|
||||
.unwrap_or(false);
|
||||
let is_local_replay_duplicate_confirmed = progress.is_duplicate_confirmed(slot).expect("If the frozen hash exists, then the slot must exist in bank forks and thus in progress map");
|
||||
let cluster_duplicate_confirmed_hash = get_cluster_duplicate_confirmed_hash(
|
||||
slot,
|
||||
gossip_duplicate_confirmed_hash,
|
||||
&frozen_hash,
|
||||
is_local_replay_duplicate_confirmed,
|
||||
);
|
||||
let is_slot_duplicate = duplicate_slots_tracker.contains(&slot);
|
||||
let mut is_slot_duplicate =
|
||||
progress.is_unconfirmed_duplicate(slot).expect("If the frozen hash exists, then the slot must exist in bank forks and thus in progress map");
|
||||
if matches!(slot_state_update, SlotStateUpdate::Duplicate) {
|
||||
if is_slot_duplicate {
|
||||
// Already processed duplicate signal for this slot, no need to continue
|
||||
return;
|
||||
} else {
|
||||
// Otherwise, mark the slot as duplicate so the appropriate state changes
|
||||
// will trigger
|
||||
is_slot_duplicate = true;
|
||||
}
|
||||
}
|
||||
let is_dead = progress.is_dead(slot).expect("If the frozen hash exists, then the slot must exist in bank forks and thus in progress map");
|
||||
|
||||
info!(
|
||||
@@ -300,7 +309,14 @@ pub(crate) fn check_slot_agrees_with_cluster(
|
||||
is_slot_duplicate,
|
||||
is_dead,
|
||||
);
|
||||
apply_state_changes(slot, fork_choice, state_changes);
|
||||
apply_state_changes(
|
||||
slot,
|
||||
progress,
|
||||
fork_choice,
|
||||
ancestors,
|
||||
descendants,
|
||||
state_changes,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -308,16 +324,15 @@ mod test {
|
||||
use super::*;
|
||||
use crate::consensus::test::VoteSimulator;
|
||||
use solana_runtime::bank_forks::BankForks;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::RwLock,
|
||||
};
|
||||
use std::sync::RwLock;
|
||||
use trees::tr;
|
||||
|
||||
struct InitialState {
|
||||
heaviest_subtree_fork_choice: HeaviestSubtreeForkChoice,
|
||||
progress: ProgressMap,
|
||||
ancestors: HashMap<Slot, HashSet<Slot>>,
|
||||
descendants: HashMap<Slot, HashSet<Slot>>,
|
||||
slot: Slot,
|
||||
bank_forks: RwLock<BankForks>,
|
||||
}
|
||||
|
||||
@@ -326,6 +341,7 @@ mod test {
|
||||
let forks = tr(0) / (tr(1) / (tr(2) / tr(3)));
|
||||
let mut vote_simulator = VoteSimulator::new(1);
|
||||
vote_simulator.fill_bank_forks(forks, &HashMap::new());
|
||||
let ancestors = vote_simulator.bank_forks.read().unwrap().ancestors();
|
||||
|
||||
let descendants = vote_simulator
|
||||
.bank_forks
|
||||
@@ -337,7 +353,9 @@ mod test {
|
||||
InitialState {
|
||||
heaviest_subtree_fork_choice: vote_simulator.heaviest_subtree_fork_choice,
|
||||
progress: vote_simulator.progress,
|
||||
ancestors,
|
||||
descendants,
|
||||
slot: 0,
|
||||
bank_forks: vote_simulator.bank_forks,
|
||||
}
|
||||
}
|
||||
@@ -608,159 +626,75 @@ mod test {
|
||||
// Common state
|
||||
let InitialState {
|
||||
mut heaviest_subtree_fork_choice,
|
||||
mut progress,
|
||||
ancestors,
|
||||
descendants,
|
||||
slot,
|
||||
bank_forks,
|
||||
..
|
||||
} = setup();
|
||||
|
||||
// MarkSlotDuplicate should mark progress map and remove
|
||||
// the slot from fork choice
|
||||
let duplicate_slot = bank_forks.read().unwrap().root() + 1;
|
||||
let duplicate_slot_hash = bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(duplicate_slot)
|
||||
.unwrap()
|
||||
.hash();
|
||||
let slot_hash = bank_forks.read().unwrap().get(slot).unwrap().hash();
|
||||
apply_state_changes(
|
||||
duplicate_slot,
|
||||
slot,
|
||||
&mut progress,
|
||||
&mut heaviest_subtree_fork_choice,
|
||||
vec![ResultingStateChange::MarkSlotDuplicate(duplicate_slot_hash)],
|
||||
&ancestors,
|
||||
&descendants,
|
||||
vec![ResultingStateChange::MarkSlotDuplicate(slot_hash)],
|
||||
);
|
||||
assert!(!heaviest_subtree_fork_choice
|
||||
.is_candidate(&(duplicate_slot, duplicate_slot_hash))
|
||||
.is_candidate_slot(&(slot, slot_hash))
|
||||
.unwrap());
|
||||
for child_slot in descendants
|
||||
.get(&duplicate_slot)
|
||||
.get(&slot)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.chain(std::iter::once(&duplicate_slot))
|
||||
.chain(std::iter::once(&slot))
|
||||
{
|
||||
assert_eq!(
|
||||
heaviest_subtree_fork_choice
|
||||
.latest_invalid_ancestor(&(
|
||||
*child_slot,
|
||||
bank_forks.read().unwrap().get(*child_slot).unwrap().hash()
|
||||
))
|
||||
progress
|
||||
.latest_unconfirmed_duplicate_ancestor(*child_slot)
|
||||
.unwrap(),
|
||||
duplicate_slot
|
||||
slot
|
||||
);
|
||||
}
|
||||
|
||||
// DuplicateConfirmedSlotMatchesCluster should re-enable fork choice
|
||||
apply_state_changes(
|
||||
duplicate_slot,
|
||||
slot,
|
||||
&mut progress,
|
||||
&mut heaviest_subtree_fork_choice,
|
||||
&ancestors,
|
||||
&descendants,
|
||||
vec![ResultingStateChange::DuplicateConfirmedSlotMatchesCluster(
|
||||
duplicate_slot_hash,
|
||||
slot_hash,
|
||||
)],
|
||||
);
|
||||
for child_slot in descendants
|
||||
.get(&duplicate_slot)
|
||||
.get(&slot)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.chain(std::iter::once(&duplicate_slot))
|
||||
.chain(std::iter::once(&slot))
|
||||
{
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.latest_invalid_ancestor(&(
|
||||
*child_slot,
|
||||
bank_forks.read().unwrap().get(*child_slot).unwrap().hash()
|
||||
))
|
||||
assert!(progress
|
||||
.latest_unconfirmed_duplicate_ancestor(*child_slot)
|
||||
.is_none());
|
||||
}
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.is_candidate(&(duplicate_slot, duplicate_slot_hash))
|
||||
.is_candidate_slot(&(slot, slot_hash))
|
||||
.unwrap());
|
||||
}
|
||||
|
||||
fn run_test_state_duplicate_then_bank_frozen(initial_bank_hash: Option<Hash>) {
|
||||
// Common state
|
||||
let InitialState {
|
||||
mut heaviest_subtree_fork_choice,
|
||||
progress,
|
||||
bank_forks,
|
||||
..
|
||||
} = setup();
|
||||
|
||||
// Setup a duplicate slot state transition with the initial bank state of the duplicate slot
|
||||
// determined by `initial_bank_hash`, which can be:
|
||||
// 1) A default hash (unfrozen bank),
|
||||
// 2) None (a slot that hasn't even started replay yet).
|
||||
let root = 0;
|
||||
let mut duplicate_slots_tracker = DuplicateSlotsTracker::default();
|
||||
let gossip_duplicate_confirmed_slots = GossipDuplicateConfirmedSlots::default();
|
||||
let duplicate_slot = 2;
|
||||
check_slot_agrees_with_cluster(
|
||||
duplicate_slot,
|
||||
root,
|
||||
initial_bank_hash,
|
||||
&mut duplicate_slots_tracker,
|
||||
&gossip_duplicate_confirmed_slots,
|
||||
&progress,
|
||||
&mut heaviest_subtree_fork_choice,
|
||||
SlotStateUpdate::Duplicate,
|
||||
);
|
||||
assert!(duplicate_slots_tracker.contains(&duplicate_slot));
|
||||
// Nothing should be applied yet to fork choice, since bank was not yet frozen
|
||||
for slot in 2..=3 {
|
||||
let slot_hash = bank_forks.read().unwrap().get(slot).unwrap().hash();
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.latest_invalid_ancestor(&(slot, slot_hash))
|
||||
.is_none());
|
||||
}
|
||||
|
||||
// Now freeze the bank
|
||||
let frozen_duplicate_slot_hash = bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(duplicate_slot)
|
||||
.unwrap()
|
||||
.hash();
|
||||
check_slot_agrees_with_cluster(
|
||||
duplicate_slot,
|
||||
root,
|
||||
Some(frozen_duplicate_slot_hash),
|
||||
&mut duplicate_slots_tracker,
|
||||
&gossip_duplicate_confirmed_slots,
|
||||
&progress,
|
||||
&mut heaviest_subtree_fork_choice,
|
||||
SlotStateUpdate::Frozen,
|
||||
);
|
||||
|
||||
// Progress map should have the correct updates, fork choice should mark duplicate
|
||||
// as unvotable
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.is_unconfirmed_duplicate(&(duplicate_slot, frozen_duplicate_slot_hash))
|
||||
.unwrap());
|
||||
|
||||
// The ancestor of the duplicate slot should be the best slot now
|
||||
let (duplicate_ancestor, duplicate_parent_hash) = {
|
||||
let r_bank_forks = bank_forks.read().unwrap();
|
||||
let parent_bank = r_bank_forks.get(duplicate_slot).unwrap().parent().unwrap();
|
||||
(parent_bank.slot(), parent_bank.hash())
|
||||
};
|
||||
assert_eq!(
|
||||
heaviest_subtree_fork_choice.best_overall_slot(),
|
||||
(duplicate_ancestor, duplicate_parent_hash)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_state_unfrozen_bank_duplicate_then_bank_frozen() {
|
||||
run_test_state_duplicate_then_bank_frozen(Some(Hash::default()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_state_unreplayed_bank_duplicate_then_bank_frozen() {
|
||||
run_test_state_duplicate_then_bank_frozen(None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_state_ancestor_confirmed_descendant_duplicate() {
|
||||
// Common state
|
||||
let InitialState {
|
||||
mut heaviest_subtree_fork_choice,
|
||||
progress,
|
||||
mut progress,
|
||||
ancestors,
|
||||
descendants,
|
||||
bank_forks,
|
||||
..
|
||||
} = setup();
|
||||
@@ -771,7 +705,6 @@ mod test {
|
||||
(3, slot3_hash)
|
||||
);
|
||||
let root = 0;
|
||||
let mut duplicate_slots_tracker = DuplicateSlotsTracker::default();
|
||||
let mut gossip_duplicate_confirmed_slots = GossipDuplicateConfirmedSlots::default();
|
||||
|
||||
// Mark slot 2 as duplicate confirmed
|
||||
@@ -781,67 +714,36 @@ mod test {
|
||||
2,
|
||||
root,
|
||||
Some(slot2_hash),
|
||||
&mut duplicate_slots_tracker,
|
||||
&gossip_duplicate_confirmed_slots,
|
||||
&progress,
|
||||
&ancestors,
|
||||
&descendants,
|
||||
&mut progress,
|
||||
&mut heaviest_subtree_fork_choice,
|
||||
SlotStateUpdate::DuplicateConfirmed,
|
||||
);
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.is_duplicate_confirmed(&(2, slot2_hash))
|
||||
.unwrap());
|
||||
|
||||
assert_eq!(
|
||||
heaviest_subtree_fork_choice.best_overall_slot(),
|
||||
(3, slot3_hash)
|
||||
);
|
||||
for slot in 0..=2 {
|
||||
let slot_hash = bank_forks.read().unwrap().get(slot).unwrap().hash();
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.is_duplicate_confirmed(&(slot, slot_hash))
|
||||
.unwrap());
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.latest_invalid_ancestor(&(slot, slot_hash))
|
||||
.is_none());
|
||||
}
|
||||
|
||||
// Mark 3 as duplicate, should not remove the duplicate confirmed slot 2 from
|
||||
// fork choice
|
||||
// Mark 3 as duplicate, should not remove slot 2 from fork choice
|
||||
check_slot_agrees_with_cluster(
|
||||
3,
|
||||
root,
|
||||
Some(slot3_hash),
|
||||
&mut duplicate_slots_tracker,
|
||||
&gossip_duplicate_confirmed_slots,
|
||||
&progress,
|
||||
&ancestors,
|
||||
&descendants,
|
||||
&mut progress,
|
||||
&mut heaviest_subtree_fork_choice,
|
||||
SlotStateUpdate::Duplicate,
|
||||
);
|
||||
assert!(duplicate_slots_tracker.contains(&3));
|
||||
|
||||
assert_eq!(
|
||||
heaviest_subtree_fork_choice.best_overall_slot(),
|
||||
(2, slot2_hash)
|
||||
);
|
||||
for slot in 0..=3 {
|
||||
let slot_hash = bank_forks.read().unwrap().get(slot).unwrap().hash();
|
||||
if slot <= 2 {
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.is_duplicate_confirmed(&(slot, slot_hash))
|
||||
.unwrap());
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.latest_invalid_ancestor(&(slot, slot_hash))
|
||||
.is_none());
|
||||
} else {
|
||||
assert!(!heaviest_subtree_fork_choice
|
||||
.is_duplicate_confirmed(&(slot, slot_hash))
|
||||
.unwrap());
|
||||
assert_eq!(
|
||||
heaviest_subtree_fork_choice
|
||||
.latest_invalid_ancestor(&(slot, slot_hash))
|
||||
.unwrap(),
|
||||
3
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -849,7 +751,9 @@ mod test {
|
||||
// Common state
|
||||
let InitialState {
|
||||
mut heaviest_subtree_fork_choice,
|
||||
progress,
|
||||
mut progress,
|
||||
ancestors,
|
||||
descendants,
|
||||
bank_forks,
|
||||
..
|
||||
} = setup();
|
||||
@@ -860,30 +764,19 @@ mod test {
|
||||
(3, slot3_hash)
|
||||
);
|
||||
let root = 0;
|
||||
let mut duplicate_slots_tracker = DuplicateSlotsTracker::default();
|
||||
let mut gossip_duplicate_confirmed_slots = GossipDuplicateConfirmedSlots::default();
|
||||
|
||||
// Mark 2 as duplicate
|
||||
// Mark 2 as duplicate confirmed
|
||||
check_slot_agrees_with_cluster(
|
||||
2,
|
||||
root,
|
||||
Some(bank_forks.read().unwrap().get(2).unwrap().hash()),
|
||||
&mut duplicate_slots_tracker,
|
||||
&gossip_duplicate_confirmed_slots,
|
||||
&progress,
|
||||
&ancestors,
|
||||
&descendants,
|
||||
&mut progress,
|
||||
&mut heaviest_subtree_fork_choice,
|
||||
SlotStateUpdate::Duplicate,
|
||||
);
|
||||
assert!(duplicate_slots_tracker.contains(&2));
|
||||
for slot in 2..=3 {
|
||||
let slot_hash = bank_forks.read().unwrap().get(slot).unwrap().hash();
|
||||
assert_eq!(
|
||||
heaviest_subtree_fork_choice
|
||||
.latest_invalid_ancestor(&(slot, slot_hash))
|
||||
.unwrap(),
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
let slot1_hash = bank_forks.read().unwrap().get(1).unwrap().hash();
|
||||
assert_eq!(
|
||||
@@ -897,93 +790,14 @@ mod test {
|
||||
3,
|
||||
root,
|
||||
Some(slot3_hash),
|
||||
&mut duplicate_slots_tracker,
|
||||
&gossip_duplicate_confirmed_slots,
|
||||
&progress,
|
||||
&ancestors,
|
||||
&descendants,
|
||||
&mut progress,
|
||||
&mut heaviest_subtree_fork_choice,
|
||||
SlotStateUpdate::DuplicateConfirmed,
|
||||
);
|
||||
for slot in 0..=3 {
|
||||
let slot_hash = bank_forks.read().unwrap().get(slot).unwrap().hash();
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.is_duplicate_confirmed(&(slot, slot_hash))
|
||||
.unwrap());
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.latest_invalid_ancestor(&(slot, slot_hash))
|
||||
.is_none());
|
||||
}
|
||||
assert_eq!(
|
||||
heaviest_subtree_fork_choice.best_overall_slot(),
|
||||
(3, slot3_hash)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_state_descendant_confirmed_ancestor_duplicate() {
|
||||
// Common state
|
||||
let InitialState {
|
||||
mut heaviest_subtree_fork_choice,
|
||||
progress,
|
||||
bank_forks,
|
||||
..
|
||||
} = setup();
|
||||
|
||||
let slot3_hash = bank_forks.read().unwrap().get(3).unwrap().hash();
|
||||
assert_eq!(
|
||||
heaviest_subtree_fork_choice.best_overall_slot(),
|
||||
(3, slot3_hash)
|
||||
);
|
||||
let root = 0;
|
||||
let mut duplicate_slots_tracker = DuplicateSlotsTracker::default();
|
||||
let mut gossip_duplicate_confirmed_slots = GossipDuplicateConfirmedSlots::default();
|
||||
|
||||
// Mark 3 as duplicate confirmed
|
||||
gossip_duplicate_confirmed_slots.insert(3, slot3_hash);
|
||||
check_slot_agrees_with_cluster(
|
||||
3,
|
||||
root,
|
||||
Some(slot3_hash),
|
||||
&mut duplicate_slots_tracker,
|
||||
&gossip_duplicate_confirmed_slots,
|
||||
&progress,
|
||||
&mut heaviest_subtree_fork_choice,
|
||||
SlotStateUpdate::DuplicateConfirmed,
|
||||
);
|
||||
let verify_all_slots_duplicate_confirmed =
|
||||
|bank_forks: &RwLock<BankForks>,
|
||||
heaviest_subtree_fork_choice: &HeaviestSubtreeForkChoice| {
|
||||
for slot in 0..=3 {
|
||||
let slot_hash = bank_forks.read().unwrap().get(slot).unwrap().hash();
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.is_duplicate_confirmed(&(slot, slot_hash))
|
||||
.unwrap());
|
||||
assert!(heaviest_subtree_fork_choice
|
||||
.latest_invalid_ancestor(&(slot, slot_hash))
|
||||
.is_none());
|
||||
}
|
||||
};
|
||||
verify_all_slots_duplicate_confirmed(&bank_forks, &heaviest_subtree_fork_choice);
|
||||
assert_eq!(
|
||||
heaviest_subtree_fork_choice.best_overall_slot(),
|
||||
(3, slot3_hash)
|
||||
);
|
||||
|
||||
// Mark ancestor 1 as duplicate, fork choice should be unaffected since
|
||||
// slot 1 was duplicate confirmed by the confirmation on its
|
||||
// descendant, 3.
|
||||
let slot1_hash = bank_forks.read().unwrap().get(1).unwrap().hash();
|
||||
check_slot_agrees_with_cluster(
|
||||
1,
|
||||
root,
|
||||
Some(slot1_hash),
|
||||
&mut duplicate_slots_tracker,
|
||||
&gossip_duplicate_confirmed_slots,
|
||||
&progress,
|
||||
&mut heaviest_subtree_fork_choice,
|
||||
SlotStateUpdate::Duplicate,
|
||||
);
|
||||
assert!(duplicate_slots_tracker.contains(&1));
|
||||
verify_all_slots_duplicate_confirmed(&bank_forks, &heaviest_subtree_fork_choice);
|
||||
assert_eq!(
|
||||
heaviest_subtree_fork_choice.best_overall_slot(),
|
||||
(3, slot3_hash)
|
||||
|
@@ -1,13 +1,16 @@
|
||||
use crate::serve_repair::RepairType;
|
||||
use itertools::Itertools;
|
||||
use solana_gossip::{
|
||||
cluster_info::ClusterInfo, contact_info::ContactInfo, crds::Cursor, epoch_slots::EpochSlots,
|
||||
use crate::{
|
||||
cluster_info::ClusterInfo, contact_info::ContactInfo, epoch_slots::EpochSlots,
|
||||
serve_repair::RepairType,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use solana_runtime::{bank_forks::BankForks, epoch_stakes::NodeIdToVoteAccounts};
|
||||
use solana_sdk::{clock::Slot, pubkey::Pubkey};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap, HashSet},
|
||||
sync::{Arc, Mutex, RwLock},
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc, RwLock,
|
||||
},
|
||||
};
|
||||
|
||||
// Limit the size of cluster-slots map in case
|
||||
@@ -19,26 +22,22 @@ pub type SlotPubkeys = HashMap<Pubkey, u64>;
|
||||
#[derive(Default)]
|
||||
pub struct ClusterSlots {
|
||||
cluster_slots: RwLock<BTreeMap<Slot, Arc<RwLock<SlotPubkeys>>>>,
|
||||
since: AtomicU64,
|
||||
validator_stakes: RwLock<Arc<NodeIdToVoteAccounts>>,
|
||||
epoch: RwLock<Option<u64>>,
|
||||
cursor: Mutex<Cursor>,
|
||||
}
|
||||
|
||||
impl ClusterSlots {
|
||||
pub fn lookup(&self, slot: Slot) -> Option<Arc<RwLock<SlotPubkeys>>> {
|
||||
self.cluster_slots.read().unwrap().get(&slot).cloned()
|
||||
}
|
||||
|
||||
pub fn update(&self, root: Slot, cluster_info: &ClusterInfo, bank_forks: &RwLock<BankForks>) {
|
||||
self.update_peers(bank_forks);
|
||||
let epoch_slots = {
|
||||
let mut cursor = self.cursor.lock().unwrap();
|
||||
cluster_info.get_epoch_slots(&mut cursor)
|
||||
};
|
||||
self.update_internal(root, epoch_slots);
|
||||
let since = self.since.load(Ordering::Relaxed);
|
||||
let (epoch_slots, since) = cluster_info.get_epoch_slots_since(since);
|
||||
self.update_internal(root, epoch_slots, since);
|
||||
}
|
||||
|
||||
fn update_internal(&self, root: Slot, epoch_slots_list: Vec<EpochSlots>) {
|
||||
fn update_internal(&self, root: Slot, epoch_slots_list: Vec<EpochSlots>, since: Option<u64>) {
|
||||
// Attach validator's total stake.
|
||||
let epoch_slots_list: Vec<_> = {
|
||||
let validator_stakes = self.validator_stakes.read().unwrap();
|
||||
@@ -87,6 +86,9 @@ impl ClusterSlots {
|
||||
cluster_slots.split_off(&key);
|
||||
}
|
||||
}
|
||||
if let Some(since) = since {
|
||||
self.since.store(since + 1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collect(&self, id: &Pubkey) -> HashSet<Slot> {
|
||||
@@ -204,20 +206,23 @@ mod tests {
|
||||
fn test_default() {
|
||||
let cs = ClusterSlots::default();
|
||||
assert!(cs.cluster_slots.read().unwrap().is_empty());
|
||||
assert_eq!(cs.since.load(Ordering::Relaxed), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_noop() {
|
||||
let cs = ClusterSlots::default();
|
||||
cs.update_internal(0, vec![]);
|
||||
cs.update_internal(0, vec![], None);
|
||||
assert!(cs.cluster_slots.read().unwrap().is_empty());
|
||||
assert_eq!(cs.since.load(Ordering::Relaxed), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_empty() {
|
||||
let cs = ClusterSlots::default();
|
||||
let epoch_slot = EpochSlots::default();
|
||||
cs.update_internal(0, vec![epoch_slot]);
|
||||
cs.update_internal(0, vec![epoch_slot], Some(0));
|
||||
assert_eq!(cs.since.load(Ordering::Relaxed), 1);
|
||||
assert!(cs.lookup(0).is_none());
|
||||
}
|
||||
|
||||
@@ -227,7 +232,8 @@ mod tests {
|
||||
let cs = ClusterSlots::default();
|
||||
let mut epoch_slot = EpochSlots::default();
|
||||
epoch_slot.fill(&[0], 0);
|
||||
cs.update_internal(0, vec![epoch_slot]);
|
||||
cs.update_internal(0, vec![epoch_slot], Some(0));
|
||||
assert_eq!(cs.since.load(Ordering::Relaxed), 1);
|
||||
assert!(cs.lookup(0).is_none());
|
||||
}
|
||||
|
||||
@@ -236,7 +242,8 @@ mod tests {
|
||||
let cs = ClusterSlots::default();
|
||||
let mut epoch_slot = EpochSlots::default();
|
||||
epoch_slot.fill(&[1], 0);
|
||||
cs.update_internal(0, vec![epoch_slot]);
|
||||
cs.update_internal(0, vec![epoch_slot], Some(0));
|
||||
assert_eq!(cs.since.load(Ordering::Relaxed), 1);
|
||||
assert!(cs.lookup(0).is_none());
|
||||
assert!(cs.lookup(1).is_some());
|
||||
assert_eq!(
|
||||
@@ -366,7 +373,7 @@ mod tests {
|
||||
);
|
||||
|
||||
*cs.validator_stakes.write().unwrap() = map;
|
||||
cs.update_internal(0, vec![epoch_slot]);
|
||||
cs.update_internal(0, vec![epoch_slot], None);
|
||||
assert!(cs.lookup(1).is_some());
|
||||
assert_eq!(
|
||||
cs.lookup(1)
|
||||
@@ -383,7 +390,7 @@ mod tests {
|
||||
let cs = ClusterSlots::default();
|
||||
let mut epoch_slot = EpochSlots::default();
|
||||
epoch_slot.fill(&[1], 0);
|
||||
cs.update_internal(0, vec![epoch_slot]);
|
||||
cs.update_internal(0, vec![epoch_slot], None);
|
||||
let self_id = solana_sdk::pubkey::new_rand();
|
||||
assert_eq!(
|
||||
cs.generate_repairs_for_missing_slots(&self_id, 0),
|
||||
@@ -397,7 +404,7 @@ mod tests {
|
||||
let mut epoch_slot = EpochSlots::default();
|
||||
epoch_slot.fill(&[1], 0);
|
||||
let self_id = epoch_slot.from;
|
||||
cs.update_internal(0, vec![epoch_slot]);
|
||||
cs.update_internal(0, vec![epoch_slot], None);
|
||||
let slots: Vec<Slot> = cs.collect(&self_id).into_iter().collect();
|
||||
assert_eq!(slots, vec![1]);
|
||||
}
|
||||
@@ -408,7 +415,7 @@ mod tests {
|
||||
let mut epoch_slot = EpochSlots::default();
|
||||
epoch_slot.fill(&[1], 0);
|
||||
let self_id = epoch_slot.from;
|
||||
cs.update_internal(0, vec![epoch_slot]);
|
||||
cs.update_internal(0, vec![epoch_slot], None);
|
||||
assert!(cs
|
||||
.generate_repairs_for_missing_slots(&self_id, 0)
|
||||
.is_empty());
|
||||
|
@@ -1,32 +1,28 @@
|
||||
use crate::cluster_slots::ClusterSlots;
|
||||
use crossbeam_channel::{Receiver, RecvTimeoutError, Sender};
|
||||
use solana_gossip::cluster_info::ClusterInfo;
|
||||
use solana_ledger::blockstore::Blockstore;
|
||||
use crate::{cluster_info::ClusterInfo, cluster_slots::ClusterSlots};
|
||||
use solana_ledger::blockstore::{Blockstore, CompletedSlotsReceiver};
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_runtime::bank_forks::BankForks;
|
||||
use solana_sdk::{clock::Slot, pubkey::Pubkey};
|
||||
use std::{
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc::RecvTimeoutError,
|
||||
{Arc, RwLock},
|
||||
},
|
||||
thread::{self, Builder, JoinHandle},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
pub type ClusterSlotsUpdateReceiver = Receiver<Vec<Slot>>;
|
||||
pub type ClusterSlotsUpdateSender = Sender<Vec<Slot>>;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct ClusterSlotsServiceTiming {
|
||||
pub lowest_slot_elapsed: u64,
|
||||
pub process_cluster_slots_updates_elapsed: u64,
|
||||
pub update_completed_slots_elapsed: u64,
|
||||
}
|
||||
|
||||
impl ClusterSlotsServiceTiming {
|
||||
fn update(&mut self, lowest_slot_elapsed: u64, process_cluster_slots_updates_elapsed: u64) {
|
||||
fn update(&mut self, lowest_slot_elapsed: u64, update_completed_slots_elapsed: u64) {
|
||||
self.lowest_slot_elapsed += lowest_slot_elapsed;
|
||||
self.process_cluster_slots_updates_elapsed += process_cluster_slots_updates_elapsed;
|
||||
self.update_completed_slots_elapsed += update_completed_slots_elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +36,12 @@ impl ClusterSlotsService {
|
||||
cluster_slots: Arc<ClusterSlots>,
|
||||
bank_forks: Arc<RwLock<BankForks>>,
|
||||
cluster_info: Arc<ClusterInfo>,
|
||||
cluster_slots_update_receiver: ClusterSlotsUpdateReceiver,
|
||||
completed_slots_receiver: CompletedSlotsReceiver,
|
||||
exit: Arc<AtomicBool>,
|
||||
) -> Self {
|
||||
let id = cluster_info.id();
|
||||
Self::initialize_lowest_slot(id, &blockstore, &cluster_info);
|
||||
Self::initialize_epoch_slots(&bank_forks, &cluster_info);
|
||||
Self::initialize_epoch_slots(&blockstore, &cluster_info, &completed_slots_receiver);
|
||||
let t_cluster_slots_service = Builder::new()
|
||||
.name("solana-cluster-slots-service".to_string())
|
||||
.spawn(move || {
|
||||
@@ -54,7 +50,7 @@ impl ClusterSlotsService {
|
||||
cluster_slots,
|
||||
bank_forks,
|
||||
cluster_info,
|
||||
cluster_slots_update_receiver,
|
||||
completed_slots_receiver,
|
||||
exit,
|
||||
)
|
||||
})
|
||||
@@ -74,7 +70,7 @@ impl ClusterSlotsService {
|
||||
cluster_slots: Arc<ClusterSlots>,
|
||||
bank_forks: Arc<RwLock<BankForks>>,
|
||||
cluster_info: Arc<ClusterInfo>,
|
||||
cluster_slots_update_receiver: ClusterSlotsUpdateReceiver,
|
||||
completed_slots_receiver: CompletedSlotsReceiver,
|
||||
exit: Arc<AtomicBool>,
|
||||
) {
|
||||
let mut cluster_slots_service_timing = ClusterSlotsServiceTiming::default();
|
||||
@@ -83,8 +79,7 @@ impl ClusterSlotsService {
|
||||
if exit.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
let slots = match cluster_slots_update_receiver.recv_timeout(Duration::from_millis(200))
|
||||
{
|
||||
let slots = match completed_slots_receiver.recv_timeout(Duration::from_millis(200)) {
|
||||
Ok(slots) => Some(slots),
|
||||
Err(RecvTimeoutError::Timeout) => None,
|
||||
Err(RecvTimeoutError::Disconnected) => {
|
||||
@@ -98,21 +93,17 @@ impl ClusterSlotsService {
|
||||
let lowest_slot = blockstore.lowest_slot();
|
||||
Self::update_lowest_slot(&id, lowest_slot, &cluster_info);
|
||||
lowest_slot_elapsed.stop();
|
||||
let mut process_cluster_slots_updates_elapsed =
|
||||
Measure::start("process_cluster_slots_updates_elapsed");
|
||||
let mut update_completed_slots_elapsed =
|
||||
Measure::start("update_completed_slots_elapsed");
|
||||
if let Some(slots) = slots {
|
||||
Self::process_cluster_slots_updates(
|
||||
slots,
|
||||
&cluster_slots_update_receiver,
|
||||
&cluster_info,
|
||||
);
|
||||
Self::update_completed_slots(slots, &completed_slots_receiver, &cluster_info);
|
||||
}
|
||||
cluster_slots.update(new_root, &cluster_info, &bank_forks);
|
||||
process_cluster_slots_updates_elapsed.stop();
|
||||
update_completed_slots_elapsed.stop();
|
||||
|
||||
cluster_slots_service_timing.update(
|
||||
lowest_slot_elapsed.as_us(),
|
||||
process_cluster_slots_updates_elapsed.as_us(),
|
||||
update_completed_slots_elapsed.as_us(),
|
||||
);
|
||||
|
||||
if last_stats.elapsed().as_secs() > 2 {
|
||||
@@ -124,8 +115,8 @@ impl ClusterSlotsService {
|
||||
i64
|
||||
),
|
||||
(
|
||||
"process_cluster_slots_updates_elapsed",
|
||||
cluster_slots_service_timing.process_cluster_slots_updates_elapsed,
|
||||
"update_completed_slots_elapsed",
|
||||
cluster_slots_service_timing.update_completed_slots_elapsed,
|
||||
i64
|
||||
),
|
||||
);
|
||||
@@ -135,12 +126,12 @@ impl ClusterSlotsService {
|
||||
}
|
||||
}
|
||||
|
||||
fn process_cluster_slots_updates(
|
||||
fn update_completed_slots(
|
||||
mut slots: Vec<Slot>,
|
||||
cluster_slots_update_receiver: &ClusterSlotsUpdateReceiver,
|
||||
completed_slots_receiver: &CompletedSlotsReceiver,
|
||||
cluster_info: &ClusterInfo,
|
||||
) {
|
||||
while let Ok(mut more) = cluster_slots_update_receiver.try_recv() {
|
||||
while let Ok(mut more) = completed_slots_receiver.try_recv() {
|
||||
slots.append(&mut more);
|
||||
}
|
||||
#[allow(clippy::stable_sort_primitive)]
|
||||
@@ -163,16 +154,30 @@ impl ClusterSlotsService {
|
||||
cluster_info.push_lowest_slot(*id, lowest_slot);
|
||||
}
|
||||
|
||||
fn initialize_epoch_slots(bank_forks: &RwLock<BankForks>, cluster_info: &ClusterInfo) {
|
||||
// TODO: Should probably incorporate slots that were replayed on startup,
|
||||
// and maybe some that were frozen < snapshot root in case validators restart
|
||||
// from newer snapshots and lose history.
|
||||
let frozen_banks = bank_forks.read().unwrap().frozen_banks();
|
||||
let mut frozen_bank_slots: Vec<Slot> = frozen_banks.keys().cloned().collect();
|
||||
frozen_bank_slots.sort_unstable();
|
||||
fn initialize_epoch_slots(
|
||||
blockstore: &Blockstore,
|
||||
cluster_info: &ClusterInfo,
|
||||
completed_slots_receiver: &CompletedSlotsReceiver,
|
||||
) {
|
||||
let root = blockstore.last_root();
|
||||
let mut slots: Vec<_> = blockstore
|
||||
.live_slots_iterator(root)
|
||||
.filter_map(|(slot, slot_meta)| {
|
||||
if slot_meta.is_full() {
|
||||
Some(slot)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !frozen_bank_slots.is_empty() {
|
||||
cluster_info.push_epoch_slots(&frozen_bank_slots);
|
||||
while let Ok(mut more) = completed_slots_receiver.try_recv() {
|
||||
slots.append(&mut more);
|
||||
}
|
||||
slots.sort_unstable();
|
||||
slots.dedup();
|
||||
if !slots.is_empty() {
|
||||
cluster_info.push_epoch_slots(&slots);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,21 +185,19 @@ impl ClusterSlotsService {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use solana_gossip::{cluster_info::Node, crds_value::CrdsValueLabel};
|
||||
use crate::cluster_info::Node;
|
||||
|
||||
#[test]
|
||||
pub fn test_update_lowest_slot() {
|
||||
let pubkey = Pubkey::new_unique();
|
||||
let node_info = Node::new_localhost_with_pubkey(&pubkey);
|
||||
let node_info = Node::new_localhost_with_pubkey(&Pubkey::default());
|
||||
let cluster_info = ClusterInfo::new_with_invalid_keypair(node_info.info);
|
||||
ClusterSlotsService::update_lowest_slot(&pubkey, 5, &cluster_info);
|
||||
ClusterSlotsService::update_lowest_slot(&Pubkey::default(), 5, &cluster_info);
|
||||
cluster_info.flush_push_queue();
|
||||
let lowest = {
|
||||
let label = CrdsValueLabel::LowestSlot(pubkey);
|
||||
let gossip = cluster_info.gossip.read().unwrap();
|
||||
let entry = gossip.crds.get(&label).unwrap();
|
||||
entry.value.lowest_slot().unwrap().clone()
|
||||
};
|
||||
let lowest = cluster_info
|
||||
.get_lowest_slot_for_node(&Pubkey::default(), None, |lowest_slot, _| {
|
||||
lowest_slot.clone()
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(lowest.lowest, 5);
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
use crate::consensus::Stake;
|
||||
use crate::{consensus::Stake, rpc_subscriptions::RpcSubscriptions};
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_metrics::datapoint_info;
|
||||
use solana_rpc::rpc_subscriptions::RpcSubscriptions;
|
||||
use solana_runtime::{
|
||||
bank::Bank,
|
||||
commitment::{BlockCommitment, BlockCommitmentCache, CommitmentSlots, VOTE_THRESHOLD_SIZE},
|
||||
|
@@ -1,7 +1,7 @@
|
||||
use crate::{max_slots::MaxSlots, rpc_subscriptions::RpcSubscriptions};
|
||||
use crossbeam_channel::{Receiver, RecvTimeoutError, Sender};
|
||||
use solana_ledger::blockstore::{Blockstore, CompletedDataSetInfo};
|
||||
use solana_ledger::entry::Entry;
|
||||
use solana_rpc::{max_slots::MaxSlots, rpc_subscriptions::RpcSubscriptions};
|
||||
use solana_sdk::signature::Signature;
|
||||
use std::{
|
||||
sync::{
|
||||
|
@@ -1,5 +1,4 @@
|
||||
use crate::{
|
||||
heaviest_subtree_fork_choice::HeaviestSubtreeForkChoice,
|
||||
latest_validator_votes_for_frozen_banks::LatestValidatorVotesForFrozenBanks,
|
||||
progress_map::{LockoutIntervals, ProgressMap},
|
||||
};
|
||||
@@ -92,8 +91,6 @@ pub type Stake = u64;
|
||||
pub type VotedStakes = HashMap<Slot, Stake>;
|
||||
pub type PubkeyVotes = Vec<(Pubkey, Slot)>;
|
||||
|
||||
// lint warning "bank_weight is never read"
|
||||
#[allow(dead_code)]
|
||||
pub(crate) struct ComputedBankState {
|
||||
pub voted_stakes: VotedStakes,
|
||||
pub total_stake: Stake,
|
||||
@@ -267,7 +264,7 @@ impl Tower {
|
||||
};
|
||||
for vote in &vote_state.votes {
|
||||
lockout_intervals
|
||||
.entry(vote.last_locked_out_slot())
|
||||
.entry(vote.expiration_slot())
|
||||
.or_insert_with(Vec::new)
|
||||
.push((vote.slot, key));
|
||||
}
|
||||
@@ -530,31 +527,31 @@ impl Tower {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn is_locked_out(&self, slot: Slot, ancestors: &HashSet<Slot>) -> bool {
|
||||
pub fn is_locked_out(&self, slot: Slot, ancestors: &HashMap<Slot, HashSet<Slot>>) -> bool {
|
||||
assert!(ancestors.contains_key(&slot));
|
||||
|
||||
if !self.is_recent(slot) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if a slot is locked out by simulating adding a vote for that
|
||||
// slot to the current lockouts to pop any expired votes. If any of the
|
||||
// remaining voted slots are on a different fork from the checked slot,
|
||||
// it's still locked out.
|
||||
let mut lockouts = self.lockouts.clone();
|
||||
lockouts.process_slot_vote_unchecked(slot);
|
||||
for vote in &lockouts.votes {
|
||||
if slot != vote.slot && !ancestors.contains(&vote.slot) {
|
||||
if vote.slot == slot {
|
||||
continue;
|
||||
}
|
||||
if !ancestors[&slot].contains(&vote.slot) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(root_slot) = lockouts.root_slot {
|
||||
// This case should never happen because bank forks purges all
|
||||
// non-descendants of the root every time root is set
|
||||
if slot != root_slot {
|
||||
// This case should never happen because bank forks purges all
|
||||
// non-descendants of the root every time root is set
|
||||
assert!(
|
||||
ancestors.contains(&root_slot),
|
||||
ancestors[&slot].contains(&root_slot),
|
||||
"ancestors: {:?}, slot: {} root: {}",
|
||||
ancestors,
|
||||
ancestors[&slot],
|
||||
slot,
|
||||
root_slot
|
||||
);
|
||||
@@ -564,17 +561,6 @@ impl Tower {
|
||||
false
|
||||
}
|
||||
|
||||
fn is_candidate_slot_descendant_of_last_vote(
|
||||
candidate_slot: Slot,
|
||||
last_voted_slot: Slot,
|
||||
ancestors: &HashMap<Slot, HashSet<u64>>,
|
||||
) -> Option<bool> {
|
||||
ancestors
|
||||
.get(&candidate_slot)
|
||||
.map(|candidate_slot_ancestors| candidate_slot_ancestors.contains(&last_voted_slot))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn make_check_switch_threshold_decision(
|
||||
&self,
|
||||
switch_slot: u64,
|
||||
@@ -583,11 +569,9 @@ impl Tower {
|
||||
progress: &ProgressMap,
|
||||
total_stake: u64,
|
||||
epoch_vote_accounts: &HashMap<Pubkey, (u64, ArcVoteAccount)>,
|
||||
latest_validator_votes_for_frozen_banks: &LatestValidatorVotesForFrozenBanks,
|
||||
heaviest_subtree_fork_choice: &HeaviestSubtreeForkChoice,
|
||||
) -> SwitchForkDecision {
|
||||
self.last_voted_slot_hash()
|
||||
.map(|(last_voted_slot, last_voted_hash)| {
|
||||
self.last_voted_slot()
|
||||
.map(|last_voted_slot| {
|
||||
let root = self.root();
|
||||
let empty_ancestors = HashSet::default();
|
||||
let empty_ancestors_due_to_minor_unsynced_ledger = || {
|
||||
@@ -676,7 +660,7 @@ impl Tower {
|
||||
if last_vote_ancestors.contains(&switch_slot) {
|
||||
if self.is_stray_last_vote() {
|
||||
return suspended_decision_due_to_major_unsynced_ledger();
|
||||
} else if let Some(latest_duplicate_ancestor) = heaviest_subtree_fork_choice.latest_invalid_ancestor(&(last_voted_slot, last_voted_hash)) {
|
||||
} else if let Some(latest_duplicate_ancestor) = progress.latest_unconfirmed_duplicate_ancestor(last_voted_slot) {
|
||||
// We're rolling back because one of the ancestors of the last vote was a duplicate. In this
|
||||
// case, it's acceptable if the switch candidate is one of ancestors of the previous vote,
|
||||
// just fail the switch check because there's no point in voting on an ancestor. ReplayStage
|
||||
@@ -718,9 +702,13 @@ impl Tower {
|
||||
// then use this bank as a representative for the fork.
|
||||
|| descendants.iter().any(|d| progress.get_fork_stats(*d).map(|stats| stats.computed).unwrap_or(false))
|
||||
|| *candidate_slot == last_voted_slot
|
||||
// Ignore if the `candidate_slot` is a descendant of the `last_voted_slot`, since we do not
|
||||
// want to count votes on the same fork.
|
||||
|| Self::is_candidate_slot_descendant_of_last_vote(*candidate_slot, last_voted_slot, ancestors).expect("exists in descendants map, so must exist in ancestors map")
|
||||
|| ancestors
|
||||
.get(&candidate_slot)
|
||||
.expect(
|
||||
"empty descendants implies this is a child, not parent of root, so must
|
||||
exist in the ancestors map",
|
||||
)
|
||||
.contains(&last_voted_slot)
|
||||
|| *candidate_slot <= root
|
||||
{
|
||||
continue;
|
||||
@@ -740,9 +728,8 @@ impl Tower {
|
||||
.unwrap()
|
||||
.fork_stats
|
||||
.lockout_intervals;
|
||||
// Find any locked out intervals for vote accounts in this bank with
|
||||
// `lockout_interval_end` >= `last_vote`, which implies they are locked out at
|
||||
// `last_vote` on another fork.
|
||||
// Find any locked out intervals in this bank with endpoint >= last_vote,
|
||||
// implies they are locked out at last_vote
|
||||
for (_lockout_interval_end, intervals_keyed_by_end) in lockout_intervals.range((Included(last_voted_slot), Unbounded)) {
|
||||
for (lockout_interval_start, vote_account_pubkey) in intervals_keyed_by_end {
|
||||
if locked_out_vote_accounts.contains(vote_account_pubkey) {
|
||||
@@ -765,66 +752,21 @@ impl Tower {
|
||||
.map(|(stake, _)| *stake)
|
||||
.unwrap_or(0);
|
||||
locked_out_stake += stake;
|
||||
if (locked_out_stake as f64 / total_stake as f64) > SWITCH_FORK_THRESHOLD {
|
||||
return SwitchForkDecision::SwitchProof(switch_proof);
|
||||
}
|
||||
locked_out_vote_accounts.insert(vote_account_pubkey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the latest votes for potentially gossip votes that haven't landed yet
|
||||
for (vote_account_pubkey, (candidate_latest_frozen_vote, _candidate_latest_frozen_vote_hash)) in latest_validator_votes_for_frozen_banks.max_gossip_frozen_votes() {
|
||||
if locked_out_vote_accounts.contains(&vote_account_pubkey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if *candidate_latest_frozen_vote > last_voted_slot
|
||||
&&
|
||||
// Because `candidate_latest_frozen_vote` is the last vote made by some validator
|
||||
// in the cluster for a frozen bank `B` observed through gossip, we may have cleared
|
||||
// that frozen bank `B` because we `set_root(root)` for a `root` on a different fork,
|
||||
// like so:
|
||||
//
|
||||
// |----------X ------candidate_latest_frozen_vote (frozen)
|
||||
// old root
|
||||
// |----------new root ----last_voted_slot
|
||||
//
|
||||
// In most cases, because `last_voted_slot` must be a descendant of `root`, then
|
||||
// if `candidate_latest_frozen_vote` is not found in the ancestors/descendants map (recall these
|
||||
// directly reflect the state of BankForks), this implies that `B` was pruned from BankForks
|
||||
// because it was on a different fork than `last_voted_slot`, and thus this vote for `candidate_latest_frozen_vote`
|
||||
// should be safe to count towards the switching proof:
|
||||
//
|
||||
// However, there is also the possibility that `last_voted_slot` is a stray, in which
|
||||
// case we cannot make this conclusion as we do not know the ancestors/descendants
|
||||
// of strays. Hence we err on the side of caution here and ignore this vote. This
|
||||
// is ok because validators voting on different unrooted forks should eventually vote
|
||||
// on some descendant of the root, at which time they can be included in switching proofs.
|
||||
!Self::is_candidate_slot_descendant_of_last_vote(
|
||||
*candidate_latest_frozen_vote, last_voted_slot, ancestors)
|
||||
.unwrap_or(true) {
|
||||
let stake = epoch_vote_accounts
|
||||
.get(vote_account_pubkey)
|
||||
.map(|(stake, _)| *stake)
|
||||
.unwrap_or(0);
|
||||
locked_out_stake += stake;
|
||||
if (locked_out_stake as f64 / total_stake as f64) > SWITCH_FORK_THRESHOLD {
|
||||
return SwitchForkDecision::SwitchProof(switch_proof);
|
||||
}
|
||||
locked_out_vote_accounts.insert(vote_account_pubkey);
|
||||
}
|
||||
if (locked_out_stake as f64 / total_stake as f64) > SWITCH_FORK_THRESHOLD {
|
||||
SwitchForkDecision::SwitchProof(switch_proof)
|
||||
} else {
|
||||
SwitchForkDecision::FailedSwitchThreshold(locked_out_stake, total_stake)
|
||||
}
|
||||
|
||||
// We have not detected sufficient lockout past the last voted slot to generate
|
||||
// a switching proof
|
||||
SwitchForkDecision::FailedSwitchThreshold(locked_out_stake, total_stake)
|
||||
})
|
||||
.unwrap_or(SwitchForkDecision::SameFork)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn check_switch_threshold(
|
||||
&mut self,
|
||||
switch_slot: u64,
|
||||
@@ -833,8 +775,6 @@ impl Tower {
|
||||
progress: &ProgressMap,
|
||||
total_stake: u64,
|
||||
epoch_vote_accounts: &HashMap<Pubkey, (u64, ArcVoteAccount)>,
|
||||
latest_validator_votes_for_frozen_banks: &LatestValidatorVotesForFrozenBanks,
|
||||
heaviest_subtree_fork_choice: &HeaviestSubtreeForkChoice,
|
||||
) -> SwitchForkDecision {
|
||||
let decision = self.make_check_switch_threshold_decision(
|
||||
switch_slot,
|
||||
@@ -843,8 +783,6 @@ impl Tower {
|
||||
progress,
|
||||
total_stake,
|
||||
epoch_vote_accounts,
|
||||
latest_validator_votes_for_frozen_banks,
|
||||
heaviest_subtree_fork_choice,
|
||||
);
|
||||
let new_check = Some((switch_slot, decision.clone()));
|
||||
if new_check != self.last_switch_threshold_check {
|
||||
@@ -1364,11 +1302,11 @@ pub mod test {
|
||||
use super::*;
|
||||
use crate::{
|
||||
cluster_info_vote_listener::VoteTracker,
|
||||
cluster_slot_state_verifier::{DuplicateSlotsTracker, GossipDuplicateConfirmedSlots},
|
||||
cluster_slot_state_verifier::GossipDuplicateConfirmedSlots,
|
||||
cluster_slots::ClusterSlots,
|
||||
fork_choice::{ForkChoice, SelectVoteAndResetForkResult},
|
||||
heaviest_subtree_fork_choice::SlotHashKey,
|
||||
progress_map::ForkProgress,
|
||||
fork_choice::SelectVoteAndResetForkResult,
|
||||
heaviest_subtree_fork_choice::{HeaviestSubtreeForkChoice, SlotHashKey},
|
||||
progress_map::{DuplicateStats, ForkProgress},
|
||||
replay_stage::{HeaviestForkFailures, ReplayStage},
|
||||
unfrozen_gossip_verified_vote_hashes::UnfrozenGossipVerifiedVoteHashes,
|
||||
};
|
||||
@@ -1382,7 +1320,7 @@ pub mod test {
|
||||
},
|
||||
};
|
||||
use solana_sdk::{
|
||||
account::{Account, AccountSharedData, ReadableAccount, WritableAccount},
|
||||
account::{Account, AccountSharedData, WritableAccount},
|
||||
clock::Slot,
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
@@ -1445,9 +1383,9 @@ pub mod test {
|
||||
|
||||
while let Some(visit) = walk.get() {
|
||||
let slot = visit.node().data;
|
||||
self.progress
|
||||
.entry(slot)
|
||||
.or_insert_with(|| ForkProgress::new(Hash::default(), None, None, 0, 0));
|
||||
self.progress.entry(slot).or_insert_with(|| {
|
||||
ForkProgress::new(Hash::default(), None, DuplicateStats::default(), None, 0, 0)
|
||||
});
|
||||
if self.bank_forks.read().unwrap().get(slot).is_some() {
|
||||
walk.forward();
|
||||
continue;
|
||||
@@ -1535,8 +1473,6 @@ pub mod test {
|
||||
&descendants,
|
||||
&self.progress,
|
||||
tower,
|
||||
&self.latest_validator_votes_for_frozen_banks,
|
||||
&self.heaviest_subtree_fork_choice,
|
||||
);
|
||||
|
||||
// Make sure this slot isn't locked out or failing threshold
|
||||
@@ -1561,7 +1497,6 @@ pub mod test {
|
||||
&AbsRequestSender::default(),
|
||||
None,
|
||||
&mut self.heaviest_subtree_fork_choice,
|
||||
&mut DuplicateSlotsTracker::default(),
|
||||
&mut GossipDuplicateConfirmedSlots::default(),
|
||||
&mut UnfrozenGossipVerifiedVoteHashes::default(),
|
||||
&mut true,
|
||||
@@ -1600,7 +1535,9 @@ pub mod test {
|
||||
) {
|
||||
self.progress
|
||||
.entry(slot)
|
||||
.or_insert_with(|| ForkProgress::new(Hash::default(), None, None, 0, 0))
|
||||
.or_insert_with(|| {
|
||||
ForkProgress::new(Hash::default(), None, DuplicateStats::default(), None, 0, 0)
|
||||
})
|
||||
.fork_stats
|
||||
.lockout_intervals
|
||||
.entry(lockout_interval.1)
|
||||
@@ -1707,7 +1644,14 @@ pub mod test {
|
||||
let mut progress = ProgressMap::default();
|
||||
progress.insert(
|
||||
0,
|
||||
ForkProgress::new(bank0.last_blockhash(), None, None, 0, 0),
|
||||
ForkProgress::new(
|
||||
bank0.last_blockhash(),
|
||||
None,
|
||||
DuplicateStats::default(),
|
||||
None,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
);
|
||||
let bank_forks = BankForks::new(bank0);
|
||||
let heaviest_subtree_fork_choice =
|
||||
@@ -1718,11 +1662,11 @@ pub mod test {
|
||||
fn gen_stakes(stake_votes: &[(u64, &[u64])]) -> Vec<(Pubkey, (u64, ArcVoteAccount))> {
|
||||
let mut stakes = vec![];
|
||||
for (lamports, votes) in stake_votes {
|
||||
let mut account = AccountSharedData::from(Account {
|
||||
let mut account = AccountSharedData {
|
||||
data: vec![0; VoteState::size_of()],
|
||||
lamports: *lamports,
|
||||
..Account::default()
|
||||
});
|
||||
..AccountSharedData::default()
|
||||
};
|
||||
let mut vote_state = VoteState::default();
|
||||
for slot in *votes {
|
||||
vote_state.process_slot_vote_unchecked(*slot);
|
||||
@@ -1842,8 +1786,7 @@ pub mod test {
|
||||
/ (tr(44)
|
||||
// Minor fork 2
|
||||
/ (tr(45) / (tr(46) / (tr(47) / (tr(48) / (tr(49) / (tr(50)))))))
|
||||
/ (tr(110)))
|
||||
/ tr(112))));
|
||||
/ (tr(110))))));
|
||||
|
||||
// Fill the BankForks according to the above fork structure
|
||||
vote_simulator.fill_bank_forks(forks, &HashMap::new());
|
||||
@@ -1866,46 +1809,21 @@ pub mod test {
|
||||
let mut tower = Tower::new_with_key(&vote_simulator.node_pubkeys[0]);
|
||||
|
||||
// Last vote is 47
|
||||
tower.record_vote(
|
||||
47,
|
||||
vote_simulator
|
||||
.bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(47)
|
||||
.unwrap()
|
||||
.hash(),
|
||||
);
|
||||
tower.record_vote(47, Hash::default());
|
||||
|
||||
// Trying to switch to an ancestor of last vote should only not panic
|
||||
// if the current vote has a duplicate ancestor
|
||||
let ancestor_of_voted_slot = 43;
|
||||
let duplicate_ancestor1 = 44;
|
||||
let duplicate_ancestor2 = 45;
|
||||
vote_simulator
|
||||
.heaviest_subtree_fork_choice
|
||||
.mark_fork_invalid_candidate(&(
|
||||
duplicate_ancestor1,
|
||||
vote_simulator
|
||||
.bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(duplicate_ancestor1)
|
||||
.unwrap()
|
||||
.hash(),
|
||||
));
|
||||
vote_simulator
|
||||
.heaviest_subtree_fork_choice
|
||||
.mark_fork_invalid_candidate(&(
|
||||
duplicate_ancestor2,
|
||||
vote_simulator
|
||||
.bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(duplicate_ancestor2)
|
||||
.unwrap()
|
||||
.hash(),
|
||||
));
|
||||
vote_simulator.progress.set_unconfirmed_duplicate_slot(
|
||||
duplicate_ancestor1,
|
||||
&descendants.get(&duplicate_ancestor1).unwrap(),
|
||||
);
|
||||
vote_simulator.progress.set_unconfirmed_duplicate_slot(
|
||||
duplicate_ancestor2,
|
||||
&descendants.get(&duplicate_ancestor2).unwrap(),
|
||||
);
|
||||
assert_eq!(
|
||||
tower.check_switch_threshold(
|
||||
ancestor_of_voted_slot,
|
||||
@@ -1914,8 +1832,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchDuplicateRollback(duplicate_ancestor2)
|
||||
);
|
||||
@@ -1928,18 +1844,11 @@ pub mod test {
|
||||
confirm_ancestors.push(duplicate_ancestor2);
|
||||
}
|
||||
for (i, duplicate_ancestor) in confirm_ancestors.into_iter().enumerate() {
|
||||
vote_simulator
|
||||
.heaviest_subtree_fork_choice
|
||||
.mark_fork_valid_candidate(&(
|
||||
duplicate_ancestor,
|
||||
vote_simulator
|
||||
.bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(duplicate_ancestor)
|
||||
.unwrap()
|
||||
.hash(),
|
||||
));
|
||||
vote_simulator.progress.set_confirmed_duplicate_slot(
|
||||
duplicate_ancestor,
|
||||
ancestors.get(&duplicate_ancestor).unwrap(),
|
||||
&descendants.get(&duplicate_ancestor).unwrap(),
|
||||
);
|
||||
let res = tower.check_switch_threshold(
|
||||
ancestor_of_voted_slot,
|
||||
&ancestors,
|
||||
@@ -1947,8 +1856,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
);
|
||||
if i == 0 {
|
||||
assert_eq!(
|
||||
@@ -1984,8 +1891,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::SameFork
|
||||
);
|
||||
@@ -1999,8 +1904,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||
);
|
||||
@@ -2016,8 +1919,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||
);
|
||||
@@ -2033,8 +1934,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||
);
|
||||
@@ -2050,8 +1949,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||
);
|
||||
@@ -2069,8 +1966,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||
);
|
||||
@@ -2086,8 +1981,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::SwitchProof(Hash::default())
|
||||
);
|
||||
@@ -2104,8 +1997,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::SwitchProof(Hash::default())
|
||||
);
|
||||
@@ -2131,115 +2022,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_switch_threshold_use_gossip_votes() {
|
||||
let num_validators = 2;
|
||||
let (bank0, mut vote_simulator, total_stake) = setup_switch_test(2);
|
||||
let ancestors = vote_simulator.bank_forks.read().unwrap().ancestors();
|
||||
let descendants = vote_simulator
|
||||
.bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.descendants()
|
||||
.clone();
|
||||
let mut tower = Tower::new_with_key(&vote_simulator.node_pubkeys[0]);
|
||||
let other_vote_account = vote_simulator.vote_pubkeys[1];
|
||||
|
||||
// Last vote is 47
|
||||
tower.record_vote(47, Hash::default());
|
||||
|
||||
// Trying to switch to another fork at 110 should fail
|
||||
assert_eq!(
|
||||
tower.check_switch_threshold(
|
||||
110,
|
||||
&ancestors,
|
||||
&descendants,
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, num_validators * 10000)
|
||||
);
|
||||
|
||||
// Adding a vote on the descendant shouldn't count toward the switch threshold
|
||||
vote_simulator.simulate_lockout_interval(50, (49, 100), &other_vote_account);
|
||||
assert_eq!(
|
||||
tower.check_switch_threshold(
|
||||
110,
|
||||
&ancestors,
|
||||
&descendants,
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||
);
|
||||
|
||||
// Adding a later vote from gossip that isn't on the same fork should count toward the
|
||||
// switch threshold
|
||||
vote_simulator
|
||||
.latest_validator_votes_for_frozen_banks
|
||||
.check_add_vote(
|
||||
other_vote_account,
|
||||
112,
|
||||
Some(
|
||||
vote_simulator
|
||||
.bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(112)
|
||||
.unwrap()
|
||||
.hash(),
|
||||
),
|
||||
false,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tower.check_switch_threshold(
|
||||
110,
|
||||
&ancestors,
|
||||
&descendants,
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::SwitchProof(Hash::default())
|
||||
);
|
||||
|
||||
// If we now set a root that causes slot 112 to be purged from BankForks, then
|
||||
// the switch proof will now fail since that validator's vote can no longer be
|
||||
// included in the switching proof
|
||||
vote_simulator.set_root(44);
|
||||
let ancestors = vote_simulator.bank_forks.read().unwrap().ancestors();
|
||||
let descendants = vote_simulator
|
||||
.bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.descendants()
|
||||
.clone();
|
||||
assert_eq!(
|
||||
tower.check_switch_threshold(
|
||||
110,
|
||||
&ancestors,
|
||||
&descendants,
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||
);
|
||||
@@ -2521,14 +2303,16 @@ pub mod test {
|
||||
#[test]
|
||||
fn test_is_locked_out_empty() {
|
||||
let tower = Tower::new_for_tests(0, 0.67);
|
||||
let ancestors = HashSet::new();
|
||||
let ancestors = vec![(0, HashSet::new())].into_iter().collect();
|
||||
assert!(!tower.is_locked_out(0, &ancestors));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_locked_out_root_slot_child_pass() {
|
||||
let mut tower = Tower::new_for_tests(0, 0.67);
|
||||
let ancestors: HashSet<Slot> = vec![0].into_iter().collect();
|
||||
let ancestors = vec![(1, vec![0].into_iter().collect())]
|
||||
.into_iter()
|
||||
.collect();
|
||||
tower.lockouts.root_slot = Some(0);
|
||||
assert!(!tower.is_locked_out(1, &ancestors));
|
||||
}
|
||||
@@ -2536,7 +2320,9 @@ pub mod test {
|
||||
#[test]
|
||||
fn test_is_locked_out_root_slot_sibling_fail() {
|
||||
let mut tower = Tower::new_for_tests(0, 0.67);
|
||||
let ancestors: HashSet<Slot> = vec![0].into_iter().collect();
|
||||
let ancestors = vec![(2, vec![0].into_iter().collect())]
|
||||
.into_iter()
|
||||
.collect();
|
||||
tower.lockouts.root_slot = Some(0);
|
||||
tower.record_vote(1, Hash::default());
|
||||
assert!(tower.is_locked_out(2, &ancestors));
|
||||
@@ -2567,7 +2353,9 @@ pub mod test {
|
||||
#[test]
|
||||
fn test_is_locked_out_double_vote() {
|
||||
let mut tower = Tower::new_for_tests(0, 0.67);
|
||||
let ancestors: HashSet<Slot> = vec![0].into_iter().collect();
|
||||
let ancestors = vec![(1, vec![0].into_iter().collect()), (0, HashSet::new())]
|
||||
.into_iter()
|
||||
.collect();
|
||||
tower.record_vote(0, Hash::default());
|
||||
tower.record_vote(1, Hash::default());
|
||||
assert!(tower.is_locked_out(0, &ancestors));
|
||||
@@ -2576,7 +2364,9 @@ pub mod test {
|
||||
#[test]
|
||||
fn test_is_locked_out_child() {
|
||||
let mut tower = Tower::new_for_tests(0, 0.67);
|
||||
let ancestors: HashSet<Slot> = vec![0].into_iter().collect();
|
||||
let ancestors = vec![(1, vec![0].into_iter().collect())]
|
||||
.into_iter()
|
||||
.collect();
|
||||
tower.record_vote(0, Hash::default());
|
||||
assert!(!tower.is_locked_out(1, &ancestors));
|
||||
}
|
||||
@@ -2584,7 +2374,13 @@ pub mod test {
|
||||
#[test]
|
||||
fn test_is_locked_out_sibling() {
|
||||
let mut tower = Tower::new_for_tests(0, 0.67);
|
||||
let ancestors: HashSet<Slot> = vec![0].into_iter().collect();
|
||||
let ancestors = vec![
|
||||
(0, HashSet::new()),
|
||||
(1, vec![0].into_iter().collect()),
|
||||
(2, vec![0].into_iter().collect()),
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
tower.record_vote(0, Hash::default());
|
||||
tower.record_vote(1, Hash::default());
|
||||
assert!(tower.is_locked_out(2, &ancestors));
|
||||
@@ -2593,7 +2389,13 @@ pub mod test {
|
||||
#[test]
|
||||
fn test_is_locked_out_last_vote_expired() {
|
||||
let mut tower = Tower::new_for_tests(0, 0.67);
|
||||
let ancestors: HashSet<Slot> = vec![0].into_iter().collect();
|
||||
let ancestors = vec![
|
||||
(0, HashSet::new()),
|
||||
(1, vec![0].into_iter().collect()),
|
||||
(4, vec![0].into_iter().collect()),
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
tower.record_vote(0, Hash::default());
|
||||
tower.record_vote(1, Hash::default());
|
||||
assert!(!tower.is_locked_out(4, &ancestors));
|
||||
@@ -2657,7 +2459,7 @@ pub mod test {
|
||||
});
|
||||
let set: HashSet<u64> = vec![0u64, 1u64].into_iter().collect();
|
||||
let ancestors: HashMap<u64, HashSet<u64>> = [(2u64, set)].iter().cloned().collect();
|
||||
Tower::update_ancestor_voted_stakes(&mut voted_stakes, 2, account.lamports(), &ancestors);
|
||||
Tower::update_ancestor_voted_stakes(&mut voted_stakes, 2, account.lamports, &ancestors);
|
||||
assert_eq!(voted_stakes[&0], 1);
|
||||
assert_eq!(voted_stakes[&1], 1);
|
||||
assert_eq!(voted_stakes[&2], 1);
|
||||
@@ -2918,8 +2720,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::SameFork
|
||||
);
|
||||
@@ -2933,8 +2733,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||
);
|
||||
@@ -2949,8 +2747,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::SwitchProof(Hash::default())
|
||||
);
|
||||
@@ -3020,8 +2816,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||
);
|
||||
@@ -3036,8 +2830,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||
);
|
||||
@@ -3052,8 +2844,6 @@ pub mod test {
|
||||
&vote_simulator.progress,
|
||||
total_stake,
|
||||
bank0.epoch_vote_accounts(0).unwrap(),
|
||||
&vote_simulator.latest_validator_votes_for_frozen_banks,
|
||||
&vote_simulator.heaviest_subtree_fork_choice,
|
||||
),
|
||||
SwitchForkDecision::SwitchProof(Hash::default())
|
||||
);
|
||||
|
@@ -1,17 +1,16 @@
|
||||
use {
|
||||
crate::crds_value::MAX_WALLCLOCK,
|
||||
solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
rpc_port,
|
||||
sanitize::{Sanitize, SanitizeError},
|
||||
signature::{Keypair, Signer},
|
||||
timing::timestamp,
|
||||
},
|
||||
std::net::{IpAddr, SocketAddr},
|
||||
};
|
||||
use crate::crds_value::MAX_WALLCLOCK;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
#[cfg(test)]
|
||||
use solana_sdk::rpc_port;
|
||||
use solana_sdk::sanitize::{Sanitize, SanitizeError};
|
||||
#[cfg(test)]
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use solana_sdk::timing::timestamp;
|
||||
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
|
||||
/// Structure representing a node on the network
|
||||
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, AbiExample, Deserialize, Serialize)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, AbiExample)]
|
||||
pub struct ContactInfo {
|
||||
pub id: Pubkey,
|
||||
/// gossip address
|
||||
@@ -49,13 +48,34 @@ impl Sanitize for ContactInfo {
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ContactInfo {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.id.cmp(&other.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for ContactInfo {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for ContactInfo {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ContactInfo {}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! socketaddr {
|
||||
($ip:expr, $port:expr) => {
|
||||
std::net::SocketAddr::from((std::net::Ipv4Addr::from($ip), $port))
|
||||
};
|
||||
($str:expr) => {{
|
||||
$str.parse::<std::net::SocketAddr>().unwrap()
|
||||
let a: std::net::SocketAddr = $str.parse().unwrap();
|
||||
a
|
||||
}};
|
||||
}
|
||||
#[macro_export]
|
||||
@@ -134,8 +154,8 @@ impl ContactInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// Used in tests
|
||||
pub fn new_with_pubkey_socketaddr(pubkey: &Pubkey, bind_addr: &SocketAddr) -> Self {
|
||||
#[cfg(test)]
|
||||
pub(crate) fn new_with_pubkey_socketaddr(pubkey: &Pubkey, bind_addr: &SocketAddr) -> Self {
|
||||
fn next_port(addr: &SocketAddr, nxt: u16) -> SocketAddr {
|
||||
let mut nxt_addr = *addr;
|
||||
nxt_addr.set_port(addr.port() + nxt);
|
||||
@@ -168,8 +188,8 @@ impl ContactInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// Used in tests
|
||||
pub fn new_with_socketaddr(bind_addr: &SocketAddr) -> Self {
|
||||
#[cfg(test)]
|
||||
pub(crate) fn new_with_socketaddr(bind_addr: &SocketAddr) -> Self {
|
||||
let keypair = Keypair::new();
|
||||
Self::new_with_pubkey_socketaddr(&keypair.pubkey(), bind_addr)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user