Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c8bad57455 | ||
|
71654c0457 | ||
|
f9d6fb48a4 | ||
|
fa9aa0a1d7 | ||
|
9758ebfc99 | ||
|
8be23a2bb2 | ||
|
4ff9a6910d | ||
|
fd192e3641 | ||
|
a8de467ef8 | ||
|
1a186beb5c | ||
|
66a21ed65e | ||
|
1a42a40492 | ||
|
5841e4d665 | ||
|
6542a04521 | ||
|
5c27009758 | ||
|
888f3522d8 |
@@ -67,7 +67,8 @@ jobs:
|
|||||||
|
|
||||||
# explorer pull request
|
# explorer pull request
|
||||||
- name: "explorer"
|
- name: "explorer"
|
||||||
if: type = pull_request
|
if: type = pull_request AND branch = master
|
||||||
|
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "node"
|
- "node"
|
||||||
@@ -86,7 +87,8 @@ jobs:
|
|||||||
|
|
||||||
# web3.js pull request
|
# web3.js pull request
|
||||||
- name: "web3.js"
|
- name: "web3.js"
|
||||||
if: type = pull_request
|
if: type = pull_request AND branch = master
|
||||||
|
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "lts/*"
|
- "lts/*"
|
||||||
|
1090
Cargo.lock
generated
1090
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@ members = [
|
|||||||
"log-analyzer",
|
"log-analyzer",
|
||||||
"merkle-tree",
|
"merkle-tree",
|
||||||
"stake-o-matic",
|
"stake-o-matic",
|
||||||
|
"storage-bigtable",
|
||||||
"streamer",
|
"streamer",
|
||||||
"measure",
|
"measure",
|
||||||
"metrics",
|
"metrics",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-account-decoder"
|
name = "solana-account-decoder"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana account decoder"
|
description = "Solana account decoder"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -13,8 +13,8 @@ bincode = "1.3.1"
|
|||||||
bs58 = "0.3.1"
|
bs58 = "0.3.1"
|
||||||
Inflector = "0.11.4"
|
Inflector = "0.11.4"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.3.0" }
|
solana-vote-program = { path = "../programs/vote", version = "1.3.1" }
|
||||||
spl-token-v1-0 = { package = "spl-token", version = "1.0.6", features = ["skip-no-mangle"] }
|
spl-token-v1-0 = { package = "spl-token", version = "1.0.6", features = ["skip-no-mangle"] }
|
||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
|
@@ -8,10 +8,12 @@ pub mod parse_nonce;
|
|||||||
pub mod parse_token;
|
pub mod parse_token;
|
||||||
pub mod parse_vote;
|
pub mod parse_vote;
|
||||||
|
|
||||||
use crate::parse_account_data::{parse_account_data, ParsedAccount};
|
use crate::parse_account_data::{parse_account_data, AccountAdditionalData, ParsedAccount};
|
||||||
use solana_sdk::{account::Account, clock::Epoch, pubkey::Pubkey};
|
use solana_sdk::{account::Account, clock::Epoch, pubkey::Pubkey};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
pub type StringAmount = String;
|
||||||
|
|
||||||
/// A duplicate representation of an Account for pretty JSON serialization
|
/// A duplicate representation of an Account for pretty JSON serialization
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@@ -44,11 +46,17 @@ pub enum UiAccountEncoding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UiAccount {
|
impl UiAccount {
|
||||||
pub fn encode(account: Account, encoding: UiAccountEncoding) -> Self {
|
pub fn encode(
|
||||||
|
account: Account,
|
||||||
|
encoding: UiAccountEncoding,
|
||||||
|
additional_data: Option<AccountAdditionalData>,
|
||||||
|
) -> Self {
|
||||||
let data = match encoding {
|
let data = match encoding {
|
||||||
UiAccountEncoding::Binary => account.data.into(),
|
UiAccountEncoding::Binary => account.data.into(),
|
||||||
UiAccountEncoding::JsonParsed => {
|
UiAccountEncoding::JsonParsed => {
|
||||||
if let Ok(parsed_data) = parse_account_data(&account.owner, &account.data) {
|
if let Ok(parsed_data) =
|
||||||
|
parse_account_data(&account.owner, &account.data, additional_data)
|
||||||
|
{
|
||||||
UiAccountData::Json(parsed_data)
|
UiAccountData::Json(parsed_data)
|
||||||
} else {
|
} else {
|
||||||
account.data.into()
|
account.data.into()
|
||||||
|
@@ -30,6 +30,9 @@ pub enum ParseAccountError {
|
|||||||
#[error("Program not parsable")]
|
#[error("Program not parsable")]
|
||||||
ProgramNotParsable,
|
ProgramNotParsable,
|
||||||
|
|
||||||
|
#[error("Additional data required to parse: {0}")]
|
||||||
|
AdditionalDataMissing(String),
|
||||||
|
|
||||||
#[error("Instruction error")]
|
#[error("Instruction error")]
|
||||||
InstructionError(#[from] InstructionError),
|
InstructionError(#[from] InstructionError),
|
||||||
|
|
||||||
@@ -52,16 +55,25 @@ pub enum ParsableAccount {
|
|||||||
Vote,
|
Vote,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct AccountAdditionalData {
|
||||||
|
pub spl_token_decimals: Option<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_account_data(
|
pub fn parse_account_data(
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
additional_data: Option<AccountAdditionalData>,
|
||||||
) -> Result<ParsedAccount, ParseAccountError> {
|
) -> Result<ParsedAccount, ParseAccountError> {
|
||||||
let program_name = PARSABLE_PROGRAM_IDS
|
let program_name = PARSABLE_PROGRAM_IDS
|
||||||
.get(program_id)
|
.get(program_id)
|
||||||
.ok_or_else(|| ParseAccountError::ProgramNotParsable)?;
|
.ok_or_else(|| ParseAccountError::ProgramNotParsable)?;
|
||||||
|
let additional_data = additional_data.unwrap_or_default();
|
||||||
let parsed_json = match program_name {
|
let parsed_json = match program_name {
|
||||||
ParsableAccount::Nonce => serde_json::to_value(parse_nonce(data)?)?,
|
ParsableAccount::Nonce => serde_json::to_value(parse_nonce(data)?)?,
|
||||||
ParsableAccount::SplToken => serde_json::to_value(parse_token(data)?)?,
|
ParsableAccount::SplToken => {
|
||||||
|
serde_json::to_value(parse_token(data, additional_data.spl_token_decimals)?)?
|
||||||
|
}
|
||||||
ParsableAccount::Vote => serde_json::to_value(parse_vote(data)?)?,
|
ParsableAccount::Vote => serde_json::to_value(parse_vote(data)?)?,
|
||||||
};
|
};
|
||||||
Ok(ParsedAccount {
|
Ok(ParsedAccount {
|
||||||
@@ -83,18 +95,19 @@ mod test {
|
|||||||
fn test_parse_account_data() {
|
fn test_parse_account_data() {
|
||||||
let other_program = Pubkey::new_rand();
|
let other_program = Pubkey::new_rand();
|
||||||
let data = vec![0; 4];
|
let data = vec![0; 4];
|
||||||
assert!(parse_account_data(&other_program, &data).is_err());
|
assert!(parse_account_data(&other_program, &data, None).is_err());
|
||||||
|
|
||||||
let vote_state = VoteState::default();
|
let vote_state = VoteState::default();
|
||||||
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
|
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
|
||||||
let versioned = VoteStateVersions::Current(Box::new(vote_state));
|
let versioned = VoteStateVersions::Current(Box::new(vote_state));
|
||||||
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
|
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
|
||||||
let parsed = parse_account_data(&solana_vote_program::id(), &vote_account_data).unwrap();
|
let parsed =
|
||||||
|
parse_account_data(&solana_vote_program::id(), &vote_account_data, None).unwrap();
|
||||||
assert_eq!(parsed.program, "vote".to_string());
|
assert_eq!(parsed.program, "vote".to_string());
|
||||||
|
|
||||||
let nonce_data = Versions::new_current(State::Initialized(Data::default()));
|
let nonce_data = Versions::new_current(State::Initialized(Data::default()));
|
||||||
let nonce_account_data = bincode::serialize(&nonce_data).unwrap();
|
let nonce_account_data = bincode::serialize(&nonce_data).unwrap();
|
||||||
let parsed = parse_account_data(&system_program::id(), &nonce_account_data).unwrap();
|
let parsed = parse_account_data(&system_program::id(), &nonce_account_data, None).unwrap();
|
||||||
assert_eq!(parsed.program, "nonce".to_string());
|
assert_eq!(parsed.program, "nonce".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
use crate::parse_account_data::{ParsableAccount, ParseAccountError};
|
use crate::{
|
||||||
|
parse_account_data::{ParsableAccount, ParseAccountError},
|
||||||
|
StringAmount,
|
||||||
|
};
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use spl_token_v1_0::{
|
use spl_token_v1_0::{
|
||||||
option::COption,
|
option::COption,
|
||||||
@@ -19,15 +22,24 @@ pub fn spl_token_v1_0_native_mint() -> Pubkey {
|
|||||||
Pubkey::from_str(&spl_token_v1_0::native_mint::id().to_string()).unwrap()
|
Pubkey::from_str(&spl_token_v1_0::native_mint::id().to_string()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_token(data: &[u8]) -> Result<TokenAccountType, ParseAccountError> {
|
pub fn parse_token(
|
||||||
|
data: &[u8],
|
||||||
|
mint_decimals: Option<u8>,
|
||||||
|
) -> Result<TokenAccountType, ParseAccountError> {
|
||||||
let mut data = data.to_vec();
|
let mut data = data.to_vec();
|
||||||
if data.len() == size_of::<Account>() {
|
if data.len() == size_of::<Account>() {
|
||||||
let account: Account = *unpack(&mut data)
|
let account: Account = *unpack(&mut data)
|
||||||
.map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?;
|
.map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?;
|
||||||
|
let decimals = mint_decimals.ok_or_else(|| {
|
||||||
|
ParseAccountError::AdditionalDataMissing(
|
||||||
|
"no mint_decimals provided to parse spl-token account".to_string(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let ui_token_amount = token_amount_to_ui_amount(account.amount, decimals);
|
||||||
Ok(TokenAccountType::Account(UiTokenAccount {
|
Ok(TokenAccountType::Account(UiTokenAccount {
|
||||||
mint: account.mint.to_string(),
|
mint: account.mint.to_string(),
|
||||||
owner: account.owner.to_string(),
|
owner: account.owner.to_string(),
|
||||||
amount: account.amount,
|
token_amount: ui_token_amount,
|
||||||
delegate: match account.delegate {
|
delegate: match account.delegate {
|
||||||
COption::Some(pubkey) => Some(pubkey.to_string()),
|
COption::Some(pubkey) => Some(pubkey.to_string()),
|
||||||
COption::None => None,
|
COption::None => None,
|
||||||
@@ -86,13 +98,31 @@ pub enum TokenAccountType {
|
|||||||
pub struct UiTokenAccount {
|
pub struct UiTokenAccount {
|
||||||
pub mint: String,
|
pub mint: String,
|
||||||
pub owner: String,
|
pub owner: String,
|
||||||
pub amount: u64,
|
pub token_amount: UiTokenAmount,
|
||||||
pub delegate: Option<String>,
|
pub delegate: Option<String>,
|
||||||
pub is_initialized: bool,
|
pub is_initialized: bool,
|
||||||
pub is_native: bool,
|
pub is_native: bool,
|
||||||
pub delegated_amount: u64,
|
pub delegated_amount: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct UiTokenAmount {
|
||||||
|
pub ui_amount: f64,
|
||||||
|
pub decimals: u8,
|
||||||
|
pub amount: StringAmount,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn token_amount_to_ui_amount(amount: u64, decimals: u8) -> UiTokenAmount {
|
||||||
|
// Use `amount_to_ui_amount()` once spl_token is bumped to a version that supports it: https://github.com/solana-labs/solana-program-library/pull/211
|
||||||
|
let amount_decimals = amount as f64 / 10_usize.pow(decimals as u32) as f64;
|
||||||
|
UiTokenAmount {
|
||||||
|
ui_amount: amount_decimals,
|
||||||
|
decimals,
|
||||||
|
amount: amount.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UiMint {
|
pub struct UiMint {
|
||||||
@@ -110,6 +140,14 @@ pub struct UiMultisig {
|
|||||||
pub signers: Vec<String>,
|
pub signers: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_token_account_mint(data: &[u8]) -> Option<Pubkey> {
|
||||||
|
if data.len() == size_of::<Account>() {
|
||||||
|
Some(Pubkey::new(&data[0..32]))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -125,12 +163,17 @@ mod test {
|
|||||||
account.owner = owner_pubkey;
|
account.owner = owner_pubkey;
|
||||||
account.amount = 42;
|
account.amount = 42;
|
||||||
account.is_initialized = true;
|
account.is_initialized = true;
|
||||||
|
assert!(parse_token(&account_data, None).is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&account_data).unwrap(),
|
parse_token(&account_data, Some(2)).unwrap(),
|
||||||
TokenAccountType::Account(UiTokenAccount {
|
TokenAccountType::Account(UiTokenAccount {
|
||||||
mint: mint_pubkey.to_string(),
|
mint: mint_pubkey.to_string(),
|
||||||
owner: owner_pubkey.to_string(),
|
owner: owner_pubkey.to_string(),
|
||||||
amount: 42,
|
token_amount: UiTokenAmount {
|
||||||
|
ui_amount: 0.42,
|
||||||
|
decimals: 2,
|
||||||
|
amount: "42".to_string()
|
||||||
|
},
|
||||||
delegate: None,
|
delegate: None,
|
||||||
is_initialized: true,
|
is_initialized: true,
|
||||||
is_native: false,
|
is_native: false,
|
||||||
@@ -144,7 +187,7 @@ mod test {
|
|||||||
mint.decimals = 3;
|
mint.decimals = 3;
|
||||||
mint.is_initialized = true;
|
mint.is_initialized = true;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&mint_data).unwrap(),
|
parse_token(&mint_data, None).unwrap(),
|
||||||
TokenAccountType::Mint(UiMint {
|
TokenAccountType::Mint(UiMint {
|
||||||
owner: Some(owner_pubkey.to_string()),
|
owner: Some(owner_pubkey.to_string()),
|
||||||
decimals: 3,
|
decimals: 3,
|
||||||
@@ -166,7 +209,7 @@ mod test {
|
|||||||
multisig.is_initialized = true;
|
multisig.is_initialized = true;
|
||||||
multisig.signers = signers;
|
multisig.signers = signers;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&multisig_data).unwrap(),
|
parse_token(&multisig_data, None).unwrap(),
|
||||||
TokenAccountType::Multisig(UiMultisig {
|
TokenAccountType::Multisig(UiMultisig {
|
||||||
num_required_signers: 2,
|
num_required_signers: 2,
|
||||||
num_valid_signers: 3,
|
num_valid_signers: 3,
|
||||||
@@ -180,6 +223,20 @@ mod test {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let bad_data = vec![0; 4];
|
let bad_data = vec![0; 4];
|
||||||
assert!(parse_token(&bad_data).is_err());
|
assert!(parse_token(&bad_data, None).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_token_account_mint() {
|
||||||
|
let mint_pubkey = SplTokenPubkey::new(&[2; 32]);
|
||||||
|
let mut account_data = [0; size_of::<Account>()];
|
||||||
|
let mut account: &mut Account = unpack_unchecked(&mut account_data).unwrap();
|
||||||
|
account.mint = mint_pubkey;
|
||||||
|
|
||||||
|
let expected_mint_pubkey = Pubkey::new(&[2; 32]);
|
||||||
|
assert_eq!(
|
||||||
|
get_token_account_mint(&account_data),
|
||||||
|
Some(expected_mint_pubkey)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-accounts-bench"
|
name = "solana-accounts-bench"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -10,10 +10,10 @@ homepage = "https://solana.com/"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
rayon = "1.3.1"
|
rayon = "1.3.1"
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-measure = { path = "../measure", version = "1.3.0" }
|
solana-measure = { path = "../measure", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
rand = "0.7.0"
|
rand = "0.7.0"
|
||||||
clap = "2.33.1"
|
clap = "2.33.1"
|
||||||
crossbeam-channel = "0.4"
|
crossbeam-channel = "0.4"
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-banking-bench"
|
name = "solana-banking-bench"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -13,16 +13,16 @@ crossbeam-channel = "0.4"
|
|||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
rand = "0.7.0"
|
rand = "0.7.0"
|
||||||
rayon = "1.3.1"
|
rayon = "1.3.1"
|
||||||
solana-core = { path = "../core", version = "1.3.0" }
|
solana-core = { path = "../core", version = "1.3.1" }
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-streamer = { path = "../streamer", version = "1.3.0" }
|
solana-streamer = { path = "../streamer", version = "1.3.1" }
|
||||||
solana-perf = { path = "../perf", version = "1.3.0" }
|
solana-perf = { path = "../perf", version = "1.3.1" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.3.0" }
|
solana-ledger = { path = "../ledger", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-measure = { path = "../measure", version = "1.3.0" }
|
solana-measure = { path = "../measure", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
@@ -167,6 +167,7 @@ fn main() {
|
|||||||
|
|
||||||
let (verified_sender, verified_receiver) = unbounded();
|
let (verified_sender, verified_receiver) = unbounded();
|
||||||
let (vote_sender, vote_receiver) = unbounded();
|
let (vote_sender, vote_receiver) = unbounded();
|
||||||
|
let (replay_vote_sender, _replay_vote_receiver) = unbounded();
|
||||||
let bank0 = Bank::new(&genesis_config);
|
let bank0 = Bank::new(&genesis_config);
|
||||||
let mut bank_forks = BankForks::new(bank0);
|
let mut bank_forks = BankForks::new(bank0);
|
||||||
let mut bank = bank_forks.working_bank();
|
let mut bank = bank_forks.working_bank();
|
||||||
@@ -224,6 +225,7 @@ fn main() {
|
|||||||
verified_receiver,
|
verified_receiver,
|
||||||
vote_receiver,
|
vote_receiver,
|
||||||
None,
|
None,
|
||||||
|
replay_vote_sender,
|
||||||
);
|
);
|
||||||
poh_recorder.lock().unwrap().set_bank(&bank);
|
poh_recorder.lock().unwrap().set_bank(&bank);
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-bench-exchange"
|
name = "solana-bench-exchange"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -18,21 +18,21 @@ rand = "0.7.0"
|
|||||||
rayon = "1.3.1"
|
rayon = "1.3.1"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
serde_yaml = "0.8.13"
|
serde_yaml = "0.8.13"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-core = { path = "../core", version = "1.3.0" }
|
solana-core = { path = "../core", version = "1.3.1" }
|
||||||
solana-genesis = { path = "../genesis", version = "1.3.0" }
|
solana-genesis = { path = "../genesis", version = "1.3.1" }
|
||||||
solana-client = { path = "../client", version = "1.3.0" }
|
solana-client = { path = "../client", version = "1.3.1" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.3.0" }
|
solana-faucet = { path = "../faucet", version = "1.3.1" }
|
||||||
solana-exchange-program = { path = "../programs/exchange", version = "1.3.0" }
|
solana-exchange-program = { path = "../programs/exchange", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.3.0" }
|
solana-metrics = { path = "../metrics", version = "1.3.1" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.3.0" }
|
solana-net-utils = { path = "../net-utils", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
solana-local-cluster = { path = "../local-cluster", version = "1.3.0" }
|
solana-local-cluster = { path = "../local-cluster", version = "1.3.1" }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
@@ -2,18 +2,18 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-bench-streamer"
|
name = "solana-bench-streamer"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33.1"
|
clap = "2.33.1"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-streamer = { path = "../streamer", version = "1.3.0" }
|
solana-streamer = { path = "../streamer", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.3.0" }
|
solana-net-utils = { path = "../net-utils", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-bench-tps"
|
name = "solana-bench-tps"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -14,23 +14,23 @@ log = "0.4.8"
|
|||||||
rayon = "1.3.1"
|
rayon = "1.3.1"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
serde_yaml = "0.8.13"
|
serde_yaml = "0.8.13"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-core = { path = "../core", version = "1.3.0" }
|
solana-core = { path = "../core", version = "1.3.1" }
|
||||||
solana-genesis = { path = "../genesis", version = "1.3.0" }
|
solana-genesis = { path = "../genesis", version = "1.3.1" }
|
||||||
solana-client = { path = "../client", version = "1.3.0" }
|
solana-client = { path = "../client", version = "1.3.1" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.3.0" }
|
solana-faucet = { path = "../faucet", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.3.0" }
|
solana-metrics = { path = "../metrics", version = "1.3.1" }
|
||||||
solana-measure = { path = "../measure", version = "1.3.0" }
|
solana-measure = { path = "../measure", version = "1.3.1" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.3.0" }
|
solana-net-utils = { path = "../net-utils", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = "0.4.0"
|
serial_test = "0.4.0"
|
||||||
serial_test_derive = "0.4.0"
|
serial_test_derive = "0.4.0"
|
||||||
solana-local-cluster = { path = "../local-cluster", version = "1.3.0" }
|
solana-local-cluster = { path = "../local-cluster", version = "1.3.1" }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
@@ -7,7 +7,7 @@ source multinode-demo/common.sh
|
|||||||
|
|
||||||
rm -rf config/run/init-completed config/ledger config/snapshot-ledger
|
rm -rf config/run/init-completed config/ledger config/snapshot-ledger
|
||||||
|
|
||||||
timeout 15 ./run.sh &
|
timeout 120 ./run.sh &
|
||||||
pid=$!
|
pid=$!
|
||||||
|
|
||||||
attempts=20
|
attempts=20
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-clap-utils"
|
name = "solana-clap-utils"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana utilities for the clap"
|
description = "Solana utilities for the clap"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -11,8 +11,8 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
rpassword = "4.0"
|
rpassword = "4.0"
|
||||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.3.0" }
|
solana-remote-wallet = { path = "../remote-wallet", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
thiserror = "1.0.20"
|
thiserror = "1.0.20"
|
||||||
tiny-bip39 = "0.7.0"
|
tiny-bip39 = "0.7.0"
|
||||||
url = "2.1.0"
|
url = "2.1.0"
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-cli-config"
|
name = "solana-cli-config"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-cli"
|
name = "solana-cli"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -27,29 +27,29 @@ reqwest = { version = "0.10.6", default-features = false, features = ["blocking"
|
|||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
solana-account-decoder = { path = "../account-decoder", version = "1.3.0" }
|
solana-account-decoder = { path = "../account-decoder", version = "1.3.1" }
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.3.0" }
|
solana-budget-program = { path = "../programs/budget", version = "1.3.1" }
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-cli-config = { path = "../cli-config", version = "1.3.0" }
|
solana-cli-config = { path = "../cli-config", version = "1.3.1" }
|
||||||
solana-client = { path = "../client", version = "1.3.0" }
|
solana-client = { path = "../client", version = "1.3.1" }
|
||||||
solana-config-program = { path = "../programs/config", version = "1.3.0" }
|
solana-config-program = { path = "../programs/config", version = "1.3.1" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.3.0" }
|
solana-faucet = { path = "../faucet", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.3.0" }
|
solana-net-utils = { path = "../net-utils", version = "1.3.1" }
|
||||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.3.0" }
|
solana-remote-wallet = { path = "../remote-wallet", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.3.0" }
|
solana-stake-program = { path = "../programs/stake", version = "1.3.1" }
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.3.0" }
|
solana-transaction-status = { path = "../transaction-status", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.3.0" }
|
solana-vote-program = { path = "../programs/vote", version = "1.3.1" }
|
||||||
solana-vote-signer = { path = "../vote-signer", version = "1.3.0" }
|
solana-vote-signer = { path = "../vote-signer", version = "1.3.1" }
|
||||||
thiserror = "1.0.20"
|
thiserror = "1.0.20"
|
||||||
url = "2.1.1"
|
url = "2.1.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
solana-core = { path = "../core", version = "1.3.0" }
|
solana-core = { path = "../core", version = "1.3.1" }
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.3.0" }
|
solana-budget-program = { path = "../programs/budget", version = "1.3.1" }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@@ -231,8 +231,8 @@ pub enum CliCommand {
|
|||||||
TotalSupply,
|
TotalSupply,
|
||||||
TransactionHistory {
|
TransactionHistory {
|
||||||
address: Pubkey,
|
address: Pubkey,
|
||||||
end_slot: Option<Slot>, // None == latest slot
|
before: Option<Signature>,
|
||||||
slot_limit: Option<u64>, // None == search full history
|
limit: usize,
|
||||||
},
|
},
|
||||||
// Nonce commands
|
// Nonce commands
|
||||||
AuthorizeNonceAccount {
|
AuthorizeNonceAccount {
|
||||||
@@ -1235,7 +1235,7 @@ fn process_show_account(
|
|||||||
let cli_account = CliAccount {
|
let cli_account = CliAccount {
|
||||||
keyed_account: RpcKeyedAccount {
|
keyed_account: RpcKeyedAccount {
|
||||||
pubkey: account_pubkey.to_string(),
|
pubkey: account_pubkey.to_string(),
|
||||||
account: UiAccount::encode(account, UiAccountEncoding::Binary),
|
account: UiAccount::encode(account, UiAccountEncoding::Binary, None),
|
||||||
},
|
},
|
||||||
use_lamports_unit,
|
use_lamports_unit,
|
||||||
};
|
};
|
||||||
@@ -1871,9 +1871,9 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||||||
CliCommand::TotalSupply => process_total_supply(&rpc_client, config),
|
CliCommand::TotalSupply => process_total_supply(&rpc_client, config),
|
||||||
CliCommand::TransactionHistory {
|
CliCommand::TransactionHistory {
|
||||||
address,
|
address,
|
||||||
end_slot,
|
before,
|
||||||
slot_limit,
|
limit,
|
||||||
} => process_transaction_history(&rpc_client, address, *end_slot, *slot_limit),
|
} => process_transaction_history(&rpc_client, config, address, *before, *limit),
|
||||||
|
|
||||||
// Nonce Commands
|
// Nonce Commands
|
||||||
|
|
||||||
|
@@ -13,7 +13,6 @@ use solana_client::{
|
|||||||
pubsub_client::{PubsubClient, SlotInfoMessage},
|
pubsub_client::{PubsubClient, SlotInfoMessage},
|
||||||
rpc_client::RpcClient,
|
rpc_client::RpcClient,
|
||||||
rpc_config::{RpcLargestAccountsConfig, RpcLargestAccountsFilter},
|
rpc_config::{RpcLargestAccountsConfig, RpcLargestAccountsFilter},
|
||||||
rpc_request::MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE,
|
|
||||||
};
|
};
|
||||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@@ -24,6 +23,7 @@ use solana_sdk::{
|
|||||||
message::Message,
|
message::Message,
|
||||||
native_token::lamports_to_sol,
|
native_token::lamports_to_sol,
|
||||||
pubkey::{self, Pubkey},
|
pubkey::{self, Pubkey},
|
||||||
|
signature::Signature,
|
||||||
system_instruction, system_program,
|
system_instruction, system_program,
|
||||||
sysvar::{
|
sysvar::{
|
||||||
self,
|
self,
|
||||||
@@ -257,9 +257,8 @@ impl ClusterQuerySubCommands for App<'_, '_> {
|
|||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("transaction-history")
|
SubCommand::with_name("transaction-history")
|
||||||
.about("Show historical transactions affecting the given address, \
|
.about("Show historical transactions affecting the given address \
|
||||||
ordered based on the slot in which they were confirmed in \
|
from newest to oldest")
|
||||||
from lowest to highest slot")
|
|
||||||
.arg(
|
.arg(
|
||||||
pubkey!(Arg::with_name("address")
|
pubkey!(Arg::with_name("address")
|
||||||
.index(1)
|
.index(1)
|
||||||
@@ -267,26 +266,22 @@ impl ClusterQuerySubCommands for App<'_, '_> {
|
|||||||
.required(true),
|
.required(true),
|
||||||
"Account address"),
|
"Account address"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name("end_slot")
|
|
||||||
.takes_value(false)
|
|
||||||
.value_name("SLOT")
|
|
||||||
.index(2)
|
|
||||||
.validator(is_slot)
|
|
||||||
.help(
|
|
||||||
"Slot to start from [default: latest slot at maximum commitment]"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("limit")
|
Arg::with_name("limit")
|
||||||
.long("limit")
|
.long("limit")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("NUMBER OF SLOTS")
|
.value_name("LIMIT")
|
||||||
.validator(is_slot)
|
.validator(is_slot)
|
||||||
.help(
|
.default_value("1000")
|
||||||
"Limit the search to this many slots"
|
.help("Maximum number of transaction signatures to return"),
|
||||||
),
|
)
|
||||||
),
|
.arg(
|
||||||
|
Arg::with_name("before")
|
||||||
|
.long("before")
|
||||||
|
.value_name("TRANSACTION_SIGNATURE")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("Start with the first signature older than this one"),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -440,14 +435,22 @@ pub fn parse_transaction_history(
|
|||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let address = pubkey_of_signer(matches, "address", wallet_manager)?.unwrap();
|
let address = pubkey_of_signer(matches, "address", wallet_manager)?.unwrap();
|
||||||
let end_slot = value_t!(matches, "end_slot", Slot).ok();
|
|
||||||
let slot_limit = value_t!(matches, "limit", u64).ok();
|
let before = match matches.value_of("before") {
|
||||||
|
Some(signature) => Some(
|
||||||
|
signature
|
||||||
|
.parse()
|
||||||
|
.map_err(|err| CliError::BadParameter(format!("Invalid signature: {}", err)))?,
|
||||||
|
),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
let limit = value_t_or_exit!(matches, "limit", usize);
|
||||||
|
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::TransactionHistory {
|
command: CliCommand::TransactionHistory {
|
||||||
address,
|
address,
|
||||||
end_slot,
|
before,
|
||||||
slot_limit,
|
limit,
|
||||||
},
|
},
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
})
|
})
|
||||||
@@ -1305,41 +1308,36 @@ pub fn process_show_validators(
|
|||||||
|
|
||||||
pub fn process_transaction_history(
|
pub fn process_transaction_history(
|
||||||
rpc_client: &RpcClient,
|
rpc_client: &RpcClient,
|
||||||
|
config: &CliConfig,
|
||||||
address: &Pubkey,
|
address: &Pubkey,
|
||||||
end_slot: Option<Slot>, // None == use latest slot
|
before: Option<Signature>,
|
||||||
slot_limit: Option<u64>,
|
limit: usize,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
let end_slot = {
|
let results = rpc_client.get_confirmed_signatures_for_address2_with_config(
|
||||||
if let Some(end_slot) = end_slot {
|
address,
|
||||||
end_slot
|
before,
|
||||||
|
Some(limit),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let transactions_found = format!("{} transactions found", results.len());
|
||||||
|
|
||||||
|
for result in results {
|
||||||
|
if config.verbose {
|
||||||
|
println!(
|
||||||
|
"{} [slot={} status={}] {}",
|
||||||
|
result.signature,
|
||||||
|
result.slot,
|
||||||
|
match result.err {
|
||||||
|
None => "Confirmed".to_string(),
|
||||||
|
Some(err) => format!("Failed: {:?}", err),
|
||||||
|
},
|
||||||
|
result.memo.unwrap_or_else(|| "".to_string()),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
rpc_client.get_slot_with_commitment(CommitmentConfig::max())?
|
println!("{}", result.signature);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
let mut start_slot = match slot_limit {
|
|
||||||
Some(slot_limit) => end_slot.saturating_sub(slot_limit),
|
|
||||||
None => rpc_client.minimum_ledger_slot()?,
|
|
||||||
};
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Transactions affecting {} within slots [{},{}]",
|
|
||||||
address, start_slot, end_slot
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut transaction_count = 0;
|
|
||||||
while start_slot < end_slot {
|
|
||||||
let signatures = rpc_client.get_confirmed_signatures_for_address(
|
|
||||||
address,
|
|
||||||
start_slot,
|
|
||||||
(start_slot + MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE).min(end_slot),
|
|
||||||
)?;
|
|
||||||
for signature in &signatures {
|
|
||||||
println!("{}", signature);
|
|
||||||
}
|
|
||||||
transaction_count += signatures.len();
|
|
||||||
start_slot += MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE;
|
|
||||||
}
|
}
|
||||||
Ok(format!("{} transactions found", transaction_count))
|
Ok(transactions_found)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@@ -350,7 +350,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let nonce_pubkey = Pubkey::new(&[4u8; 32]);
|
let nonce_pubkey = Pubkey::new(&[4u8; 32]);
|
||||||
let rpc_nonce_account = UiAccount::encode(nonce_account, UiAccountEncoding::Binary);
|
let rpc_nonce_account = UiAccount::encode(nonce_account, UiAccountEncoding::Binary, None);
|
||||||
let get_account_response = json!(Response {
|
let get_account_response = json!(Response {
|
||||||
context: RpcResponseContext { slot: 1 },
|
context: RpcResponseContext { slot: 1 },
|
||||||
value: json!(Some(rpc_nonce_account)),
|
value: json!(Some(rpc_nonce_account)),
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-client"
|
name = "solana-client"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana Client"
|
description = "Solana Client"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -19,11 +19,11 @@ reqwest = { version = "0.10.6", default-features = false, features = ["blocking"
|
|||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
solana-account-decoder = { path = "../account-decoder", version = "1.3.0" }
|
solana-account-decoder = { path = "../account-decoder", version = "1.3.1" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.3.0" }
|
solana-net-utils = { path = "../net-utils", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.3.0" }
|
solana-transaction-status = { path = "../transaction-status", version = "1.3.1" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.3.0" }
|
solana-vote-program = { path = "../programs/vote", version = "1.3.1" }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tungstenite = "0.10.1"
|
tungstenite = "0.10.1"
|
||||||
url = "2.1.1"
|
url = "2.1.1"
|
||||||
@@ -32,7 +32,7 @@ url = "2.1.1"
|
|||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
jsonrpc-core = "14.2.0"
|
jsonrpc-core = "14.2.0"
|
||||||
jsonrpc-http-server = "14.2.0"
|
jsonrpc-http-server = "14.2.0"
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
@@ -2,7 +2,10 @@ use crate::{
|
|||||||
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
|
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
|
||||||
http_sender::HttpSender,
|
http_sender::HttpSender,
|
||||||
mock_sender::{MockSender, Mocks},
|
mock_sender::{MockSender, Mocks},
|
||||||
rpc_config::{RpcLargestAccountsConfig, RpcSendTransactionConfig, RpcTokenAccountsFilter},
|
rpc_config::{
|
||||||
|
RpcGetConfirmedSignaturesForAddress2Config, RpcLargestAccountsConfig,
|
||||||
|
RpcSendTransactionConfig, RpcTokenAccountsFilter,
|
||||||
|
},
|
||||||
rpc_request::{RpcError, RpcRequest, TokenAccountsFilter},
|
rpc_request::{RpcError, RpcRequest, TokenAccountsFilter},
|
||||||
rpc_response::*,
|
rpc_response::*,
|
||||||
rpc_sender::RpcSender,
|
rpc_sender::RpcSender,
|
||||||
@@ -12,7 +15,10 @@ use indicatif::{ProgressBar, ProgressStyle};
|
|||||||
use log::*;
|
use log::*;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use solana_account_decoder::{
|
use solana_account_decoder::{
|
||||||
parse_token::{parse_token, TokenAccountType, UiMint, UiMultisig, UiTokenAccount},
|
parse_token::{
|
||||||
|
get_token_account_mint, parse_token, TokenAccountType, UiMint, UiMultisig, UiTokenAccount,
|
||||||
|
UiTokenAmount,
|
||||||
|
},
|
||||||
UiAccount,
|
UiAccount,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@@ -35,6 +41,7 @@ use solana_transaction_status::{
|
|||||||
};
|
};
|
||||||
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
thread::sleep,
|
thread::sleep,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
@@ -289,6 +296,32 @@ impl RpcClient {
|
|||||||
Ok(signatures)
|
Ok(signatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_confirmed_signatures_for_address2(
|
||||||
|
&self,
|
||||||
|
address: &Pubkey,
|
||||||
|
) -> ClientResult<Vec<RpcConfirmedTransactionStatusWithSignature>> {
|
||||||
|
self.get_confirmed_signatures_for_address2_with_config(address, None, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_confirmed_signatures_for_address2_with_config(
|
||||||
|
&self,
|
||||||
|
address: &Pubkey,
|
||||||
|
before: Option<Signature>,
|
||||||
|
limit: Option<usize>,
|
||||||
|
) -> ClientResult<Vec<RpcConfirmedTransactionStatusWithSignature>> {
|
||||||
|
let config = RpcGetConfirmedSignaturesForAddress2Config {
|
||||||
|
before: before.map(|signature| signature.to_string()),
|
||||||
|
limit,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result: Vec<RpcConfirmedTransactionStatusWithSignature> = self.send(
|
||||||
|
RpcRequest::GetConfirmedSignaturesForAddress2,
|
||||||
|
json!([address.to_string(), config]),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_confirmed_transaction(
|
pub fn get_confirmed_transaction(
|
||||||
&self,
|
&self,
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
@@ -669,14 +702,30 @@ impl RpcClient {
|
|||||||
value: account,
|
value: account,
|
||||||
} = self.get_account_with_commitment(pubkey, commitment_config)?;
|
} = self.get_account_with_commitment(pubkey, commitment_config)?;
|
||||||
|
|
||||||
|
if account.is_none() {
|
||||||
|
return Err(RpcError::ForUser(format!("AccountNotFound: pubkey={}", pubkey)).into());
|
||||||
|
}
|
||||||
|
let account = account.unwrap();
|
||||||
|
let mint = get_token_account_mint(&account.data)
|
||||||
|
.and_then(|mint_pubkey| {
|
||||||
|
self.get_token_mint_with_commitment(&mint_pubkey, commitment_config)
|
||||||
|
.ok()
|
||||||
|
.map(|response| response.value)
|
||||||
|
.flatten()
|
||||||
|
})
|
||||||
|
.ok_or_else(|| {
|
||||||
|
Into::<ClientError>::into(RpcError::ForUser(format!(
|
||||||
|
"AccountNotFound: mint for token acccount pubkey={}",
|
||||||
|
pubkey
|
||||||
|
)))
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(Response {
|
Ok(Response {
|
||||||
context,
|
context,
|
||||||
value: account
|
value: match parse_token(&account.data, Some(mint.decimals)) {
|
||||||
.map(|account| match parse_token(&account.data) {
|
Ok(TokenAccountType::Account(ui_token_account)) => Some(ui_token_account),
|
||||||
Ok(TokenAccountType::Account(ui_token_account)) => Some(ui_token_account),
|
_ => None,
|
||||||
_ => None,
|
},
|
||||||
})
|
|
||||||
.flatten(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,7 +748,7 @@ impl RpcClient {
|
|||||||
Ok(Response {
|
Ok(Response {
|
||||||
context,
|
context,
|
||||||
value: account
|
value: account
|
||||||
.map(|account| match parse_token(&account.data) {
|
.map(|account| match parse_token(&account.data, None) {
|
||||||
Ok(TokenAccountType::Mint(ui_token_mint)) => Some(ui_token_mint),
|
Ok(TokenAccountType::Mint(ui_token_mint)) => Some(ui_token_mint),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
@@ -726,7 +775,7 @@ impl RpcClient {
|
|||||||
Ok(Response {
|
Ok(Response {
|
||||||
context,
|
context,
|
||||||
value: account
|
value: account
|
||||||
.map(|account| match parse_token(&account.data) {
|
.map(|account| match parse_token(&account.data, None) {
|
||||||
Ok(TokenAccountType::Multisig(ui_token_multisig)) => Some(ui_token_multisig),
|
Ok(TokenAccountType::Multisig(ui_token_multisig)) => Some(ui_token_multisig),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
@@ -734,7 +783,7 @@ impl RpcClient {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_token_account_balance(&self, pubkey: &Pubkey) -> ClientResult<RpcTokenAmount> {
|
pub fn get_token_account_balance(&self, pubkey: &Pubkey) -> ClientResult<UiTokenAmount> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.get_token_account_balance_with_commitment(pubkey, CommitmentConfig::default())?
|
.get_token_account_balance_with_commitment(pubkey, CommitmentConfig::default())?
|
||||||
.value)
|
.value)
|
||||||
@@ -744,7 +793,7 @@ impl RpcClient {
|
|||||||
&self,
|
&self,
|
||||||
pubkey: &Pubkey,
|
pubkey: &Pubkey,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> RpcResult<RpcTokenAmount> {
|
) -> RpcResult<UiTokenAmount> {
|
||||||
self.send(
|
self.send(
|
||||||
RpcRequest::GetTokenAccountBalance,
|
RpcRequest::GetTokenAccountBalance,
|
||||||
json!([pubkey.to_string(), commitment_config]),
|
json!([pubkey.to_string(), commitment_config]),
|
||||||
@@ -788,10 +837,10 @@ impl RpcClient {
|
|||||||
commitment_config
|
commitment_config
|
||||||
]),
|
]),
|
||||||
)?;
|
)?;
|
||||||
let pubkey_accounts = accounts_to_token_accounts(parse_keyed_accounts(
|
let pubkey_accounts = self.accounts_to_token_accounts(
|
||||||
accounts,
|
commitment_config,
|
||||||
RpcRequest::GetTokenAccountsByDelegate,
|
parse_keyed_accounts(accounts, RpcRequest::GetTokenAccountsByDelegate)?,
|
||||||
)?);
|
);
|
||||||
Ok(Response {
|
Ok(Response {
|
||||||
context,
|
context,
|
||||||
value: pubkey_accounts,
|
value: pubkey_accounts,
|
||||||
@@ -831,17 +880,17 @@ impl RpcClient {
|
|||||||
RpcRequest::GetTokenAccountsByOwner,
|
RpcRequest::GetTokenAccountsByOwner,
|
||||||
json!([owner.to_string(), token_account_filter, commitment_config]),
|
json!([owner.to_string(), token_account_filter, commitment_config]),
|
||||||
)?;
|
)?;
|
||||||
let pubkey_accounts = accounts_to_token_accounts(parse_keyed_accounts(
|
let pubkey_accounts = self.accounts_to_token_accounts(
|
||||||
accounts,
|
commitment_config,
|
||||||
RpcRequest::GetTokenAccountsByDelegate,
|
parse_keyed_accounts(accounts, RpcRequest::GetTokenAccountsByDelegate)?,
|
||||||
)?);
|
);
|
||||||
Ok(Response {
|
Ok(Response {
|
||||||
context,
|
context,
|
||||||
value: pubkey_accounts,
|
value: pubkey_accounts,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_token_supply(&self, mint: &Pubkey) -> ClientResult<RpcTokenAmount> {
|
pub fn get_token_supply(&self, mint: &Pubkey) -> ClientResult<UiTokenAmount> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.get_token_supply_with_commitment(mint, CommitmentConfig::default())?
|
.get_token_supply_with_commitment(mint, CommitmentConfig::default())?
|
||||||
.value)
|
.value)
|
||||||
@@ -851,13 +900,42 @@ impl RpcClient {
|
|||||||
&self,
|
&self,
|
||||||
mint: &Pubkey,
|
mint: &Pubkey,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> RpcResult<RpcTokenAmount> {
|
) -> RpcResult<UiTokenAmount> {
|
||||||
self.send(
|
self.send(
|
||||||
RpcRequest::GetTokenSupply,
|
RpcRequest::GetTokenSupply,
|
||||||
json!([mint.to_string(), commitment_config]),
|
json!([mint.to_string(), commitment_config]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn accounts_to_token_accounts(
|
||||||
|
&self,
|
||||||
|
commitment_config: CommitmentConfig,
|
||||||
|
pubkey_accounts: Vec<(Pubkey, Account)>,
|
||||||
|
) -> Vec<(Pubkey, UiTokenAccount)> {
|
||||||
|
let mut mint_decimals: HashMap<Pubkey, u8> = HashMap::new();
|
||||||
|
pubkey_accounts
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(pubkey, account)| {
|
||||||
|
let mint_pubkey = get_token_account_mint(&account.data)?;
|
||||||
|
let decimals = mint_decimals.get(&mint_pubkey).cloned().or_else(|| {
|
||||||
|
let mint = self
|
||||||
|
.get_token_mint_with_commitment(&mint_pubkey, commitment_config)
|
||||||
|
.ok()
|
||||||
|
.map(|response| response.value)
|
||||||
|
.flatten()?;
|
||||||
|
mint_decimals.insert(mint_pubkey, mint.decimals);
|
||||||
|
Some(mint.decimals)
|
||||||
|
})?;
|
||||||
|
match parse_token(&account.data, Some(decimals)) {
|
||||||
|
Ok(TokenAccountType::Account(ui_token_account)) => {
|
||||||
|
Some((pubkey, ui_token_account))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn poll_balance_with_timeout_and_commitment(
|
fn poll_balance_with_timeout_and_commitment(
|
||||||
&self,
|
&self,
|
||||||
pubkey: &Pubkey,
|
pubkey: &Pubkey,
|
||||||
@@ -1222,18 +1300,6 @@ fn parse_keyed_accounts(
|
|||||||
Ok(pubkey_accounts)
|
Ok(pubkey_accounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accounts_to_token_accounts(
|
|
||||||
pubkey_accounts: Vec<(Pubkey, Account)>,
|
|
||||||
) -> Vec<(Pubkey, UiTokenAccount)> {
|
|
||||||
pubkey_accounts
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(pubkey, account)| match parse_token(&account.data) {
|
|
||||||
Ok(TokenAccountType::Account(ui_token_account)) => Some((pubkey, ui_token_account)),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@@ -65,3 +65,10 @@ pub enum RpcTokenAccountsFilter {
|
|||||||
Mint(String),
|
Mint(String),
|
||||||
ProgramId(String),
|
ProgramId(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RpcGetConfirmedSignaturesForAddress2Config {
|
||||||
|
pub before: Option<String>, // Signature as base-58 string
|
||||||
|
pub limit: Option<usize>,
|
||||||
|
}
|
||||||
|
@@ -14,6 +14,7 @@ pub enum RpcRequest {
|
|||||||
GetConfirmedBlock,
|
GetConfirmedBlock,
|
||||||
GetConfirmedBlocks,
|
GetConfirmedBlocks,
|
||||||
GetConfirmedSignaturesForAddress,
|
GetConfirmedSignaturesForAddress,
|
||||||
|
GetConfirmedSignaturesForAddress2,
|
||||||
GetConfirmedTransaction,
|
GetConfirmedTransaction,
|
||||||
GetEpochInfo,
|
GetEpochInfo,
|
||||||
GetEpochSchedule,
|
GetEpochSchedule,
|
||||||
@@ -65,6 +66,7 @@ impl fmt::Display for RpcRequest {
|
|||||||
RpcRequest::GetConfirmedBlock => "getConfirmedBlock",
|
RpcRequest::GetConfirmedBlock => "getConfirmedBlock",
|
||||||
RpcRequest::GetConfirmedBlocks => "getConfirmedBlocks",
|
RpcRequest::GetConfirmedBlocks => "getConfirmedBlocks",
|
||||||
RpcRequest::GetConfirmedSignaturesForAddress => "getConfirmedSignaturesForAddress",
|
RpcRequest::GetConfirmedSignaturesForAddress => "getConfirmedSignaturesForAddress",
|
||||||
|
RpcRequest::GetConfirmedSignaturesForAddress2 => "getConfirmedSignaturesForAddress2",
|
||||||
RpcRequest::GetConfirmedTransaction => "getConfirmedTransaction",
|
RpcRequest::GetConfirmedTransaction => "getConfirmedTransaction",
|
||||||
RpcRequest::GetEpochInfo => "getEpochInfo",
|
RpcRequest::GetEpochInfo => "getEpochInfo",
|
||||||
RpcRequest::GetEpochSchedule => "getEpochSchedule",
|
RpcRequest::GetEpochSchedule => "getEpochSchedule",
|
||||||
@@ -112,6 +114,7 @@ pub const NUM_LARGEST_ACCOUNTS: usize = 20;
|
|||||||
pub const MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS: usize = 256;
|
pub const MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS: usize = 256;
|
||||||
pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE: u64 = 10_000;
|
pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE: u64 = 10_000;
|
||||||
pub const MAX_GET_CONFIRMED_BLOCKS_RANGE: u64 = 500_000;
|
pub const MAX_GET_CONFIRMED_BLOCKS_RANGE: u64 = 500_000;
|
||||||
|
pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT: usize = 1_000;
|
||||||
|
|
||||||
// Validators that are this number of slots behind are considered delinquent
|
// Validators that are this number of slots behind are considered delinquent
|
||||||
pub const DELINQUENT_VALIDATOR_SLOT_DISTANCE: u64 = 128;
|
pub const DELINQUENT_VALIDATOR_SLOT_DISTANCE: u64 = 128;
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
use crate::client_error;
|
use crate::client_error;
|
||||||
use solana_account_decoder::UiAccount;
|
use solana_account_decoder::{parse_token::UiTokenAmount, UiAccount};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{Epoch, Slot},
|
clock::{Epoch, Slot},
|
||||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||||
inflation::Inflation,
|
inflation::Inflation,
|
||||||
transaction::{Result, TransactionError},
|
transaction::{Result, TransactionError},
|
||||||
};
|
};
|
||||||
|
use solana_transaction_status::ConfirmedTransactionStatusWithSignature;
|
||||||
use std::{collections::HashMap, net::SocketAddr};
|
use std::{collections::HashMap, net::SocketAddr};
|
||||||
|
|
||||||
pub type RpcResult<T> = client_error::Result<Response<T>>;
|
pub type RpcResult<T> = client_error::Result<Response<T>>;
|
||||||
pub type RpcAmount = String;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct RpcResponseContext {
|
pub struct RpcResponseContext {
|
||||||
@@ -221,18 +221,36 @@ pub struct RpcStakeActivation {
|
|||||||
pub inactive: u64,
|
pub inactive: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct RpcTokenAmount {
|
|
||||||
pub ui_amount: f64,
|
|
||||||
pub decimals: u8,
|
|
||||||
pub amount: RpcAmount,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcTokenAccountBalance {
|
pub struct RpcTokenAccountBalance {
|
||||||
pub address: String,
|
pub address: String,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub amount: RpcTokenAmount,
|
pub amount: UiTokenAmount,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RpcConfirmedTransactionStatusWithSignature {
|
||||||
|
pub signature: String,
|
||||||
|
pub slot: Slot,
|
||||||
|
pub err: Option<TransactionError>,
|
||||||
|
pub memo: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ConfirmedTransactionStatusWithSignature> for RpcConfirmedTransactionStatusWithSignature {
|
||||||
|
fn from(value: ConfirmedTransactionStatusWithSignature) -> Self {
|
||||||
|
let ConfirmedTransactionStatusWithSignature {
|
||||||
|
signature,
|
||||||
|
slot,
|
||||||
|
err,
|
||||||
|
memo,
|
||||||
|
} = value;
|
||||||
|
Self {
|
||||||
|
signature: signature.to_string(),
|
||||||
|
slot,
|
||||||
|
err,
|
||||||
|
memo,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-core"
|
name = "solana-core"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
documentation = "https://docs.rs/solana"
|
documentation = "https://docs.rs/solana"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
readme = "../README.md"
|
readme = "../README.md"
|
||||||
@@ -43,38 +43,39 @@ regex = "1.3.9"
|
|||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
solana-account-decoder = { path = "../account-decoder", version = "1.3.0" }
|
solana-account-decoder = { path = "../account-decoder", version = "1.3.1" }
|
||||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.3.0" }
|
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.3.1" }
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.3.0" }
|
solana-budget-program = { path = "../programs/budget", version = "1.3.1" }
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-client = { path = "../client", version = "1.3.0" }
|
solana-client = { path = "../client", version = "1.3.1" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.3.0" }
|
solana-faucet = { path = "../faucet", version = "1.3.1" }
|
||||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.3.0" }
|
solana-genesis-programs = { path = "../genesis-programs", version = "1.3.1" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.3.0" }
|
solana-ledger = { path = "../ledger", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.3.0" }
|
solana-merkle-tree = { path = "../merkle-tree", version = "1.3.1" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.3.0" }
|
solana-metrics = { path = "../metrics", version = "1.3.1" }
|
||||||
solana-measure = { path = "../measure", version = "1.3.0" }
|
solana-measure = { path = "../measure", version = "1.3.1" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.3.0" }
|
solana-net-utils = { path = "../net-utils", version = "1.3.1" }
|
||||||
solana-perf = { path = "../perf", version = "1.3.0" }
|
solana-perf = { path = "../perf", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-sdk-macro-frozen-abi = { path = "../sdk/macro-frozen-abi", version = "1.3.0" }
|
solana-sdk-macro-frozen-abi = { path = "../sdk/macro-frozen-abi", version = "1.3.1" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.3.0" }
|
solana-stake-program = { path = "../programs/stake", version = "1.3.1" }
|
||||||
solana-streamer = { path = "../streamer", version = "1.3.0" }
|
solana-storage-bigtable = { path = "../storage-bigtable", version = "1.3.1" }
|
||||||
solana-sys-tuner = { path = "../sys-tuner", version = "1.3.0" }
|
solana-streamer = { path = "../streamer", version = "1.3.1" }
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.3.0" }
|
solana-sys-tuner = { path = "../sys-tuner", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-transaction-status = { path = "../transaction-status", version = "1.3.1" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
solana-vote-signer = { path = "../vote-signer", version = "1.3.0" }
|
solana-vote-program = { path = "../programs/vote", version = "1.3.1" }
|
||||||
|
solana-vote-signer = { path = "../vote-signer", version = "1.3.1" }
|
||||||
spl-token-v1-0 = { package = "spl-token", version = "1.0.6", features = ["skip-no-mangle"] }
|
spl-token-v1-0 = { package = "spl-token", version = "1.0.6", features = ["skip-no-mangle"] }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tokio = "0.1"
|
tokio_01 = { version = "0.1", package = "tokio" }
|
||||||
tokio-codec = "0.1"
|
tokio_fs_01 = { version = "0.1", package = "tokio-fs" }
|
||||||
tokio-fs = "0.1"
|
tokio_io_01 = { version = "0.1", package = "tokio-io" }
|
||||||
tokio-io = "0.1"
|
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.3.1" }
|
||||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.3.0" }
|
tokio = { version = "0.2.22", features = ["full"] }
|
||||||
trees = "0.2.1"
|
trees = "0.2.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@@ -73,6 +73,7 @@ fn bench_consume_buffered(bencher: &mut Bencher) {
|
|||||||
let batch_len = batch.packets.len();
|
let batch_len = batch.packets.len();
|
||||||
packets.push((batch, vec![0usize; batch_len]));
|
packets.push((batch, vec![0usize; batch_len]));
|
||||||
}
|
}
|
||||||
|
let (s, _r) = unbounded();
|
||||||
// This tests the performance of buffering packets.
|
// This tests the performance of buffering packets.
|
||||||
// If the packet buffers are copied, performance will be poor.
|
// If the packet buffers are copied, performance will be poor.
|
||||||
bencher.iter(move || {
|
bencher.iter(move || {
|
||||||
@@ -82,6 +83,7 @@ fn bench_consume_buffered(bencher: &mut Bencher) {
|
|||||||
&mut packets,
|
&mut packets,
|
||||||
10_000,
|
10_000,
|
||||||
None,
|
None,
|
||||||
|
&s,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -190,12 +192,14 @@ fn bench_banking(bencher: &mut Bencher, tx_type: TransactionType) {
|
|||||||
create_test_recorder(&bank, &blockstore, None);
|
create_test_recorder(&bank, &blockstore, None);
|
||||||
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
||||||
let cluster_info = Arc::new(cluster_info);
|
let cluster_info = Arc::new(cluster_info);
|
||||||
|
let (s, _r) = unbounded();
|
||||||
let _banking_stage = BankingStage::new(
|
let _banking_stage = BankingStage::new(
|
||||||
&cluster_info,
|
&cluster_info,
|
||||||
&poh_recorder,
|
&poh_recorder,
|
||||||
verified_receiver,
|
verified_receiver,
|
||||||
vote_receiver,
|
vote_receiver,
|
||||||
None,
|
None,
|
||||||
|
s,
|
||||||
);
|
);
|
||||||
poh_recorder.lock().unwrap().set_bank(&bank);
|
poh_recorder.lock().unwrap().set_bank(&bank);
|
||||||
|
|
||||||
|
@@ -24,7 +24,9 @@ use solana_perf::{
|
|||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
accounts_db::ErrorCounters,
|
accounts_db::ErrorCounters,
|
||||||
bank::{Bank, TransactionBalancesSet, TransactionProcessResult},
|
bank::{Bank, TransactionBalancesSet, TransactionProcessResult},
|
||||||
|
bank_utils,
|
||||||
transaction_batch::TransactionBatch,
|
transaction_batch::TransactionBatch,
|
||||||
|
vote_sender_types::ReplayVoteSender,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{
|
clock::{
|
||||||
@@ -81,6 +83,7 @@ impl BankingStage {
|
|||||||
verified_receiver: CrossbeamReceiver<Vec<Packets>>,
|
verified_receiver: CrossbeamReceiver<Vec<Packets>>,
|
||||||
verified_vote_receiver: CrossbeamReceiver<Vec<Packets>>,
|
verified_vote_receiver: CrossbeamReceiver<Vec<Packets>>,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
gossip_vote_sender: ReplayVoteSender,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new_num_threads(
|
Self::new_num_threads(
|
||||||
cluster_info,
|
cluster_info,
|
||||||
@@ -89,6 +92,7 @@ impl BankingStage {
|
|||||||
verified_vote_receiver,
|
verified_vote_receiver,
|
||||||
Self::num_threads(),
|
Self::num_threads(),
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
|
gossip_vote_sender,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,6 +103,7 @@ impl BankingStage {
|
|||||||
verified_vote_receiver: CrossbeamReceiver<Vec<Packets>>,
|
verified_vote_receiver: CrossbeamReceiver<Vec<Packets>>,
|
||||||
num_threads: u32,
|
num_threads: u32,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
gossip_vote_sender: ReplayVoteSender,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let batch_limit = TOTAL_BUFFERED_PACKETS / ((num_threads - 1) as usize * PACKETS_PER_BATCH);
|
let batch_limit = TOTAL_BUFFERED_PACKETS / ((num_threads - 1) as usize * PACKETS_PER_BATCH);
|
||||||
// Single thread to generate entries from many banks.
|
// Single thread to generate entries from many banks.
|
||||||
@@ -119,6 +124,7 @@ impl BankingStage {
|
|||||||
let cluster_info = cluster_info.clone();
|
let cluster_info = cluster_info.clone();
|
||||||
let mut recv_start = Instant::now();
|
let mut recv_start = Instant::now();
|
||||||
let transaction_status_sender = transaction_status_sender.clone();
|
let transaction_status_sender = transaction_status_sender.clone();
|
||||||
|
let gossip_vote_sender = gossip_vote_sender.clone();
|
||||||
Builder::new()
|
Builder::new()
|
||||||
.name("solana-banking-stage-tx".to_string())
|
.name("solana-banking-stage-tx".to_string())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
@@ -132,7 +138,8 @@ impl BankingStage {
|
|||||||
enable_forwarding,
|
enable_forwarding,
|
||||||
i,
|
i,
|
||||||
batch_limit,
|
batch_limit,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender,
|
||||||
|
gossip_vote_sender,
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -168,6 +175,7 @@ impl BankingStage {
|
|||||||
buffered_packets: &mut Vec<PacketsAndOffsets>,
|
buffered_packets: &mut Vec<PacketsAndOffsets>,
|
||||||
batch_limit: usize,
|
batch_limit: usize,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
gossip_vote_sender: &ReplayVoteSender,
|
||||||
) -> UnprocessedPackets {
|
) -> UnprocessedPackets {
|
||||||
let mut unprocessed_packets = vec![];
|
let mut unprocessed_packets = vec![];
|
||||||
let mut rebuffered_packets = 0;
|
let mut rebuffered_packets = 0;
|
||||||
@@ -199,6 +207,7 @@ impl BankingStage {
|
|||||||
&msgs,
|
&msgs,
|
||||||
unprocessed_indexes.to_owned(),
|
unprocessed_indexes.to_owned(),
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
|
gossip_vote_sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
new_tx_count += processed;
|
new_tx_count += processed;
|
||||||
@@ -283,6 +292,7 @@ impl BankingStage {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn process_buffered_packets(
|
fn process_buffered_packets(
|
||||||
my_pubkey: &Pubkey,
|
my_pubkey: &Pubkey,
|
||||||
socket: &std::net::UdpSocket,
|
socket: &std::net::UdpSocket,
|
||||||
@@ -292,6 +302,7 @@ impl BankingStage {
|
|||||||
enable_forwarding: bool,
|
enable_forwarding: bool,
|
||||||
batch_limit: usize,
|
batch_limit: usize,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
gossip_vote_sender: &ReplayVoteSender,
|
||||||
) -> BufferedPacketsDecision {
|
) -> BufferedPacketsDecision {
|
||||||
let (leader_at_slot_offset, poh_has_bank, would_be_leader) = {
|
let (leader_at_slot_offset, poh_has_bank, would_be_leader) = {
|
||||||
let poh = poh_recorder.lock().unwrap();
|
let poh = poh_recorder.lock().unwrap();
|
||||||
@@ -319,6 +330,7 @@ impl BankingStage {
|
|||||||
buffered_packets,
|
buffered_packets,
|
||||||
batch_limit,
|
batch_limit,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
|
gossip_vote_sender,
|
||||||
);
|
);
|
||||||
buffered_packets.append(&mut unprocessed);
|
buffered_packets.append(&mut unprocessed);
|
||||||
}
|
}
|
||||||
@@ -352,6 +364,7 @@ impl BankingStage {
|
|||||||
decision
|
decision
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn process_loop(
|
pub fn process_loop(
|
||||||
my_pubkey: Pubkey,
|
my_pubkey: Pubkey,
|
||||||
verified_receiver: &CrossbeamReceiver<Vec<Packets>>,
|
verified_receiver: &CrossbeamReceiver<Vec<Packets>>,
|
||||||
@@ -362,6 +375,7 @@ impl BankingStage {
|
|||||||
id: u32,
|
id: u32,
|
||||||
batch_limit: usize,
|
batch_limit: usize,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
gossip_vote_sender: ReplayVoteSender,
|
||||||
) {
|
) {
|
||||||
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
let mut buffered_packets = vec![];
|
let mut buffered_packets = vec![];
|
||||||
@@ -376,6 +390,7 @@ impl BankingStage {
|
|||||||
enable_forwarding,
|
enable_forwarding,
|
||||||
batch_limit,
|
batch_limit,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
|
&gossip_vote_sender,
|
||||||
);
|
);
|
||||||
if decision == BufferedPacketsDecision::Hold {
|
if decision == BufferedPacketsDecision::Hold {
|
||||||
// If we are waiting on a new bank,
|
// If we are waiting on a new bank,
|
||||||
@@ -403,6 +418,7 @@ impl BankingStage {
|
|||||||
id,
|
id,
|
||||||
batch_limit,
|
batch_limit,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
|
&gossip_vote_sender,
|
||||||
) {
|
) {
|
||||||
Err(RecvTimeoutError::Timeout) => (),
|
Err(RecvTimeoutError::Timeout) => (),
|
||||||
Err(RecvTimeoutError::Disconnected) => break,
|
Err(RecvTimeoutError::Disconnected) => break,
|
||||||
@@ -501,6 +517,7 @@ impl BankingStage {
|
|||||||
poh: &Arc<Mutex<PohRecorder>>,
|
poh: &Arc<Mutex<PohRecorder>>,
|
||||||
batch: &TransactionBatch,
|
batch: &TransactionBatch,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
gossip_vote_sender: &ReplayVoteSender,
|
||||||
) -> (Result<usize, PohRecorderError>, Vec<usize>) {
|
) -> (Result<usize, PohRecorderError>, Vec<usize>) {
|
||||||
let mut load_execute_time = Measure::start("load_execute_time");
|
let mut load_execute_time = Measure::start("load_execute_time");
|
||||||
// Use a shorter maximum age when adding transactions into the pipeline. This will reduce
|
// Use a shorter maximum age when adding transactions into the pipeline. This will reduce
|
||||||
@@ -533,24 +550,23 @@ impl BankingStage {
|
|||||||
let num_to_commit = num_to_commit.unwrap();
|
let num_to_commit = num_to_commit.unwrap();
|
||||||
|
|
||||||
if num_to_commit != 0 {
|
if num_to_commit != 0 {
|
||||||
let transaction_statuses = bank
|
let tx_results = bank.commit_transactions(
|
||||||
.commit_transactions(
|
txs,
|
||||||
txs,
|
None,
|
||||||
None,
|
&mut loaded_accounts,
|
||||||
&mut loaded_accounts,
|
&results,
|
||||||
&results,
|
tx_count,
|
||||||
tx_count,
|
signature_count,
|
||||||
signature_count,
|
);
|
||||||
)
|
|
||||||
.processing_results;
|
|
||||||
|
|
||||||
|
bank_utils::find_and_send_votes(txs, &tx_results, Some(gossip_vote_sender));
|
||||||
if let Some(sender) = transaction_status_sender {
|
if let Some(sender) = transaction_status_sender {
|
||||||
let post_balances = bank.collect_balances(batch);
|
let post_balances = bank.collect_balances(batch);
|
||||||
send_transaction_status_batch(
|
send_transaction_status_batch(
|
||||||
bank.clone(),
|
bank.clone(),
|
||||||
batch.transactions(),
|
batch.transactions(),
|
||||||
batch.iteration_order_vec(),
|
batch.iteration_order_vec(),
|
||||||
transaction_statuses,
|
tx_results.processing_results,
|
||||||
TransactionBalancesSet::new(pre_balances, post_balances),
|
TransactionBalancesSet::new(pre_balances, post_balances),
|
||||||
sender,
|
sender,
|
||||||
);
|
);
|
||||||
@@ -578,6 +594,7 @@ impl BankingStage {
|
|||||||
poh: &Arc<Mutex<PohRecorder>>,
|
poh: &Arc<Mutex<PohRecorder>>,
|
||||||
chunk_offset: usize,
|
chunk_offset: usize,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
gossip_vote_sender: &ReplayVoteSender,
|
||||||
) -> (Result<usize, PohRecorderError>, Vec<usize>) {
|
) -> (Result<usize, PohRecorderError>, Vec<usize>) {
|
||||||
let mut lock_time = Measure::start("lock_time");
|
let mut lock_time = Measure::start("lock_time");
|
||||||
// Once accounts are locked, other threads cannot encode transactions that will modify the
|
// Once accounts are locked, other threads cannot encode transactions that will modify the
|
||||||
@@ -590,6 +607,7 @@ impl BankingStage {
|
|||||||
poh,
|
poh,
|
||||||
&batch,
|
&batch,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
|
gossip_vote_sender,
|
||||||
);
|
);
|
||||||
retryable_txs.iter_mut().for_each(|x| *x += chunk_offset);
|
retryable_txs.iter_mut().for_each(|x| *x += chunk_offset);
|
||||||
|
|
||||||
@@ -618,6 +636,7 @@ impl BankingStage {
|
|||||||
transactions: &[Transaction],
|
transactions: &[Transaction],
|
||||||
poh: &Arc<Mutex<PohRecorder>>,
|
poh: &Arc<Mutex<PohRecorder>>,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
gossip_vote_sender: &ReplayVoteSender,
|
||||||
) -> (usize, Vec<usize>) {
|
) -> (usize, Vec<usize>) {
|
||||||
let mut chunk_start = 0;
|
let mut chunk_start = 0;
|
||||||
let mut unprocessed_txs = vec![];
|
let mut unprocessed_txs = vec![];
|
||||||
@@ -633,6 +652,7 @@ impl BankingStage {
|
|||||||
poh,
|
poh,
|
||||||
chunk_start,
|
chunk_start,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
|
gossip_vote_sender,
|
||||||
);
|
);
|
||||||
trace!("process_transactions result: {:?}", result);
|
trace!("process_transactions result: {:?}", result);
|
||||||
|
|
||||||
@@ -764,6 +784,7 @@ impl BankingStage {
|
|||||||
msgs: &Packets,
|
msgs: &Packets,
|
||||||
packet_indexes: Vec<usize>,
|
packet_indexes: Vec<usize>,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
gossip_vote_sender: &ReplayVoteSender,
|
||||||
) -> (usize, usize, Vec<usize>) {
|
) -> (usize, usize, Vec<usize>) {
|
||||||
let (transactions, transaction_to_packet_indexes) =
|
let (transactions, transaction_to_packet_indexes) =
|
||||||
Self::transactions_from_packets(msgs, &packet_indexes);
|
Self::transactions_from_packets(msgs, &packet_indexes);
|
||||||
@@ -775,8 +796,13 @@ impl BankingStage {
|
|||||||
|
|
||||||
let tx_len = transactions.len();
|
let tx_len = transactions.len();
|
||||||
|
|
||||||
let (processed, unprocessed_tx_indexes) =
|
let (processed, unprocessed_tx_indexes) = Self::process_transactions(
|
||||||
Self::process_transactions(bank, &transactions, poh, transaction_status_sender);
|
bank,
|
||||||
|
&transactions,
|
||||||
|
poh,
|
||||||
|
transaction_status_sender,
|
||||||
|
gossip_vote_sender,
|
||||||
|
);
|
||||||
|
|
||||||
let unprocessed_tx_count = unprocessed_tx_indexes.len();
|
let unprocessed_tx_count = unprocessed_tx_indexes.len();
|
||||||
|
|
||||||
@@ -846,6 +872,7 @@ impl BankingStage {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
/// Process the incoming packets
|
/// Process the incoming packets
|
||||||
pub fn process_packets(
|
pub fn process_packets(
|
||||||
my_pubkey: &Pubkey,
|
my_pubkey: &Pubkey,
|
||||||
@@ -856,6 +883,7 @@ impl BankingStage {
|
|||||||
id: u32,
|
id: u32,
|
||||||
batch_limit: usize,
|
batch_limit: usize,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
gossip_vote_sender: &ReplayVoteSender,
|
||||||
) -> Result<UnprocessedPackets, RecvTimeoutError> {
|
) -> Result<UnprocessedPackets, RecvTimeoutError> {
|
||||||
let mut recv_time = Measure::start("process_packets_recv");
|
let mut recv_time = Measure::start("process_packets_recv");
|
||||||
let mms = verified_receiver.recv_timeout(recv_timeout)?;
|
let mms = verified_receiver.recv_timeout(recv_timeout)?;
|
||||||
@@ -898,6 +926,7 @@ impl BankingStage {
|
|||||||
&msgs,
|
&msgs,
|
||||||
packet_indexes,
|
packet_indexes,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
|
gossip_vote_sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
new_tx_count += processed;
|
new_tx_count += processed;
|
||||||
@@ -1044,6 +1073,7 @@ mod tests {
|
|||||||
let bank = Arc::new(Bank::new(&genesis_config));
|
let bank = Arc::new(Bank::new(&genesis_config));
|
||||||
let (verified_sender, verified_receiver) = unbounded();
|
let (verified_sender, verified_receiver) = unbounded();
|
||||||
let (vote_sender, vote_receiver) = unbounded();
|
let (vote_sender, vote_receiver) = unbounded();
|
||||||
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
||||||
let ledger_path = get_tmp_ledger_path!();
|
let ledger_path = get_tmp_ledger_path!();
|
||||||
{
|
{
|
||||||
let blockstore = Arc::new(
|
let blockstore = Arc::new(
|
||||||
@@ -1060,6 +1090,7 @@ mod tests {
|
|||||||
verified_receiver,
|
verified_receiver,
|
||||||
vote_receiver,
|
vote_receiver,
|
||||||
None,
|
None,
|
||||||
|
gossip_vote_sender,
|
||||||
);
|
);
|
||||||
drop(verified_sender);
|
drop(verified_sender);
|
||||||
drop(vote_sender);
|
drop(vote_sender);
|
||||||
@@ -1094,12 +1125,15 @@ mod tests {
|
|||||||
create_test_recorder(&bank, &blockstore, Some(poh_config));
|
create_test_recorder(&bank, &blockstore, Some(poh_config));
|
||||||
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
||||||
let cluster_info = Arc::new(cluster_info);
|
let cluster_info = Arc::new(cluster_info);
|
||||||
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
||||||
|
|
||||||
let banking_stage = BankingStage::new(
|
let banking_stage = BankingStage::new(
|
||||||
&cluster_info,
|
&cluster_info,
|
||||||
&poh_recorder,
|
&poh_recorder,
|
||||||
verified_receiver,
|
verified_receiver,
|
||||||
vote_receiver,
|
vote_receiver,
|
||||||
None,
|
None,
|
||||||
|
gossip_vote_sender,
|
||||||
);
|
);
|
||||||
trace!("sending bank");
|
trace!("sending bank");
|
||||||
drop(verified_sender);
|
drop(verified_sender);
|
||||||
@@ -1157,12 +1191,15 @@ mod tests {
|
|||||||
create_test_recorder(&bank, &blockstore, Some(poh_config));
|
create_test_recorder(&bank, &blockstore, Some(poh_config));
|
||||||
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
||||||
let cluster_info = Arc::new(cluster_info);
|
let cluster_info = Arc::new(cluster_info);
|
||||||
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
||||||
|
|
||||||
let banking_stage = BankingStage::new(
|
let banking_stage = BankingStage::new(
|
||||||
&cluster_info,
|
&cluster_info,
|
||||||
&poh_recorder,
|
&poh_recorder,
|
||||||
verified_receiver,
|
verified_receiver,
|
||||||
vote_receiver,
|
vote_receiver,
|
||||||
None,
|
None,
|
||||||
|
gossip_vote_sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
// fund another account so we can send 2 good transactions in a single batch.
|
// fund another account so we can send 2 good transactions in a single batch.
|
||||||
@@ -1283,6 +1320,8 @@ mod tests {
|
|||||||
let (vote_sender, vote_receiver) = unbounded();
|
let (vote_sender, vote_receiver) = unbounded();
|
||||||
let ledger_path = get_tmp_ledger_path!();
|
let ledger_path = get_tmp_ledger_path!();
|
||||||
{
|
{
|
||||||
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
||||||
|
|
||||||
let entry_receiver = {
|
let entry_receiver = {
|
||||||
// start a banking_stage to eat verified receiver
|
// start a banking_stage to eat verified receiver
|
||||||
let bank = Arc::new(Bank::new(&genesis_config));
|
let bank = Arc::new(Bank::new(&genesis_config));
|
||||||
@@ -1305,6 +1344,7 @@ mod tests {
|
|||||||
vote_receiver,
|
vote_receiver,
|
||||||
2,
|
2,
|
||||||
None,
|
None,
|
||||||
|
gossip_vote_sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
// wait for banking_stage to eat the packets
|
// wait for banking_stage to eat the packets
|
||||||
@@ -1682,6 +1722,7 @@ mod tests {
|
|||||||
let poh_recorder = Arc::new(Mutex::new(poh_recorder));
|
let poh_recorder = Arc::new(Mutex::new(poh_recorder));
|
||||||
|
|
||||||
poh_recorder.lock().unwrap().set_working_bank(working_bank);
|
poh_recorder.lock().unwrap().set_working_bank(working_bank);
|
||||||
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
||||||
|
|
||||||
BankingStage::process_and_record_transactions(
|
BankingStage::process_and_record_transactions(
|
||||||
&bank,
|
&bank,
|
||||||
@@ -1689,6 +1730,7 @@ mod tests {
|
|||||||
&poh_recorder,
|
&poh_recorder,
|
||||||
0,
|
0,
|
||||||
None,
|
None,
|
||||||
|
&gossip_vote_sender,
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -1725,6 +1767,7 @@ mod tests {
|
|||||||
&poh_recorder,
|
&poh_recorder,
|
||||||
0,
|
0,
|
||||||
None,
|
None,
|
||||||
|
&gossip_vote_sender,
|
||||||
)
|
)
|
||||||
.0,
|
.0,
|
||||||
Err(PohRecorderError::MaxHeightReached)
|
Err(PohRecorderError::MaxHeightReached)
|
||||||
@@ -1776,12 +1819,15 @@ mod tests {
|
|||||||
|
|
||||||
poh_recorder.lock().unwrap().set_working_bank(working_bank);
|
poh_recorder.lock().unwrap().set_working_bank(working_bank);
|
||||||
|
|
||||||
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
||||||
|
|
||||||
let (result, unprocessed) = BankingStage::process_and_record_transactions(
|
let (result, unprocessed) = BankingStage::process_and_record_transactions(
|
||||||
&bank,
|
&bank,
|
||||||
&transactions,
|
&transactions,
|
||||||
&poh_recorder,
|
&poh_recorder,
|
||||||
0,
|
0,
|
||||||
None,
|
None,
|
||||||
|
&gossip_vote_sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
@@ -1865,8 +1911,16 @@ mod tests {
|
|||||||
// record
|
// record
|
||||||
let poh_recorder = Arc::new(Mutex::new(poh_recorder));
|
let poh_recorder = Arc::new(Mutex::new(poh_recorder));
|
||||||
|
|
||||||
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
||||||
|
|
||||||
let (processed_transactions_count, mut retryable_txs) =
|
let (processed_transactions_count, mut retryable_txs) =
|
||||||
BankingStage::process_transactions(&bank, &transactions, &poh_recorder, None);
|
BankingStage::process_transactions(
|
||||||
|
&bank,
|
||||||
|
&transactions,
|
||||||
|
&poh_recorder,
|
||||||
|
None,
|
||||||
|
&gossip_vote_sender,
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(processed_transactions_count, 0,);
|
assert_eq!(processed_transactions_count, 0,);
|
||||||
|
|
||||||
@@ -1943,12 +1997,15 @@ mod tests {
|
|||||||
&Arc::new(AtomicBool::new(false)),
|
&Arc::new(AtomicBool::new(false)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
||||||
|
|
||||||
let _ = BankingStage::process_and_record_transactions(
|
let _ = BankingStage::process_and_record_transactions(
|
||||||
&bank,
|
&bank,
|
||||||
&transactions,
|
&transactions,
|
||||||
&poh_recorder,
|
&poh_recorder,
|
||||||
0,
|
0,
|
||||||
Some(transaction_status_sender),
|
Some(transaction_status_sender),
|
||||||
|
&gossip_vote_sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
transaction_status_service.join().unwrap();
|
transaction_status_service.join().unwrap();
|
||||||
|
@@ -15,10 +15,7 @@ use crossbeam_channel::{
|
|||||||
};
|
};
|
||||||
use itertools::izip;
|
use itertools::izip;
|
||||||
use log::*;
|
use log::*;
|
||||||
use solana_ledger::{
|
use solana_ledger::blockstore::Blockstore;
|
||||||
blockstore::Blockstore,
|
|
||||||
blockstore_processor::{ReplayVotesReceiver, ReplayedVote},
|
|
||||||
};
|
|
||||||
use solana_metrics::inc_new_counter_debug;
|
use solana_metrics::inc_new_counter_debug;
|
||||||
use solana_perf::packet::{self, Packets};
|
use solana_perf::packet::{self, Packets};
|
||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
@@ -26,6 +23,7 @@ use solana_runtime::{
|
|||||||
bank_forks::BankForks,
|
bank_forks::BankForks,
|
||||||
epoch_stakes::{EpochAuthorizedVoters, EpochStakes},
|
epoch_stakes::{EpochAuthorizedVoters, EpochStakes},
|
||||||
stakes::Stakes,
|
stakes::Stakes,
|
||||||
|
vote_sender_types::{ReplayVoteReceiver, ReplayedVote},
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{Epoch, Slot},
|
clock::{Epoch, Slot},
|
||||||
@@ -248,7 +246,7 @@ impl ClusterInfoVoteListener {
|
|||||||
bank_forks: Arc<RwLock<BankForks>>,
|
bank_forks: Arc<RwLock<BankForks>>,
|
||||||
subscriptions: Arc<RpcSubscriptions>,
|
subscriptions: Arc<RpcSubscriptions>,
|
||||||
verified_vote_sender: VerifiedVoteSender,
|
verified_vote_sender: VerifiedVoteSender,
|
||||||
replay_votes_receiver: ReplayVotesReceiver,
|
replay_votes_receiver: ReplayVoteReceiver,
|
||||||
blockstore: Arc<Blockstore>,
|
blockstore: Arc<Blockstore>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let exit_ = exit.clone();
|
let exit_ = exit.clone();
|
||||||
@@ -420,7 +418,7 @@ impl ClusterInfoVoteListener {
|
|||||||
bank_forks: Arc<RwLock<BankForks>>,
|
bank_forks: Arc<RwLock<BankForks>>,
|
||||||
subscriptions: Arc<RpcSubscriptions>,
|
subscriptions: Arc<RpcSubscriptions>,
|
||||||
verified_vote_sender: VerifiedVoteSender,
|
verified_vote_sender: VerifiedVoteSender,
|
||||||
replay_votes_receiver: ReplayVotesReceiver,
|
replay_votes_receiver: ReplayVoteReceiver,
|
||||||
blockstore: Arc<Blockstore>,
|
blockstore: Arc<Blockstore>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut optimistic_confirmation_verifier =
|
let mut optimistic_confirmation_verifier =
|
||||||
@@ -478,7 +476,7 @@ impl ClusterInfoVoteListener {
|
|||||||
root_bank: &Bank,
|
root_bank: &Bank,
|
||||||
subscriptions: &RpcSubscriptions,
|
subscriptions: &RpcSubscriptions,
|
||||||
verified_vote_sender: &VerifiedVoteSender,
|
verified_vote_sender: &VerifiedVoteSender,
|
||||||
replay_votes_receiver: &ReplayVotesReceiver,
|
replay_votes_receiver: &ReplayVoteReceiver,
|
||||||
) -> Result<Vec<(Slot, Hash)>> {
|
) -> Result<Vec<(Slot, Hash)>> {
|
||||||
Self::get_and_process_votes(
|
Self::get_and_process_votes(
|
||||||
gossip_vote_txs_receiver,
|
gossip_vote_txs_receiver,
|
||||||
@@ -496,7 +494,7 @@ impl ClusterInfoVoteListener {
|
|||||||
root_bank: &Bank,
|
root_bank: &Bank,
|
||||||
subscriptions: &RpcSubscriptions,
|
subscriptions: &RpcSubscriptions,
|
||||||
verified_vote_sender: &VerifiedVoteSender,
|
verified_vote_sender: &VerifiedVoteSender,
|
||||||
replay_votes_receiver: &ReplayVotesReceiver,
|
replay_votes_receiver: &ReplayVoteReceiver,
|
||||||
) -> Result<Vec<(Slot, Hash)>> {
|
) -> Result<Vec<(Slot, Hash)>> {
|
||||||
let mut sel = Select::new();
|
let mut sel = Select::new();
|
||||||
sel.recv(gossip_vote_txs_receiver);
|
sel.recv(gossip_vote_txs_receiver);
|
||||||
@@ -772,12 +770,12 @@ impl ClusterInfoVoteListener {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use solana_ledger::blockstore_processor::ReplayVotesSender;
|
|
||||||
use solana_perf::packet;
|
use solana_perf::packet;
|
||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
bank::Bank,
|
bank::Bank,
|
||||||
commitment::BlockCommitmentCache,
|
commitment::BlockCommitmentCache,
|
||||||
genesis_utils::{self, GenesisConfigInfo, ValidatorVoteKeypairs},
|
genesis_utils::{self, GenesisConfigInfo, ValidatorVoteKeypairs},
|
||||||
|
vote_sender_types::ReplayVoteSender,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
@@ -1040,7 +1038,7 @@ mod tests {
|
|||||||
validator_voting_keypairs: &[ValidatorVoteKeypairs],
|
validator_voting_keypairs: &[ValidatorVoteKeypairs],
|
||||||
switch_proof_hash: Option<Hash>,
|
switch_proof_hash: Option<Hash>,
|
||||||
votes_sender: &VerifiedVoteTransactionsSender,
|
votes_sender: &VerifiedVoteTransactionsSender,
|
||||||
replay_votes_sender: &ReplayVotesSender,
|
replay_votes_sender: &ReplayVoteSender,
|
||||||
) {
|
) {
|
||||||
validator_voting_keypairs.iter().for_each(|keypairs| {
|
validator_voting_keypairs.iter().for_each(|keypairs| {
|
||||||
let node_keypair = &keypairs.node_keypair;
|
let node_keypair = &keypairs.node_keypair;
|
||||||
|
@@ -21,9 +21,7 @@ use crate::{
|
|||||||
use solana_ledger::{
|
use solana_ledger::{
|
||||||
block_error::BlockError,
|
block_error::BlockError,
|
||||||
blockstore::Blockstore,
|
blockstore::Blockstore,
|
||||||
blockstore_processor::{
|
blockstore_processor::{self, BlockstoreProcessorError, TransactionStatusSender},
|
||||||
self, BlockstoreProcessorError, ReplayVotesSender, TransactionStatusSender,
|
|
||||||
},
|
|
||||||
entry::VerifyRecyclers,
|
entry::VerifyRecyclers,
|
||||||
leader_schedule_cache::LeaderScheduleCache,
|
leader_schedule_cache::LeaderScheduleCache,
|
||||||
};
|
};
|
||||||
@@ -31,7 +29,7 @@ use solana_measure::{measure::Measure, thread_mem_usage};
|
|||||||
use solana_metrics::inc_new_counter_info;
|
use solana_metrics::inc_new_counter_info;
|
||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
bank::Bank, bank_forks::BankForks, commitment::BlockCommitmentCache,
|
bank::Bank, bank_forks::BankForks, commitment::BlockCommitmentCache,
|
||||||
snapshot_package::AccountsPackageSender,
|
snapshot_package::AccountsPackageSender, vote_sender_types::ReplayVoteSender,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{Slot, NUM_CONSECUTIVE_LEADER_SLOTS},
|
clock::{Slot, NUM_CONSECUTIVE_LEADER_SLOTS},
|
||||||
@@ -223,7 +221,7 @@ impl ReplayStage {
|
|||||||
cluster_slots: Arc<ClusterSlots>,
|
cluster_slots: Arc<ClusterSlots>,
|
||||||
retransmit_slots_sender: RetransmitSlotsSender,
|
retransmit_slots_sender: RetransmitSlotsSender,
|
||||||
duplicate_slots_reset_receiver: DuplicateSlotsResetReceiver,
|
duplicate_slots_reset_receiver: DuplicateSlotsResetReceiver,
|
||||||
replay_votes_sender: ReplayVotesSender,
|
replay_vote_sender: ReplayVoteSender,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let ReplayStageConfig {
|
let ReplayStageConfig {
|
||||||
my_pubkey,
|
my_pubkey,
|
||||||
@@ -344,7 +342,7 @@ impl ReplayStage {
|
|||||||
&verify_recyclers,
|
&verify_recyclers,
|
||||||
&mut heaviest_subtree_fork_choice,
|
&mut heaviest_subtree_fork_choice,
|
||||||
&subscriptions,
|
&subscriptions,
|
||||||
&replay_votes_sender,
|
&replay_vote_sender,
|
||||||
);
|
);
|
||||||
replay_active_banks_time.stop();
|
replay_active_banks_time.stop();
|
||||||
Self::report_memory(&allocated, "replay_active_banks", start);
|
Self::report_memory(&allocated, "replay_active_banks", start);
|
||||||
@@ -940,7 +938,7 @@ impl ReplayStage {
|
|||||||
blockstore: &Blockstore,
|
blockstore: &Blockstore,
|
||||||
bank_progress: &mut ForkProgress,
|
bank_progress: &mut ForkProgress,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
replay_votes_sender: &ReplayVotesSender,
|
replay_vote_sender: &ReplayVoteSender,
|
||||||
verify_recyclers: &VerifyRecyclers,
|
verify_recyclers: &VerifyRecyclers,
|
||||||
) -> result::Result<usize, BlockstoreProcessorError> {
|
) -> result::Result<usize, BlockstoreProcessorError> {
|
||||||
let tx_count_before = bank_progress.replay_progress.num_txs;
|
let tx_count_before = bank_progress.replay_progress.num_txs;
|
||||||
@@ -951,7 +949,7 @@ impl ReplayStage {
|
|||||||
&mut bank_progress.replay_progress,
|
&mut bank_progress.replay_progress,
|
||||||
false,
|
false,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
Some(replay_votes_sender),
|
Some(replay_vote_sender),
|
||||||
None,
|
None,
|
||||||
verify_recyclers,
|
verify_recyclers,
|
||||||
);
|
);
|
||||||
@@ -1214,7 +1212,7 @@ impl ReplayStage {
|
|||||||
verify_recyclers: &VerifyRecyclers,
|
verify_recyclers: &VerifyRecyclers,
|
||||||
heaviest_subtree_fork_choice: &mut HeaviestSubtreeForkChoice,
|
heaviest_subtree_fork_choice: &mut HeaviestSubtreeForkChoice,
|
||||||
subscriptions: &Arc<RpcSubscriptions>,
|
subscriptions: &Arc<RpcSubscriptions>,
|
||||||
replay_votes_sender: &ReplayVotesSender,
|
replay_vote_sender: &ReplayVoteSender,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut did_complete_bank = false;
|
let mut did_complete_bank = false;
|
||||||
let mut tx_count = 0;
|
let mut tx_count = 0;
|
||||||
@@ -1260,7 +1258,7 @@ impl ReplayStage {
|
|||||||
&blockstore,
|
&blockstore,
|
||||||
bank_progress,
|
bank_progress,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
replay_votes_sender,
|
replay_vote_sender,
|
||||||
verify_recyclers,
|
verify_recyclers,
|
||||||
);
|
);
|
||||||
match replay_result {
|
match replay_result {
|
||||||
@@ -2417,7 +2415,7 @@ pub(crate) mod tests {
|
|||||||
F: Fn(&Keypair, Arc<Bank>) -> Vec<Shred>,
|
F: Fn(&Keypair, Arc<Bank>) -> Vec<Shred>,
|
||||||
{
|
{
|
||||||
let ledger_path = get_tmp_ledger_path!();
|
let ledger_path = get_tmp_ledger_path!();
|
||||||
let (replay_votes_sender, _replay_votes_receiver) = unbounded();
|
let (replay_vote_sender, _replay_vote_receiver) = unbounded();
|
||||||
let res = {
|
let res = {
|
||||||
let blockstore = Arc::new(
|
let blockstore = Arc::new(
|
||||||
Blockstore::open(&ledger_path)
|
Blockstore::open(&ledger_path)
|
||||||
@@ -2442,8 +2440,8 @@ pub(crate) mod tests {
|
|||||||
&blockstore,
|
&blockstore,
|
||||||
&mut bank0_progress,
|
&mut bank0_progress,
|
||||||
None,
|
None,
|
||||||
&replay_votes_sender,
|
&replay_vote_sender,
|
||||||
&VerifyRecyclers::default(),
|
&&VerifyRecyclers::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check that the erroring bank was marked as dead in the progress map
|
// Check that the erroring bank was marked as dead in the progress map
|
||||||
@@ -2606,7 +2604,7 @@ pub(crate) mod tests {
|
|||||||
blockstore.set_roots(&[slot]).unwrap();
|
blockstore.set_roots(&[slot]).unwrap();
|
||||||
|
|
||||||
let (transaction_status_sender, transaction_status_receiver) = unbounded();
|
let (transaction_status_sender, transaction_status_receiver) = unbounded();
|
||||||
let (replay_votes_sender, _replay_votes_receiver) = unbounded();
|
let (replay_vote_sender, _replay_vote_receiver) = unbounded();
|
||||||
let transaction_status_service = TransactionStatusService::new(
|
let transaction_status_service = TransactionStatusService::new(
|
||||||
transaction_status_receiver,
|
transaction_status_receiver,
|
||||||
blockstore,
|
blockstore,
|
||||||
@@ -2620,7 +2618,7 @@ pub(crate) mod tests {
|
|||||||
&entries,
|
&entries,
|
||||||
true,
|
true,
|
||||||
Some(transaction_status_sender),
|
Some(transaction_status_sender),
|
||||||
Some(&replay_votes_sender),
|
Some(&replay_vote_sender),
|
||||||
);
|
);
|
||||||
|
|
||||||
transaction_status_service.join().unwrap();
|
transaction_status_service.join().unwrap();
|
||||||
|
338
core/src/rpc.rs
338
core/src/rpc.rs
@@ -9,7 +9,11 @@ use bincode::{config::Options, serialize};
|
|||||||
use jsonrpc_core::{Error, Metadata, Result};
|
use jsonrpc_core::{Error, Metadata, Result};
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use solana_account_decoder::{
|
use solana_account_decoder::{
|
||||||
parse_token::{spl_token_id_v1_0, spl_token_v1_0_native_mint},
|
parse_account_data::AccountAdditionalData,
|
||||||
|
parse_token::{
|
||||||
|
get_token_account_mint, spl_token_id_v1_0, spl_token_v1_0_native_mint,
|
||||||
|
token_amount_to_ui_amount, UiTokenAmount,
|
||||||
|
},
|
||||||
UiAccount, UiAccountEncoding,
|
UiAccount, UiAccountEncoding,
|
||||||
};
|
};
|
||||||
use solana_client::{
|
use solana_client::{
|
||||||
@@ -17,6 +21,7 @@ use solana_client::{
|
|||||||
rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType},
|
rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType},
|
||||||
rpc_request::{
|
rpc_request::{
|
||||||
TokenAccountsFilter, DELINQUENT_VALIDATOR_SLOT_DISTANCE, MAX_GET_CONFIRMED_BLOCKS_RANGE,
|
TokenAccountsFilter, DELINQUENT_VALIDATOR_SLOT_DISTANCE, MAX_GET_CONFIRMED_BLOCKS_RANGE,
|
||||||
|
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT,
|
||||||
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE,
|
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE,
|
||||||
MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS, NUM_LARGEST_ACCOUNTS,
|
MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS, NUM_LARGEST_ACCOUNTS,
|
||||||
},
|
},
|
||||||
@@ -66,6 +71,7 @@ use std::{
|
|||||||
Arc, Mutex, RwLock,
|
Arc, Mutex, RwLock,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use tokio::runtime;
|
||||||
|
|
||||||
fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
|
fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
|
||||||
let context = RpcResponseContext { slot: bank.slot() };
|
let context = RpcResponseContext { slot: bank.slot() };
|
||||||
@@ -90,6 +96,7 @@ pub struct JsonRpcConfig {
|
|||||||
pub identity_pubkey: Pubkey,
|
pub identity_pubkey: Pubkey,
|
||||||
pub faucet_addr: Option<SocketAddr>,
|
pub faucet_addr: Option<SocketAddr>,
|
||||||
pub health_check_slot_distance: u64,
|
pub health_check_slot_distance: u64,
|
||||||
|
pub enable_bigtable_ledger_storage: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -103,6 +110,8 @@ pub struct JsonRpcRequestProcessor {
|
|||||||
cluster_info: Arc<ClusterInfo>,
|
cluster_info: Arc<ClusterInfo>,
|
||||||
genesis_hash: Hash,
|
genesis_hash: Hash,
|
||||||
transaction_sender: Arc<Mutex<Sender<TransactionInfo>>>,
|
transaction_sender: Arc<Mutex<Sender<TransactionInfo>>>,
|
||||||
|
runtime_handle: runtime::Handle,
|
||||||
|
bigtable_ledger_storage: Option<solana_storage_bigtable::LedgerStorage>,
|
||||||
}
|
}
|
||||||
impl Metadata for JsonRpcRequestProcessor {}
|
impl Metadata for JsonRpcRequestProcessor {}
|
||||||
|
|
||||||
@@ -157,6 +166,7 @@ impl JsonRpcRequestProcessor {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
config: JsonRpcConfig,
|
config: JsonRpcConfig,
|
||||||
bank_forks: Arc<RwLock<BankForks>>,
|
bank_forks: Arc<RwLock<BankForks>>,
|
||||||
@@ -166,6 +176,8 @@ impl JsonRpcRequestProcessor {
|
|||||||
health: Arc<RpcHealth>,
|
health: Arc<RpcHealth>,
|
||||||
cluster_info: Arc<ClusterInfo>,
|
cluster_info: Arc<ClusterInfo>,
|
||||||
genesis_hash: Hash,
|
genesis_hash: Hash,
|
||||||
|
runtime: &runtime::Runtime,
|
||||||
|
bigtable_ledger_storage: Option<solana_storage_bigtable::LedgerStorage>,
|
||||||
) -> (Self, Receiver<TransactionInfo>) {
|
) -> (Self, Receiver<TransactionInfo>) {
|
||||||
let (sender, receiver) = channel();
|
let (sender, receiver) = channel();
|
||||||
(
|
(
|
||||||
@@ -179,6 +191,8 @@ impl JsonRpcRequestProcessor {
|
|||||||
cluster_info,
|
cluster_info,
|
||||||
genesis_hash,
|
genesis_hash,
|
||||||
transaction_sender: Arc::new(Mutex::new(sender)),
|
transaction_sender: Arc::new(Mutex::new(sender)),
|
||||||
|
runtime_handle: runtime.handle().clone(),
|
||||||
|
bigtable_ledger_storage,
|
||||||
},
|
},
|
||||||
receiver,
|
receiver,
|
||||||
)
|
)
|
||||||
@@ -217,6 +231,8 @@ impl JsonRpcRequestProcessor {
|
|||||||
cluster_info,
|
cluster_info,
|
||||||
genesis_hash,
|
genesis_hash,
|
||||||
transaction_sender: Arc::new(Mutex::new(sender)),
|
transaction_sender: Arc::new(Mutex::new(sender)),
|
||||||
|
runtime_handle: runtime::Runtime::new().unwrap().handle().clone(),
|
||||||
|
bigtable_ledger_storage: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,8 +246,14 @@ impl JsonRpcRequestProcessor {
|
|||||||
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
||||||
new_response(
|
new_response(
|
||||||
&bank,
|
&bank,
|
||||||
bank.get_account(pubkey)
|
bank.get_account(pubkey).and_then(|account| {
|
||||||
.map(|account| UiAccount::encode(account, encoding)),
|
if account.owner == spl_token_id_v1_0() && encoding == UiAccountEncoding::JsonParsed
|
||||||
|
{
|
||||||
|
get_parsed_token_account(bank.clone(), account)
|
||||||
|
} else {
|
||||||
|
Some(UiAccount::encode(account, encoding, None))
|
||||||
|
}
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,12 +275,17 @@ impl JsonRpcRequestProcessor {
|
|||||||
let config = config.unwrap_or_default();
|
let config = config.unwrap_or_default();
|
||||||
let bank = self.bank(config.commitment);
|
let bank = self.bank(config.commitment);
|
||||||
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
||||||
get_filtered_program_accounts(&bank, program_id, filters)
|
let keyed_accounts = get_filtered_program_accounts(&bank, program_id, filters);
|
||||||
.map(|(pubkey, account)| RpcKeyedAccount {
|
if program_id == &spl_token_id_v1_0() && encoding == UiAccountEncoding::JsonParsed {
|
||||||
pubkey: pubkey.to_string(),
|
get_parsed_token_accounts(bank, keyed_accounts).collect()
|
||||||
account: UiAccount::encode(account, encoding.clone()),
|
} else {
|
||||||
})
|
keyed_accounts
|
||||||
.collect()
|
.map(|(pubkey, account)| RpcKeyedAccount {
|
||||||
|
pubkey: pubkey.to_string(),
|
||||||
|
account: UiAccount::encode(account, encoding.clone(), None),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_inflation_governor(
|
pub fn get_inflation_governor(
|
||||||
@@ -556,6 +583,7 @@ impl JsonRpcRequestProcessor {
|
|||||||
slot: Slot,
|
slot: Slot,
|
||||||
encoding: Option<UiTransactionEncoding>,
|
encoding: Option<UiTransactionEncoding>,
|
||||||
) -> Result<Option<ConfirmedBlock>> {
|
) -> Result<Option<ConfirmedBlock>> {
|
||||||
|
let encoding = encoding.unwrap_or(UiTransactionEncoding::Json);
|
||||||
if self.config.enable_rpc_transaction_history
|
if self.config.enable_rpc_transaction_history
|
||||||
&& slot
|
&& slot
|
||||||
<= self
|
<= self
|
||||||
@@ -564,7 +592,15 @@ impl JsonRpcRequestProcessor {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.highest_confirmed_root()
|
.highest_confirmed_root()
|
||||||
{
|
{
|
||||||
let result = self.blockstore.get_confirmed_block(slot, encoding);
|
let result = self.blockstore.get_confirmed_block(slot, Some(encoding));
|
||||||
|
if result.is_err() {
|
||||||
|
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||||
|
return Ok(self
|
||||||
|
.runtime_handle
|
||||||
|
.block_on(bigtable_ledger_storage.get_confirmed_block(slot, encoding))
|
||||||
|
.ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
self.check_slot_cleaned_up(&result, slot)?;
|
self.check_slot_cleaned_up(&result, slot)?;
|
||||||
Ok(result.ok())
|
Ok(result.ok())
|
||||||
} else {
|
} else {
|
||||||
@@ -593,9 +629,25 @@ impl JsonRpcRequestProcessor {
|
|||||||
MAX_GET_CONFIRMED_BLOCKS_RANGE
|
MAX_GET_CONFIRMED_BLOCKS_RANGE
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let lowest_slot = self.blockstore.lowest_slot();
|
||||||
|
if start_slot < lowest_slot {
|
||||||
|
// If the starting slot is lower than what's available in blockstore assume the entire
|
||||||
|
// [start_slot..end_slot] can be fetched from BigTable.
|
||||||
|
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||||
|
return Ok(self
|
||||||
|
.runtime_handle
|
||||||
|
.block_on(
|
||||||
|
bigtable_ledger_storage
|
||||||
|
.get_confirmed_blocks(start_slot, (end_slot - start_slot) as usize),
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|_| vec![]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(self
|
Ok(self
|
||||||
.blockstore
|
.blockstore
|
||||||
.rooted_slot_iterator(max(start_slot, self.blockstore.lowest_slot()))
|
.rooted_slot_iterator(max(start_slot, lowest_slot))
|
||||||
.map_err(|_| Error::internal_error())?
|
.map_err(|_| Error::internal_error())?
|
||||||
.filter(|&slot| slot <= end_slot)
|
.filter(|&slot| slot <= end_slot)
|
||||||
.collect())
|
.collect())
|
||||||
@@ -689,6 +741,16 @@ impl JsonRpcRequestProcessor {
|
|||||||
err,
|
err,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||||
|
self.runtime_handle
|
||||||
|
.block_on(bigtable_ledger_storage.get_signature_status(&signature))
|
||||||
|
.map(Some)
|
||||||
|
.unwrap_or(None)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@@ -731,21 +793,38 @@ impl JsonRpcRequestProcessor {
|
|||||||
signature: Signature,
|
signature: Signature,
|
||||||
encoding: Option<UiTransactionEncoding>,
|
encoding: Option<UiTransactionEncoding>,
|
||||||
) -> Option<ConfirmedTransaction> {
|
) -> Option<ConfirmedTransaction> {
|
||||||
|
let encoding = encoding.unwrap_or(UiTransactionEncoding::Json);
|
||||||
if self.config.enable_rpc_transaction_history {
|
if self.config.enable_rpc_transaction_history {
|
||||||
self.blockstore
|
match self
|
||||||
.get_confirmed_transaction(signature, encoding)
|
.blockstore
|
||||||
|
.get_confirmed_transaction(signature, Some(encoding))
|
||||||
.unwrap_or(None)
|
.unwrap_or(None)
|
||||||
.filter(|confirmed_transaction| {
|
{
|
||||||
confirmed_transaction.slot
|
Some(confirmed_transaction) => {
|
||||||
|
if confirmed_transaction.slot
|
||||||
<= self
|
<= self
|
||||||
.block_commitment_cache
|
.block_commitment_cache
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.highest_confirmed_root()
|
.highest_confirmed_root()
|
||||||
})
|
{
|
||||||
} else {
|
return Some(confirmed_transaction);
|
||||||
None
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||||
|
return self
|
||||||
|
.runtime_handle
|
||||||
|
.block_on(
|
||||||
|
bigtable_ledger_storage
|
||||||
|
.get_confirmed_transaction(&signature, encoding),
|
||||||
|
)
|
||||||
|
.unwrap_or(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_confirmed_signatures_for_address(
|
pub fn get_confirmed_signatures_for_address(
|
||||||
@@ -755,6 +834,8 @@ impl JsonRpcRequestProcessor {
|
|||||||
end_slot: Slot,
|
end_slot: Slot,
|
||||||
) -> Vec<Signature> {
|
) -> Vec<Signature> {
|
||||||
if self.config.enable_rpc_transaction_history {
|
if self.config.enable_rpc_transaction_history {
|
||||||
|
// TODO: Add bigtable_ledger_storage support as a part of
|
||||||
|
// https://github.com/solana-labs/solana/pull/10928
|
||||||
let end_slot = min(
|
let end_slot = min(
|
||||||
end_slot,
|
end_slot,
|
||||||
self.block_commitment_cache
|
self.block_commitment_cache
|
||||||
@@ -770,10 +851,74 @@ impl JsonRpcRequestProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_confirmed_signatures_for_address2(
|
||||||
|
&self,
|
||||||
|
address: Pubkey,
|
||||||
|
mut before: Option<Signature>,
|
||||||
|
mut limit: usize,
|
||||||
|
) -> Result<Vec<RpcConfirmedTransactionStatusWithSignature>> {
|
||||||
|
if self.config.enable_rpc_transaction_history {
|
||||||
|
let highest_confirmed_root = self
|
||||||
|
.block_commitment_cache
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.highest_confirmed_root();
|
||||||
|
|
||||||
|
let mut results = self
|
||||||
|
.blockstore
|
||||||
|
.get_confirmed_signatures_for_address2(
|
||||||
|
address,
|
||||||
|
highest_confirmed_root,
|
||||||
|
before,
|
||||||
|
limit,
|
||||||
|
)
|
||||||
|
.map_err(|err| Error::invalid_params(format!("{}", err)))?;
|
||||||
|
|
||||||
|
if results.len() < limit {
|
||||||
|
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||||
|
if !results.is_empty() {
|
||||||
|
limit -= results.len();
|
||||||
|
before = results.last().map(|x| x.signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bigtable_results = self
|
||||||
|
.runtime_handle
|
||||||
|
.block_on(
|
||||||
|
bigtable_ledger_storage.get_confirmed_signatures_for_address(
|
||||||
|
&address,
|
||||||
|
before.as_ref(),
|
||||||
|
limit,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.map_err(|err| Error::invalid_params(format!("{}", err)))?;
|
||||||
|
results.append(&mut bigtable_results)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(results.into_iter().map(|x| x.into()).collect())
|
||||||
|
} else {
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_first_available_block(&self) -> Slot {
|
pub fn get_first_available_block(&self) -> Slot {
|
||||||
self.blockstore
|
let slot = self
|
||||||
|
.blockstore
|
||||||
.get_first_available_block()
|
.get_first_available_block()
|
||||||
.unwrap_or_default()
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||||
|
let bigtable_slot = self
|
||||||
|
.runtime_handle
|
||||||
|
.block_on(bigtable_ledger_storage.get_first_available_block())
|
||||||
|
.unwrap_or(None)
|
||||||
|
.unwrap_or(slot);
|
||||||
|
|
||||||
|
if bigtable_slot < slot {
|
||||||
|
return bigtable_slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slot
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_stake_activation(
|
pub fn get_stake_activation(
|
||||||
@@ -841,7 +986,7 @@ impl JsonRpcRequestProcessor {
|
|||||||
&self,
|
&self,
|
||||||
pubkey: &Pubkey,
|
pubkey: &Pubkey,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<RpcResponse<RpcTokenAmount>> {
|
) -> Result<RpcResponse<UiTokenAmount>> {
|
||||||
let bank = self.bank(commitment);
|
let bank = self.bank(commitment);
|
||||||
let account = bank.get_account(pubkey).ok_or_else(|| {
|
let account = bank.get_account(pubkey).ok_or_else(|| {
|
||||||
Error::invalid_params("Invalid param: could not find account".to_string())
|
Error::invalid_params("Invalid param: could not find account".to_string())
|
||||||
@@ -868,7 +1013,7 @@ impl JsonRpcRequestProcessor {
|
|||||||
&self,
|
&self,
|
||||||
mint: &Pubkey,
|
mint: &Pubkey,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<RpcResponse<RpcTokenAmount>> {
|
) -> Result<RpcResponse<UiTokenAmount>> {
|
||||||
let bank = self.bank(commitment);
|
let bank = self.bank(commitment);
|
||||||
let (mint_owner, decimals) = get_mint_owner_and_decimals(&bank, mint)?;
|
let (mint_owner, decimals) = get_mint_owner_and_decimals(&bank, mint)?;
|
||||||
if mint_owner != spl_token_id_v1_0() {
|
if mint_owner != spl_token_id_v1_0() {
|
||||||
@@ -976,12 +1121,17 @@ impl JsonRpcRequestProcessor {
|
|||||||
encoding: None,
|
encoding: None,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
let accounts = get_filtered_program_accounts(&bank, &token_program_id, filters)
|
let keyed_accounts = get_filtered_program_accounts(&bank, &token_program_id, filters);
|
||||||
.map(|(pubkey, account)| RpcKeyedAccount {
|
let accounts = if encoding == UiAccountEncoding::JsonParsed {
|
||||||
pubkey: pubkey.to_string(),
|
get_parsed_token_accounts(bank.clone(), keyed_accounts).collect()
|
||||||
account: UiAccount::encode(account, encoding.clone()),
|
} else {
|
||||||
})
|
keyed_accounts
|
||||||
.collect();
|
.map(|(pubkey, account)| RpcKeyedAccount {
|
||||||
|
pubkey: pubkey.to_string(),
|
||||||
|
account: UiAccount::encode(account, encoding.clone(), None),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
Ok(new_response(&bank, accounts))
|
Ok(new_response(&bank, accounts))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1022,12 +1172,17 @@ impl JsonRpcRequestProcessor {
|
|||||||
encoding: None,
|
encoding: None,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
let accounts = get_filtered_program_accounts(&bank, &token_program_id, filters)
|
let keyed_accounts = get_filtered_program_accounts(&bank, &token_program_id, filters);
|
||||||
.map(|(pubkey, account)| RpcKeyedAccount {
|
let accounts = if encoding == UiAccountEncoding::JsonParsed {
|
||||||
pubkey: pubkey.to_string(),
|
get_parsed_token_accounts(bank.clone(), keyed_accounts).collect()
|
||||||
account: UiAccount::encode(account, encoding.clone()),
|
} else {
|
||||||
})
|
keyed_accounts
|
||||||
.collect();
|
.map(|(pubkey, account)| RpcKeyedAccount {
|
||||||
|
pubkey: pubkey.to_string(),
|
||||||
|
account: UiAccount::encode(account, encoding.clone(), None),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
Ok(new_response(&bank, accounts))
|
Ok(new_response(&bank, accounts))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1081,6 +1236,47 @@ fn get_filtered_program_accounts(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_parsed_token_account(bank: Arc<Bank>, account: Account) -> Option<UiAccount> {
|
||||||
|
get_token_account_mint(&account.data)
|
||||||
|
.and_then(|mint_pubkey| get_mint_owner_and_decimals(&bank, &mint_pubkey).ok())
|
||||||
|
.map(|(_, decimals)| {
|
||||||
|
UiAccount::encode(
|
||||||
|
account,
|
||||||
|
UiAccountEncoding::JsonParsed,
|
||||||
|
Some(AccountAdditionalData {
|
||||||
|
spl_token_decimals: Some(decimals),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_parsed_token_accounts<I>(
|
||||||
|
bank: Arc<Bank>,
|
||||||
|
keyed_accounts: I,
|
||||||
|
) -> impl Iterator<Item = RpcKeyedAccount>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = (Pubkey, Account)>,
|
||||||
|
{
|
||||||
|
let mut mint_decimals: HashMap<Pubkey, u8> = HashMap::new();
|
||||||
|
keyed_accounts.filter_map(move |(pubkey, account)| {
|
||||||
|
get_token_account_mint(&account.data).map(|mint_pubkey| {
|
||||||
|
let spl_token_decimals = mint_decimals.get(&mint_pubkey).cloned().or_else(|| {
|
||||||
|
let (_, decimals) = get_mint_owner_and_decimals(&bank, &mint_pubkey).ok()?;
|
||||||
|
mint_decimals.insert(mint_pubkey, decimals);
|
||||||
|
Some(decimals)
|
||||||
|
});
|
||||||
|
RpcKeyedAccount {
|
||||||
|
pubkey: pubkey.to_string(),
|
||||||
|
account: UiAccount::encode(
|
||||||
|
account,
|
||||||
|
UiAccountEncoding::JsonParsed,
|
||||||
|
Some(AccountAdditionalData { spl_token_decimals }),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Analyze a passed Pubkey that may be a Token program id or Mint address to determine the program
|
/// Analyze a passed Pubkey that may be a Token program id or Mint address to determine the program
|
||||||
/// id and optional Mint
|
/// id and optional Mint
|
||||||
fn get_token_program_id_and_mint(
|
fn get_token_program_id_and_mint(
|
||||||
@@ -1134,16 +1330,6 @@ fn get_mint_decimals(data: &[u8]) -> Result<u8> {
|
|||||||
.map(|mint: &mut Mint| mint.decimals)
|
.map(|mint: &mut Mint| mint.decimals)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_amount_to_ui_amount(amount: u64, decimals: u8) -> RpcTokenAmount {
|
|
||||||
// Use `amount_to_ui_amount()` once spl_token is bumped to a version that supports it: https://github.com/solana-labs/solana-program-library/pull/211
|
|
||||||
let amount_decimals = amount as f64 / 10_usize.pow(decimals as u32) as f64;
|
|
||||||
RpcTokenAmount {
|
|
||||||
ui_amount: amount_decimals,
|
|
||||||
decimals,
|
|
||||||
amount: amount.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rpc]
|
#[rpc]
|
||||||
pub trait RpcSol {
|
pub trait RpcSol {
|
||||||
type Metadata;
|
type Metadata;
|
||||||
@@ -1406,6 +1592,14 @@ pub trait RpcSol {
|
|||||||
end_slot: Slot,
|
end_slot: Slot,
|
||||||
) -> Result<Vec<String>>;
|
) -> Result<Vec<String>>;
|
||||||
|
|
||||||
|
#[rpc(meta, name = "getConfirmedSignaturesForAddress2")]
|
||||||
|
fn get_confirmed_signatures_for_address2(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
address: String,
|
||||||
|
config: Option<RpcGetConfirmedSignaturesForAddress2Config>,
|
||||||
|
) -> Result<Vec<RpcConfirmedTransactionStatusWithSignature>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getFirstAvailableBlock")]
|
#[rpc(meta, name = "getFirstAvailableBlock")]
|
||||||
fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot>;
|
fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot>;
|
||||||
|
|
||||||
@@ -1427,7 +1621,7 @@ pub trait RpcSol {
|
|||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
pubkey_str: String,
|
pubkey_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<RpcResponse<RpcTokenAmount>>;
|
) -> Result<RpcResponse<UiTokenAmount>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getTokenSupply")]
|
#[rpc(meta, name = "getTokenSupply")]
|
||||||
fn get_token_supply(
|
fn get_token_supply(
|
||||||
@@ -1435,7 +1629,7 @@ pub trait RpcSol {
|
|||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
mint_str: String,
|
mint_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<RpcResponse<RpcTokenAmount>>;
|
) -> Result<RpcResponse<UiTokenAmount>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getTokenLargestAccounts")]
|
#[rpc(meta, name = "getTokenLargestAccounts")]
|
||||||
fn get_token_largest_accounts(
|
fn get_token_largest_accounts(
|
||||||
@@ -2036,6 +2230,34 @@ impl RpcSol for RpcSolImpl {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_confirmed_signatures_for_address2(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
address: String,
|
||||||
|
config: Option<RpcGetConfirmedSignaturesForAddress2Config>,
|
||||||
|
) -> Result<Vec<RpcConfirmedTransactionStatusWithSignature>> {
|
||||||
|
let address = verify_pubkey(address)?;
|
||||||
|
|
||||||
|
let config = config.unwrap_or_default();
|
||||||
|
let before = if let Some(before) = config.before {
|
||||||
|
Some(verify_signature(&before)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let limit = config
|
||||||
|
.limit
|
||||||
|
.unwrap_or(MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT);
|
||||||
|
|
||||||
|
if limit == 0 || limit > MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT {
|
||||||
|
return Err(Error::invalid_params(format!(
|
||||||
|
"Invalid limit; max {}",
|
||||||
|
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
meta.get_confirmed_signatures_for_address2(address, before, limit)
|
||||||
|
}
|
||||||
|
|
||||||
fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot> {
|
fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot> {
|
||||||
debug!("get_first_available_block rpc request received");
|
debug!("get_first_available_block rpc request received");
|
||||||
Ok(meta.get_first_available_block())
|
Ok(meta.get_first_available_block())
|
||||||
@@ -2060,7 +2282,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
pubkey_str: String,
|
pubkey_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<RpcResponse<RpcTokenAmount>> {
|
) -> Result<RpcResponse<UiTokenAmount>> {
|
||||||
debug!(
|
debug!(
|
||||||
"get_token_account_balance rpc request received: {:?}",
|
"get_token_account_balance rpc request received: {:?}",
|
||||||
pubkey_str
|
pubkey_str
|
||||||
@@ -2074,7 +2296,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
mint_str: String,
|
mint_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<RpcResponse<RpcTokenAmount>> {
|
) -> Result<RpcResponse<UiTokenAmount>> {
|
||||||
debug!("get_token_supply rpc request received: {:?}", mint_str);
|
debug!("get_token_supply rpc request received: {:?}", mint_str);
|
||||||
let mint = verify_pubkey(mint_str)?;
|
let mint = verify_pubkey(mint_str)?;
|
||||||
meta.get_token_supply(&mint, commitment)
|
meta.get_token_supply(&mint, commitment)
|
||||||
@@ -2344,6 +2566,8 @@ pub mod tests {
|
|||||||
RpcHealth::stub(),
|
RpcHealth::stub(),
|
||||||
cluster_info.clone(),
|
cluster_info.clone(),
|
||||||
Hash::default(),
|
Hash::default(),
|
||||||
|
&runtime::Runtime::new().unwrap(),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
||||||
|
|
||||||
@@ -3486,6 +3710,8 @@ pub mod tests {
|
|||||||
RpcHealth::stub(),
|
RpcHealth::stub(),
|
||||||
cluster_info,
|
cluster_info,
|
||||||
Hash::default(),
|
Hash::default(),
|
||||||
|
&runtime::Runtime::new().unwrap(),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
||||||
|
|
||||||
@@ -3525,6 +3751,8 @@ pub mod tests {
|
|||||||
health.clone(),
|
health.clone(),
|
||||||
cluster_info,
|
cluster_info,
|
||||||
Hash::default(),
|
Hash::default(),
|
||||||
|
&runtime::Runtime::new().unwrap(),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
||||||
|
|
||||||
@@ -3705,6 +3933,8 @@ pub mod tests {
|
|||||||
RpcHealth::stub(),
|
RpcHealth::stub(),
|
||||||
cluster_info,
|
cluster_info,
|
||||||
Hash::default(),
|
Hash::default(),
|
||||||
|
&runtime::Runtime::new().unwrap(),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
||||||
assert_eq!(request_processor.validator_exit(), false);
|
assert_eq!(request_processor.validator_exit(), false);
|
||||||
@@ -3732,6 +3962,8 @@ pub mod tests {
|
|||||||
RpcHealth::stub(),
|
RpcHealth::stub(),
|
||||||
cluster_info,
|
cluster_info,
|
||||||
Hash::default(),
|
Hash::default(),
|
||||||
|
&runtime::Runtime::new().unwrap(),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
||||||
assert_eq!(request_processor.validator_exit(), true);
|
assert_eq!(request_processor.validator_exit(), true);
|
||||||
@@ -3821,6 +4053,8 @@ pub mod tests {
|
|||||||
RpcHealth::stub(),
|
RpcHealth::stub(),
|
||||||
cluster_info,
|
cluster_info,
|
||||||
Hash::default(),
|
Hash::default(),
|
||||||
|
&runtime::Runtime::new().unwrap(),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
SendTransactionService::new(tpu_address, &bank_forks, &exit, receiver);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -4436,7 +4670,7 @@ pub mod tests {
|
|||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||||
.expect("actual response deserialization");
|
.expect("actual response deserialization");
|
||||||
let balance: RpcTokenAmount =
|
let balance: UiTokenAmount =
|
||||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||||
let error = f64::EPSILON;
|
let error = f64::EPSILON;
|
||||||
assert!((balance.ui_amount - 4.2).abs() < error);
|
assert!((balance.ui_amount - 4.2).abs() < error);
|
||||||
@@ -4464,7 +4698,7 @@ pub mod tests {
|
|||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||||
.expect("actual response deserialization");
|
.expect("actual response deserialization");
|
||||||
let supply: RpcTokenAmount =
|
let supply: UiTokenAmount =
|
||||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||||
let error = f64::EPSILON;
|
let error = f64::EPSILON;
|
||||||
assert!((supply.ui_amount - 2.0 * 4.2).abs() < error);
|
assert!((supply.ui_amount - 2.0 * 4.2).abs() < error);
|
||||||
@@ -4724,7 +4958,7 @@ pub mod tests {
|
|||||||
vec![
|
vec![
|
||||||
RpcTokenAccountBalance {
|
RpcTokenAccountBalance {
|
||||||
address: token_with_different_mint_pubkey.to_string(),
|
address: token_with_different_mint_pubkey.to_string(),
|
||||||
amount: RpcTokenAmount {
|
amount: UiTokenAmount {
|
||||||
ui_amount: 0.42,
|
ui_amount: 0.42,
|
||||||
decimals: 2,
|
decimals: 2,
|
||||||
amount: "42".to_string(),
|
amount: "42".to_string(),
|
||||||
@@ -4732,7 +4966,7 @@ pub mod tests {
|
|||||||
},
|
},
|
||||||
RpcTokenAccountBalance {
|
RpcTokenAccountBalance {
|
||||||
address: token_with_smaller_balance.to_string(),
|
address: token_with_smaller_balance.to_string(),
|
||||||
amount: RpcTokenAmount {
|
amount: UiTokenAmount {
|
||||||
ui_amount: 0.1,
|
ui_amount: 0.1,
|
||||||
decimals: 2,
|
decimals: 2,
|
||||||
amount: "10".to_string(),
|
amount: "10".to_string(),
|
||||||
|
@@ -676,7 +676,8 @@ mod tests {
|
|||||||
.get_account(&nonce_account.pubkey())
|
.get_account(&nonce_account.pubkey())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.data;
|
.data;
|
||||||
let expected_data = parse_account_data(&system_program::id(), &expected_data).unwrap();
|
let expected_data =
|
||||||
|
parse_account_data(&system_program::id(), &expected_data, None).unwrap();
|
||||||
let expected = json!({
|
let expected = json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "accountNotification",
|
"method": "accountNotification",
|
||||||
|
@@ -23,7 +23,7 @@ use std::{
|
|||||||
sync::{mpsc::channel, Arc, RwLock},
|
sync::{mpsc::channel, Arc, RwLock},
|
||||||
thread::{self, Builder, JoinHandle},
|
thread::{self, Builder, JoinHandle},
|
||||||
};
|
};
|
||||||
use tokio::prelude::Future;
|
use tokio::runtime;
|
||||||
|
|
||||||
pub struct JsonRpcService {
|
pub struct JsonRpcService {
|
||||||
thread_hdl: JoinHandle<()>,
|
thread_hdl: JoinHandle<()>,
|
||||||
@@ -32,6 +32,7 @@ pub struct JsonRpcService {
|
|||||||
pub request_processor: JsonRpcRequestProcessor, // Used only by test_rpc_new()...
|
pub request_processor: JsonRpcRequestProcessor, // Used only by test_rpc_new()...
|
||||||
|
|
||||||
close_handle: Option<CloseHandle>,
|
close_handle: Option<CloseHandle>,
|
||||||
|
runtime: runtime::Runtime,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RpcRequestMiddleware {
|
struct RpcRequestMiddleware {
|
||||||
@@ -97,6 +98,9 @@ impl RpcRequestMiddleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn process_file_get(&self, path: &str) -> RequestMiddlewareAction {
|
fn process_file_get(&self, path: &str) -> RequestMiddlewareAction {
|
||||||
|
// Stuck on tokio 0.1 until the jsonrpc-http-server crate upgrades to tokio 0.2
|
||||||
|
use tokio_01::prelude::*;
|
||||||
|
|
||||||
let stem = path.split_at(1).1; // Drop leading '/' from path
|
let stem = path.split_at(1).1; // Drop leading '/' from path
|
||||||
let filename = {
|
let filename = {
|
||||||
match path {
|
match path {
|
||||||
@@ -115,10 +119,10 @@ impl RpcRequestMiddleware {
|
|||||||
RequestMiddlewareAction::Respond {
|
RequestMiddlewareAction::Respond {
|
||||||
should_validate_hosts: true,
|
should_validate_hosts: true,
|
||||||
response: Box::new(
|
response: Box::new(
|
||||||
tokio_fs::file::File::open(filename)
|
tokio_fs_01::file::File::open(filename)
|
||||||
.and_then(|file| {
|
.and_then(|file| {
|
||||||
let buf: Vec<u8> = Vec::new();
|
let buf: Vec<u8> = Vec::new();
|
||||||
tokio_io::io::read_to_end(file, buf)
|
tokio_io_01::io::read_to_end(file, buf)
|
||||||
.and_then(|item| Ok(hyper::Response::new(item.1.into())))
|
.and_then(|item| Ok(hyper::Response::new(item.1.into())))
|
||||||
.or_else(|_| Ok(RpcRequestMiddleware::internal_server_error()))
|
.or_else(|_| Ok(RpcRequestMiddleware::internal_server_error()))
|
||||||
})
|
})
|
||||||
@@ -249,6 +253,28 @@ impl JsonRpcService {
|
|||||||
));
|
));
|
||||||
|
|
||||||
let tpu_address = cluster_info.my_contact_info().tpu;
|
let tpu_address = cluster_info.my_contact_info().tpu;
|
||||||
|
let mut runtime = runtime::Builder::new()
|
||||||
|
.threaded_scheduler()
|
||||||
|
.thread_name("rpc-runtime")
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.expect("Runtime");
|
||||||
|
|
||||||
|
let bigtable_ledger_storage = if config.enable_bigtable_ledger_storage {
|
||||||
|
runtime
|
||||||
|
.block_on(solana_storage_bigtable::LedgerStorage::new(false))
|
||||||
|
.map(|x| {
|
||||||
|
info!("BigTable ledger storage initialized");
|
||||||
|
Some(x)
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
error!("Failed to initialize BigTable ledger storage: {:?}", err);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let (request_processor, receiver) = JsonRpcRequestProcessor::new(
|
let (request_processor, receiver) = JsonRpcRequestProcessor::new(
|
||||||
config,
|
config,
|
||||||
bank_forks.clone(),
|
bank_forks.clone(),
|
||||||
@@ -258,6 +284,8 @@ impl JsonRpcService {
|
|||||||
health.clone(),
|
health.clone(),
|
||||||
cluster_info,
|
cluster_info,
|
||||||
genesis_hash,
|
genesis_hash,
|
||||||
|
&runtime,
|
||||||
|
bigtable_ledger_storage,
|
||||||
);
|
);
|
||||||
|
|
||||||
let exit_send_transaction_service = Arc::new(AtomicBool::new(false));
|
let exit_send_transaction_service = Arc::new(AtomicBool::new(false));
|
||||||
@@ -325,6 +353,7 @@ impl JsonRpcService {
|
|||||||
.register_exit(Box::new(move || close_handle_.close()));
|
.register_exit(Box::new(move || close_handle_.close()));
|
||||||
Self {
|
Self {
|
||||||
thread_hdl,
|
thread_hdl,
|
||||||
|
runtime,
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
request_processor: test_request_processor,
|
request_processor: test_request_processor,
|
||||||
close_handle: Some(close_handle),
|
close_handle: Some(close_handle),
|
||||||
@@ -338,6 +367,7 @@ impl JsonRpcService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn join(self) -> thread::Result<()> {
|
pub fn join(self) -> thread::Result<()> {
|
||||||
|
self.runtime.shutdown_background();
|
||||||
self.thread_hdl.join()
|
self.thread_hdl.join()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
||||||
|
|
||||||
|
use crate::rpc::{get_parsed_token_account, get_parsed_token_accounts};
|
||||||
use core::hash::Hash;
|
use core::hash::Hash;
|
||||||
use jsonrpc_core::futures::Future;
|
use jsonrpc_core::futures::Future;
|
||||||
use jsonrpc_pubsub::{
|
use jsonrpc_pubsub::{
|
||||||
@@ -7,7 +8,7 @@ use jsonrpc_pubsub::{
|
|||||||
SubscriptionId,
|
SubscriptionId,
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
use solana_account_decoder::{parse_token::spl_token_id_v1_0, UiAccount, UiAccountEncoding};
|
||||||
use solana_client::{
|
use solana_client::{
|
||||||
rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},
|
rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},
|
||||||
rpc_filter::RpcFilterType,
|
rpc_filter::RpcFilterType,
|
||||||
@@ -38,7 +39,9 @@ use std::{
|
|||||||
iter,
|
iter,
|
||||||
sync::{Arc, Mutex, RwLock},
|
sync::{Arc, Mutex, RwLock},
|
||||||
};
|
};
|
||||||
use tokio::runtime::{Builder as RuntimeBuilder, Runtime, TaskExecutor};
|
|
||||||
|
// Stuck on tokio 0.1 until the jsonrpc-pubsub crate upgrades to tokio 0.2
|
||||||
|
use tokio_01::runtime::{Builder as RuntimeBuilder, Runtime, TaskExecutor};
|
||||||
|
|
||||||
const RECEIVE_DELAY_MILLIS: u64 = 100;
|
const RECEIVE_DELAY_MILLIS: u64 = 100;
|
||||||
|
|
||||||
@@ -176,7 +179,7 @@ where
|
|||||||
K: Eq + Hash + Clone + Copy,
|
K: Eq + Hash + Clone + Copy,
|
||||||
S: Clone + Serialize,
|
S: Clone + Serialize,
|
||||||
B: Fn(&Bank, &K) -> X,
|
B: Fn(&Bank, &K) -> X,
|
||||||
F: Fn(X, Slot, Option<T>) -> (Box<dyn Iterator<Item = S>>, Slot),
|
F: Fn(X, Slot, Option<T>, Option<Arc<Bank>>) -> (Box<dyn Iterator<Item = S>>, Slot),
|
||||||
X: Clone + Serialize + Default,
|
X: Clone + Serialize + Default,
|
||||||
T: Clone,
|
T: Clone,
|
||||||
{
|
{
|
||||||
@@ -200,16 +203,18 @@ where
|
|||||||
commitment_slots.highest_confirmed_slot
|
commitment_slots.highest_confirmed_slot
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let results = {
|
let bank = bank_forks.read().unwrap().get(slot).cloned();
|
||||||
let bank_forks = bank_forks.read().unwrap();
|
let results = bank
|
||||||
bank_forks
|
.clone()
|
||||||
.get(slot)
|
.map(|desired_bank| bank_method(&desired_bank, hashmap_key))
|
||||||
.map(|desired_bank| bank_method(&desired_bank, hashmap_key))
|
.unwrap_or_default();
|
||||||
.unwrap_or_default()
|
|
||||||
};
|
|
||||||
let mut w_last_notified_slot = last_notified_slot.write().unwrap();
|
let mut w_last_notified_slot = last_notified_slot.write().unwrap();
|
||||||
let (filter_results, result_slot) =
|
let (filter_results, result_slot) = filter_results(
|
||||||
filter_results(results, *w_last_notified_slot, config.as_ref().cloned());
|
results,
|
||||||
|
*w_last_notified_slot,
|
||||||
|
config.as_ref().cloned(),
|
||||||
|
bank,
|
||||||
|
);
|
||||||
for result in filter_results {
|
for result in filter_results {
|
||||||
notifier.notify(
|
notifier.notify(
|
||||||
Response {
|
Response {
|
||||||
@@ -242,16 +247,24 @@ fn filter_account_result(
|
|||||||
result: Option<(Account, Slot)>,
|
result: Option<(Account, Slot)>,
|
||||||
last_notified_slot: Slot,
|
last_notified_slot: Slot,
|
||||||
encoding: Option<UiAccountEncoding>,
|
encoding: Option<UiAccountEncoding>,
|
||||||
|
bank: Option<Arc<Bank>>,
|
||||||
) -> (Box<dyn Iterator<Item = UiAccount>>, Slot) {
|
) -> (Box<dyn Iterator<Item = UiAccount>>, Slot) {
|
||||||
if let Some((account, fork)) = result {
|
if let Some((account, fork)) = result {
|
||||||
// If fork < last_notified_slot this means that we last notified for a fork
|
// If fork < last_notified_slot this means that we last notified for a fork
|
||||||
// and should notify that the account state has been reverted.
|
// and should notify that the account state has been reverted.
|
||||||
if fork != last_notified_slot {
|
if fork != last_notified_slot {
|
||||||
let encoding = encoding.unwrap_or(UiAccountEncoding::Binary);
|
let encoding = encoding.unwrap_or(UiAccountEncoding::Binary);
|
||||||
return (
|
if account.owner == spl_token_id_v1_0() && encoding == UiAccountEncoding::JsonParsed {
|
||||||
Box::new(iter::once(UiAccount::encode(account, encoding))),
|
let bank = bank.unwrap(); // If result.is_some(), bank must also be Some
|
||||||
fork,
|
if let Some(ui_account) = get_parsed_token_account(bank, account) {
|
||||||
);
|
return (Box::new(iter::once(ui_account)), fork);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
Box::new(iter::once(UiAccount::encode(account, encoding, None))),
|
||||||
|
fork,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Box::new(iter::empty()), last_notified_slot)
|
(Box::new(iter::empty()), last_notified_slot)
|
||||||
@@ -261,6 +274,7 @@ fn filter_signature_result(
|
|||||||
result: Option<transaction::Result<()>>,
|
result: Option<transaction::Result<()>>,
|
||||||
last_notified_slot: Slot,
|
last_notified_slot: Slot,
|
||||||
_config: Option<()>,
|
_config: Option<()>,
|
||||||
|
_bank: Option<Arc<Bank>>,
|
||||||
) -> (Box<dyn Iterator<Item = RpcSignatureResult>>, Slot) {
|
) -> (Box<dyn Iterator<Item = RpcSignatureResult>>, Slot) {
|
||||||
(
|
(
|
||||||
Box::new(
|
Box::new(
|
||||||
@@ -276,27 +290,30 @@ fn filter_program_results(
|
|||||||
accounts: Vec<(Pubkey, Account)>,
|
accounts: Vec<(Pubkey, Account)>,
|
||||||
last_notified_slot: Slot,
|
last_notified_slot: Slot,
|
||||||
config: Option<ProgramConfig>,
|
config: Option<ProgramConfig>,
|
||||||
|
bank: Option<Arc<Bank>>,
|
||||||
) -> (Box<dyn Iterator<Item = RpcKeyedAccount>>, Slot) {
|
) -> (Box<dyn Iterator<Item = RpcKeyedAccount>>, Slot) {
|
||||||
let config = config.unwrap_or_default();
|
let config = config.unwrap_or_default();
|
||||||
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
||||||
let filters = config.filters;
|
let filters = config.filters;
|
||||||
(
|
let keyed_accounts = accounts.into_iter().filter(move |(_, account)| {
|
||||||
Box::new(
|
filters.iter().all(|filter_type| match filter_type {
|
||||||
accounts
|
RpcFilterType::DataSize(size) => account.data.len() as u64 == *size,
|
||||||
.into_iter()
|
RpcFilterType::Memcmp(compare) => compare.bytes_match(&account.data),
|
||||||
.filter(move |(_, account)| {
|
})
|
||||||
filters.iter().all(|filter_type| match filter_type {
|
});
|
||||||
RpcFilterType::DataSize(size) => account.data.len() as u64 == *size,
|
let accounts: Box<dyn Iterator<Item = RpcKeyedAccount>> =
|
||||||
RpcFilterType::Memcmp(compare) => compare.bytes_match(&account.data),
|
if encoding == UiAccountEncoding::JsonParsed {
|
||||||
})
|
let bank = bank.unwrap(); // If !accounts.is_empty(), bank must be Some
|
||||||
})
|
Box::new(get_parsed_token_accounts(bank, keyed_accounts))
|
||||||
.map(move |(pubkey, account)| RpcKeyedAccount {
|
} else {
|
||||||
|
Box::new(
|
||||||
|
keyed_accounts.map(move |(pubkey, account)| RpcKeyedAccount {
|
||||||
pubkey: pubkey.to_string(),
|
pubkey: pubkey.to_string(),
|
||||||
account: UiAccount::encode(account, encoding.clone()),
|
account: UiAccount::encode(account, encoding.clone(), None),
|
||||||
}),
|
}),
|
||||||
),
|
)
|
||||||
last_notified_slot,
|
};
|
||||||
)
|
(accounts, last_notified_slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -858,7 +875,7 @@ impl RpcSubscriptions {
|
|||||||
&subscriptions.gossip_account_subscriptions,
|
&subscriptions.gossip_account_subscriptions,
|
||||||
&subscriptions.gossip_program_subscriptions,
|
&subscriptions.gossip_program_subscriptions,
|
||||||
&subscriptions.gossip_signature_subscriptions,
|
&subscriptions.gossip_signature_subscriptions,
|
||||||
&bank_forks,
|
bank_forks,
|
||||||
&commitment_slots,
|
&commitment_slots,
|
||||||
¬ifier,
|
¬ifier,
|
||||||
);
|
);
|
||||||
@@ -879,7 +896,7 @@ impl RpcSubscriptions {
|
|||||||
for pubkey in &pubkeys {
|
for pubkey in &pubkeys {
|
||||||
Self::check_account(
|
Self::check_account(
|
||||||
pubkey,
|
pubkey,
|
||||||
&bank_forks,
|
bank_forks,
|
||||||
account_subscriptions.clone(),
|
account_subscriptions.clone(),
|
||||||
¬ifier,
|
¬ifier,
|
||||||
&commitment_slots,
|
&commitment_slots,
|
||||||
@@ -893,7 +910,7 @@ impl RpcSubscriptions {
|
|||||||
for program_id in &programs {
|
for program_id in &programs {
|
||||||
Self::check_program(
|
Self::check_program(
|
||||||
program_id,
|
program_id,
|
||||||
&bank_forks,
|
bank_forks,
|
||||||
program_subscriptions.clone(),
|
program_subscriptions.clone(),
|
||||||
¬ifier,
|
¬ifier,
|
||||||
&commitment_slots,
|
&commitment_slots,
|
||||||
@@ -907,7 +924,7 @@ impl RpcSubscriptions {
|
|||||||
for signature in &signatures {
|
for signature in &signatures {
|
||||||
Self::check_signature(
|
Self::check_signature(
|
||||||
signature,
|
signature,
|
||||||
&bank_forks,
|
bank_forks,
|
||||||
signature_subscriptions.clone(),
|
signature_subscriptions.clone(),
|
||||||
¬ifier,
|
¬ifier,
|
||||||
&commitment_slots,
|
&commitment_slots,
|
||||||
@@ -950,7 +967,7 @@ pub(crate) mod tests {
|
|||||||
system_transaction,
|
system_transaction,
|
||||||
};
|
};
|
||||||
use std::{fmt::Debug, sync::mpsc::channel, time::Instant};
|
use std::{fmt::Debug, sync::mpsc::channel, time::Instant};
|
||||||
use tokio::{prelude::FutureExt, runtime::Runtime, timer::Delay};
|
use tokio_01::{prelude::FutureExt, runtime::Runtime, timer::Delay};
|
||||||
|
|
||||||
pub(crate) fn robust_poll_or_panic<T: Debug + Send + 'static>(
|
pub(crate) fn robust_poll_or_panic<T: Debug + Send + 'static>(
|
||||||
receiver: futures::sync::mpsc::Receiver<T>,
|
receiver: futures::sync::mpsc::Receiver<T>,
|
||||||
|
@@ -13,11 +13,11 @@ use crate::{
|
|||||||
sigverify_stage::SigVerifyStage,
|
sigverify_stage::SigVerifyStage,
|
||||||
};
|
};
|
||||||
use crossbeam_channel::unbounded;
|
use crossbeam_channel::unbounded;
|
||||||
use solana_ledger::{
|
use solana_ledger::{blockstore::Blockstore, blockstore_processor::TransactionStatusSender};
|
||||||
blockstore::Blockstore,
|
use solana_runtime::{
|
||||||
blockstore_processor::{ReplayVotesReceiver, TransactionStatusSender},
|
bank_forks::BankForks,
|
||||||
|
vote_sender_types::{ReplayVoteReceiver, ReplayVoteSender},
|
||||||
};
|
};
|
||||||
use solana_runtime::bank_forks::BankForks;
|
|
||||||
use std::{
|
use std::{
|
||||||
net::UdpSocket,
|
net::UdpSocket,
|
||||||
sync::{
|
sync::{
|
||||||
@@ -55,7 +55,8 @@ impl Tpu {
|
|||||||
vote_tracker: Arc<VoteTracker>,
|
vote_tracker: Arc<VoteTracker>,
|
||||||
bank_forks: Arc<RwLock<BankForks>>,
|
bank_forks: Arc<RwLock<BankForks>>,
|
||||||
verified_vote_sender: VerifiedVoteSender,
|
verified_vote_sender: VerifiedVoteSender,
|
||||||
replay_votes_receiver: ReplayVotesReceiver,
|
replay_vote_receiver: ReplayVoteReceiver,
|
||||||
|
replay_vote_sender: ReplayVoteSender,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (packet_sender, packet_receiver) = channel();
|
let (packet_sender, packet_receiver) = channel();
|
||||||
let fetch_stage = FetchStage::new_with_sender(
|
let fetch_stage = FetchStage::new_with_sender(
|
||||||
@@ -82,7 +83,7 @@ impl Tpu {
|
|||||||
bank_forks,
|
bank_forks,
|
||||||
subscriptions.clone(),
|
subscriptions.clone(),
|
||||||
verified_vote_sender,
|
verified_vote_sender,
|
||||||
replay_votes_receiver,
|
replay_vote_receiver,
|
||||||
blockstore.clone(),
|
blockstore.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -92,6 +93,7 @@ impl Tpu {
|
|||||||
verified_receiver,
|
verified_receiver,
|
||||||
verified_vote_packets_receiver,
|
verified_vote_packets_receiver,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
|
replay_vote_sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
let broadcast_stage = broadcast_type.new_broadcast_stage(
|
let broadcast_stage = broadcast_type.new_broadcast_stage(
|
||||||
|
@@ -57,7 +57,7 @@ impl TransactionStatusService {
|
|||||||
} = write_transaction_status_receiver.recv_timeout(Duration::from_secs(1))?;
|
} = write_transaction_status_receiver.recv_timeout(Duration::from_secs(1))?;
|
||||||
|
|
||||||
let slot = bank.slot();
|
let slot = bank.slot();
|
||||||
for (((transaction, (status, hash_age_kind)), pre_balances), post_balances) in
|
for ((((_, transaction), (status, hash_age_kind)), pre_balances), post_balances) in
|
||||||
OrderedIterator::new(&transactions, iteration_order.as_deref())
|
OrderedIterator::new(&transactions, iteration_order.as_deref())
|
||||||
.zip(statuses)
|
.zip(statuses)
|
||||||
.zip(balances.pre_balances)
|
.zip(balances.pre_balances)
|
||||||
|
@@ -21,12 +21,12 @@ use crate::{
|
|||||||
use crossbeam_channel::unbounded;
|
use crossbeam_channel::unbounded;
|
||||||
use solana_ledger::{
|
use solana_ledger::{
|
||||||
blockstore::{Blockstore, CompletedSlotsReceiver},
|
blockstore::{Blockstore, CompletedSlotsReceiver},
|
||||||
blockstore_processor::{ReplayVotesSender, TransactionStatusSender},
|
blockstore_processor::TransactionStatusSender,
|
||||||
leader_schedule_cache::LeaderScheduleCache,
|
leader_schedule_cache::LeaderScheduleCache,
|
||||||
};
|
};
|
||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
bank_forks::BankForks, commitment::BlockCommitmentCache,
|
bank_forks::BankForks, commitment::BlockCommitmentCache,
|
||||||
snapshot_package::AccountsPackageSender,
|
snapshot_package::AccountsPackageSender, vote_sender_types::ReplayVoteSender,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
@@ -98,7 +98,7 @@ impl Tvu {
|
|||||||
vote_tracker: Arc<VoteTracker>,
|
vote_tracker: Arc<VoteTracker>,
|
||||||
retransmit_slots_sender: RetransmitSlotsSender,
|
retransmit_slots_sender: RetransmitSlotsSender,
|
||||||
verified_vote_receiver: VerifiedVoteReceiver,
|
verified_vote_receiver: VerifiedVoteReceiver,
|
||||||
replay_votes_sender: ReplayVotesSender,
|
replay_vote_sender: ReplayVoteSender,
|
||||||
tvu_config: TvuConfig,
|
tvu_config: TvuConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let keypair: Arc<Keypair> = cluster_info.keypair.clone();
|
let keypair: Arc<Keypair> = cluster_info.keypair.clone();
|
||||||
@@ -199,7 +199,7 @@ impl Tvu {
|
|||||||
cluster_slots,
|
cluster_slots,
|
||||||
retransmit_slots_sender,
|
retransmit_slots_sender,
|
||||||
duplicate_slots_reset_receiver,
|
duplicate_slots_reset_receiver,
|
||||||
replay_votes_sender,
|
replay_vote_sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
let ledger_cleanup_service = tvu_config.max_ledger_shreds.map(|max_ledger_shreds| {
|
let ledger_cleanup_service = tvu_config.max_ledger_shreds.map(|max_ledger_shreds| {
|
||||||
@@ -285,7 +285,7 @@ pub mod tests {
|
|||||||
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
|
||||||
let (retransmit_slots_sender, _retransmit_slots_receiver) = unbounded();
|
let (retransmit_slots_sender, _retransmit_slots_receiver) = unbounded();
|
||||||
let (_verified_vote_sender, verified_vote_receiver) = unbounded();
|
let (_verified_vote_sender, verified_vote_receiver) = unbounded();
|
||||||
let (replay_votes_sender, _replay_votes_receiver) = unbounded();
|
let (replay_vote_sender, _replay_vote_receiver) = unbounded();
|
||||||
let bank_forks = Arc::new(RwLock::new(bank_forks));
|
let bank_forks = Arc::new(RwLock::new(bank_forks));
|
||||||
let tvu = Tvu::new(
|
let tvu = Tvu::new(
|
||||||
&vote_keypair.pubkey(),
|
&vote_keypair.pubkey(),
|
||||||
@@ -319,7 +319,7 @@ pub mod tests {
|
|||||||
Arc::new(VoteTracker::new(&bank)),
|
Arc::new(VoteTracker::new(&bank)),
|
||||||
retransmit_slots_sender,
|
retransmit_slots_sender,
|
||||||
verified_vote_receiver,
|
verified_vote_receiver,
|
||||||
replay_votes_sender,
|
replay_vote_sender,
|
||||||
TvuConfig::default(),
|
TvuConfig::default(),
|
||||||
);
|
);
|
||||||
exit.store(true, Ordering::Relaxed);
|
exit.store(true, Ordering::Relaxed);
|
||||||
|
@@ -27,7 +27,7 @@ use solana_ledger::{
|
|||||||
bank_forks_utils,
|
bank_forks_utils,
|
||||||
blockstore::{Blockstore, CompletedSlotsReceiver, PurgeType},
|
blockstore::{Blockstore, CompletedSlotsReceiver, PurgeType},
|
||||||
blockstore_db::BlockstoreRecoveryMode,
|
blockstore_db::BlockstoreRecoveryMode,
|
||||||
blockstore_processor::{self, ReplayVotesSender, TransactionStatusSender},
|
blockstore_processor::{self, TransactionStatusSender},
|
||||||
create_new_tmp_ledger,
|
create_new_tmp_ledger,
|
||||||
leader_schedule::FixedSchedule,
|
leader_schedule::FixedSchedule,
|
||||||
leader_schedule_cache::LeaderScheduleCache,
|
leader_schedule_cache::LeaderScheduleCache,
|
||||||
@@ -223,7 +223,7 @@ impl Validator {
|
|||||||
validator_exit.register_exit(Box::new(move || exit_.store(true, Ordering::Relaxed)));
|
validator_exit.register_exit(Box::new(move || exit_.store(true, Ordering::Relaxed)));
|
||||||
let validator_exit = Arc::new(RwLock::new(Some(validator_exit)));
|
let validator_exit = Arc::new(RwLock::new(Some(validator_exit)));
|
||||||
|
|
||||||
let (replay_votes_sender, replay_votes_receiver) = unbounded();
|
let (replay_vote_sender, replay_vote_receiver) = unbounded();
|
||||||
let (
|
let (
|
||||||
genesis_config,
|
genesis_config,
|
||||||
bank_forks,
|
bank_forks,
|
||||||
@@ -238,7 +238,7 @@ impl Validator {
|
|||||||
rewards_recorder_sender,
|
rewards_recorder_sender,
|
||||||
rewards_recorder_service,
|
rewards_recorder_service,
|
||||||
},
|
},
|
||||||
) = new_banks_from_ledger(config, ledger_path, poh_verify, &exit, &replay_votes_sender);
|
) = new_banks_from_ledger(config, ledger_path, poh_verify, &exit);
|
||||||
|
|
||||||
let leader_schedule_cache = Arc::new(leader_schedule_cache);
|
let leader_schedule_cache = Arc::new(leader_schedule_cache);
|
||||||
let bank = bank_forks.working_bank();
|
let bank = bank_forks.working_bank();
|
||||||
@@ -453,7 +453,7 @@ impl Validator {
|
|||||||
vote_tracker.clone(),
|
vote_tracker.clone(),
|
||||||
retransmit_slots_sender,
|
retransmit_slots_sender,
|
||||||
verified_vote_receiver,
|
verified_vote_receiver,
|
||||||
replay_votes_sender,
|
replay_vote_sender.clone(),
|
||||||
TvuConfig {
|
TvuConfig {
|
||||||
max_ledger_shreds: config.max_ledger_shreds,
|
max_ledger_shreds: config.max_ledger_shreds,
|
||||||
halt_on_trusted_validators_accounts_hash_mismatch: config
|
halt_on_trusted_validators_accounts_hash_mismatch: config
|
||||||
@@ -481,7 +481,8 @@ impl Validator {
|
|||||||
vote_tracker,
|
vote_tracker,
|
||||||
bank_forks,
|
bank_forks,
|
||||||
verified_vote_sender,
|
verified_vote_sender,
|
||||||
replay_votes_receiver,
|
replay_vote_receiver,
|
||||||
|
replay_vote_sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
datapoint_info!("validator-new", ("id", id.to_string(), String));
|
datapoint_info!("validator-new", ("id", id.to_string(), String));
|
||||||
@@ -574,7 +575,6 @@ fn new_banks_from_ledger(
|
|||||||
ledger_path: &Path,
|
ledger_path: &Path,
|
||||||
poh_verify: bool,
|
poh_verify: bool,
|
||||||
exit: &Arc<AtomicBool>,
|
exit: &Arc<AtomicBool>,
|
||||||
replay_votes_sender: &ReplayVotesSender,
|
|
||||||
) -> (
|
) -> (
|
||||||
GenesisConfig,
|
GenesisConfig,
|
||||||
BankForks,
|
BankForks,
|
||||||
@@ -636,7 +636,6 @@ fn new_banks_from_ledger(
|
|||||||
transaction_history_services
|
transaction_history_services
|
||||||
.transaction_status_sender
|
.transaction_status_sender
|
||||||
.clone(),
|
.clone(),
|
||||||
Some(&replay_votes_sender),
|
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|err| {
|
.unwrap_or_else(|err| {
|
||||||
error!("Failed to load ledger: {:?}", err);
|
error!("Failed to load ledger: {:?}", err);
|
||||||
|
@@ -26,7 +26,7 @@ use std::{
|
|||||||
thread::sleep,
|
thread::sleep,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use tokio::runtime::Runtime;
|
use tokio_01::runtime::Runtime;
|
||||||
|
|
||||||
macro_rules! json_req {
|
macro_rules! json_req {
|
||||||
($method: expr, $params: expr) => {{
|
($method: expr, $params: expr) => {{
|
||||||
@@ -189,7 +189,7 @@ fn test_rpc_subscriptions() {
|
|||||||
.and_then(move |client| {
|
.and_then(move |client| {
|
||||||
for sig in signature_set {
|
for sig in signature_set {
|
||||||
let status_sender = status_sender.clone();
|
let status_sender = status_sender.clone();
|
||||||
tokio::spawn(
|
tokio_01::spawn(
|
||||||
client
|
client
|
||||||
.signature_subscribe(sig.clone(), None)
|
.signature_subscribe(sig.clone(), None)
|
||||||
.and_then(move |sig_stream| {
|
.and_then(move |sig_stream| {
|
||||||
@@ -203,7 +203,7 @@ fn test_rpc_subscriptions() {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
tokio::spawn(
|
tokio_01::spawn(
|
||||||
client
|
client
|
||||||
.slot_subscribe()
|
.slot_subscribe()
|
||||||
.and_then(move |slot_stream| {
|
.and_then(move |slot_stream| {
|
||||||
@@ -218,7 +218,7 @@ fn test_rpc_subscriptions() {
|
|||||||
);
|
);
|
||||||
for pubkey in account_set {
|
for pubkey in account_set {
|
||||||
let account_sender = account_sender.clone();
|
let account_sender = account_sender.clone();
|
||||||
tokio::spawn(
|
tokio_01::spawn(
|
||||||
client
|
client
|
||||||
.account_subscribe(pubkey, None)
|
.account_subscribe(pubkey, None)
|
||||||
.and_then(move |account_stream| {
|
.and_then(move |account_stream| {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-crate-features"
|
name = "solana-crate-features"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana Crate Features"
|
description = "Solana Crate Features"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
|
@@ -30,6 +30,16 @@ module.exports = {
|
|||||||
label: "Validate",
|
label: "Validate",
|
||||||
position: "left",
|
position: "left",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
to: "integrations/exchange",
|
||||||
|
label: "Integrate",
|
||||||
|
position: "left",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: "cluster/overview",
|
||||||
|
label: "Learn",
|
||||||
|
position: "left",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
href: "https://discordapp.com/invite/pquxPsq",
|
href: "https://discordapp.com/invite/pquxPsq",
|
||||||
label: "Chat",
|
label: "Chat",
|
||||||
|
@@ -1,7 +1,11 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
docs: {
|
docs: {
|
||||||
"Introduction": ["introduction"],
|
"About": [
|
||||||
"Wallet Guide": [
|
"introduction",
|
||||||
|
"terminology",
|
||||||
|
"history",
|
||||||
|
],
|
||||||
|
"Wallets": [
|
||||||
"wallet-guide",
|
"wallet-guide",
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
@@ -28,11 +32,11 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
"wallet-guide/support",
|
"wallet-guide/support",
|
||||||
],
|
],
|
||||||
"Staking Guide": [
|
"Staking": [
|
||||||
"staking",
|
"staking",
|
||||||
"staking/stake-accounts",
|
"staking/stake-accounts",
|
||||||
],
|
],
|
||||||
"Command Line Guide": [
|
"Command Line": [
|
||||||
"cli",
|
"cli",
|
||||||
"cli/install-solana-cli-tools",
|
"cli/install-solana-cli-tools",
|
||||||
"cli/conventions",
|
"cli/conventions",
|
||||||
@@ -43,8 +47,7 @@ module.exports = {
|
|||||||
"offline-signing",
|
"offline-signing",
|
||||||
"offline-signing/durable-nonce",
|
"offline-signing/durable-nonce",
|
||||||
],
|
],
|
||||||
"Solana Clusters": ["clusters"],
|
"Developing": [
|
||||||
"Develop Applications": [
|
|
||||||
"apps",
|
"apps",
|
||||||
"apps/rent",
|
"apps/rent",
|
||||||
"apps/hello-world",
|
"apps/hello-world",
|
||||||
@@ -56,8 +59,8 @@ module.exports = {
|
|||||||
"apps/javascript-api",
|
"apps/javascript-api",
|
||||||
"apps/builtins",
|
"apps/builtins",
|
||||||
],
|
],
|
||||||
"Integration Guides": ["integrations/exchange"],
|
"Integrating": ["integrations/exchange"],
|
||||||
"Run a Validator": [
|
"Validating": [
|
||||||
"running-validator",
|
"running-validator",
|
||||||
"running-validator/validator-reqs",
|
"running-validator/validator-reqs",
|
||||||
"running-validator/validator-start",
|
"running-validator/validator-start",
|
||||||
@@ -65,12 +68,13 @@ module.exports = {
|
|||||||
"running-validator/validator-stake",
|
"running-validator/validator-stake",
|
||||||
"running-validator/validator-monitor",
|
"running-validator/validator-monitor",
|
||||||
"running-validator/validator-info",
|
"running-validator/validator-info",
|
||||||
"running-validator/validator-troubleshoot",
|
|
||||||
],
|
|
||||||
"Tour de SOL": [
|
|
||||||
"tour-de-sol",
|
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
|
label: "Incenvitized Testnet",
|
||||||
|
items: [
|
||||||
|
"tour-de-sol",
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
label: "Registration",
|
label: "Registration",
|
||||||
items: [
|
items: [
|
||||||
"tour-de-sol/registration/how-to-register",
|
"tour-de-sol/registration/how-to-register",
|
||||||
@@ -91,10 +95,21 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
"tour-de-sol/useful-links",
|
"tour-de-sol/useful-links",
|
||||||
"tour-de-sol/submitting-bugs",
|
"tour-de-sol/submitting-bugs",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"running-validator/validator-troubleshoot",
|
||||||
],
|
],
|
||||||
"Benchmark a Cluster": ["cluster/bench-tps", "cluster/performance-metrics"],
|
"Clusters": [
|
||||||
"Solana's Architecture": [
|
"clusters",
|
||||||
"cluster/overview",
|
"cluster/bench-tps",
|
||||||
|
"cluster/performance-metrics"
|
||||||
|
],
|
||||||
|
"Architecture": [
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
label: "Cluster",
|
||||||
|
items: [
|
||||||
|
"cluster/overview",
|
||||||
"cluster/synchronization",
|
"cluster/synchronization",
|
||||||
"cluster/leader-rotation",
|
"cluster/leader-rotation",
|
||||||
"cluster/fork-generation",
|
"cluster/fork-generation",
|
||||||
@@ -102,19 +117,27 @@ module.exports = {
|
|||||||
"cluster/turbine-block-propagation",
|
"cluster/turbine-block-propagation",
|
||||||
"cluster/vote-signing",
|
"cluster/vote-signing",
|
||||||
"cluster/stake-delegation-and-rewards",
|
"cluster/stake-delegation-and-rewards",
|
||||||
],
|
],
|
||||||
"Anatomy of a Validator": [
|
},
|
||||||
"validator/anatomy",
|
{
|
||||||
"validator/tpu",
|
type: "category",
|
||||||
"validator/tvu",
|
label: "Validator",
|
||||||
"validator/blockstore",
|
items: [
|
||||||
"validator/gossip",
|
"validator/anatomy",
|
||||||
"validator/runtime",
|
"validator/tpu",
|
||||||
],
|
"validator/tvu",
|
||||||
Terminology: ["terminology"],
|
"validator/blockstore",
|
||||||
History: ["history"],
|
"validator/gossip",
|
||||||
"Implemented Design Proposals": [
|
"validator/runtime",
|
||||||
"implemented-proposals/implemented-proposals",
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"Design Proposals": [
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
label: "Implemented",
|
||||||
|
items: [
|
||||||
|
"implemented-proposals/implemented-proposals",
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
label: "Economic Design",
|
label: "Economic Design",
|
||||||
@@ -154,9 +177,13 @@ module.exports = {
|
|||||||
"implemented-proposals/cross-program-invocation",
|
"implemented-proposals/cross-program-invocation",
|
||||||
"implemented-proposals/program-derived-addresses",
|
"implemented-proposals/program-derived-addresses",
|
||||||
"implemented-proposals/abi-management",
|
"implemented-proposals/abi-management",
|
||||||
],
|
],
|
||||||
"Accepted Design Proposals": [
|
},
|
||||||
"proposals/accepted-design-proposals",
|
{
|
||||||
|
type: "category",
|
||||||
|
label: "Accepted",
|
||||||
|
items: [
|
||||||
|
"proposals/accepted-design-proposals",
|
||||||
"proposals/ledger-replication-to-implement",
|
"proposals/ledger-replication-to-implement",
|
||||||
"proposals/optimistic-confirmation-and-slashing",
|
"proposals/optimistic-confirmation-and-slashing",
|
||||||
"proposals/vote-signing-to-implement",
|
"proposals/vote-signing-to-implement",
|
||||||
@@ -173,6 +200,8 @@ module.exports = {
|
|||||||
"proposals/optimistic_confirmation",
|
"proposals/optimistic_confirmation",
|
||||||
"proposals/embedding-move",
|
"proposals/embedding-move",
|
||||||
"proposals/rip-curl",
|
"proposals/rip-curl",
|
||||||
|
]
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -24,6 +24,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
|||||||
- [getConfirmedBlock](jsonrpc-api.md#getconfirmedblock)
|
- [getConfirmedBlock](jsonrpc-api.md#getconfirmedblock)
|
||||||
- [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks)
|
- [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks)
|
||||||
- [getConfirmedSignaturesForAddress](jsonrpc-api.md#getconfirmedsignaturesforaddress)
|
- [getConfirmedSignaturesForAddress](jsonrpc-api.md#getconfirmedsignaturesforaddress)
|
||||||
|
- [getConfirmedSignaturesForAddress2](jsonrpc-api.md#getconfirmedsignaturesforaddress2)
|
||||||
- [getConfirmedTransaction](jsonrpc-api.md#getconfirmedtransaction)
|
- [getConfirmedTransaction](jsonrpc-api.md#getconfirmedtransaction)
|
||||||
- [getEpochInfo](jsonrpc-api.md#getepochinfo)
|
- [getEpochInfo](jsonrpc-api.md#getepochinfo)
|
||||||
- [getEpochSchedule](jsonrpc-api.md#getepochschedule)
|
- [getEpochSchedule](jsonrpc-api.md#getepochschedule)
|
||||||
@@ -45,10 +46,6 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
|||||||
- [getSlotLeader](jsonrpc-api.md#getslotleader)
|
- [getSlotLeader](jsonrpc-api.md#getslotleader)
|
||||||
- [getStakeActivation](jsonrpc-api.md#getstakeactivation)
|
- [getStakeActivation](jsonrpc-api.md#getstakeactivation)
|
||||||
- [getSupply](jsonrpc-api.md#getsupply)
|
- [getSupply](jsonrpc-api.md#getsupply)
|
||||||
- [getTokenAccountBalance](jsonrpc-api.md#gettokenaccountbalance)
|
|
||||||
- [getTokenAccountsByDelegate](jsonrpc-api.md#gettokenaccountsbydelegate)
|
|
||||||
- [getTokenAccountsByOwner](jsonrpc-api.md#gettokenaccountsbyowner)
|
|
||||||
- [getTokenSupply](jsonrpc-api.md#gettokensupply)
|
|
||||||
- [getTransactionCount](jsonrpc-api.md#gettransactioncount)
|
- [getTransactionCount](jsonrpc-api.md#gettransactioncount)
|
||||||
- [getVersion](jsonrpc-api.md#getversion)
|
- [getVersion](jsonrpc-api.md#getversion)
|
||||||
- [getVoteAccounts](jsonrpc-api.md#getvoteaccounts)
|
- [getVoteAccounts](jsonrpc-api.md#getvoteaccounts)
|
||||||
@@ -68,6 +65,15 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
|||||||
- [slotSubscribe](jsonrpc-api.md#slotsubscribe)
|
- [slotSubscribe](jsonrpc-api.md#slotsubscribe)
|
||||||
- [slotUnsubscribe](jsonrpc-api.md#slotunsubscribe)
|
- [slotUnsubscribe](jsonrpc-api.md#slotunsubscribe)
|
||||||
|
|
||||||
|
## Unstable Methods
|
||||||
|
|
||||||
|
Unstable methods may see breaking changes in patch releases and may not be supported in perpetuity.
|
||||||
|
|
||||||
|
- [getTokenAccountBalance](jsonrpc-api.md#gettokenaccountbalance)
|
||||||
|
- [getTokenAccountsByDelegate](jsonrpc-api.md#gettokenaccountsbydelegate)
|
||||||
|
- [getTokenAccountsByOwner](jsonrpc-api.md#gettokenaccountsbyowner)
|
||||||
|
- [getTokenSupply](jsonrpc-api.md#gettokensupply)
|
||||||
|
|
||||||
## Request Formatting
|
## Request Formatting
|
||||||
|
|
||||||
To make a JSON-RPC request, send an HTTP POST request with a `Content-Type: application/json` header. The JSON request data should contain 4 fields:
|
To make a JSON-RPC request, send an HTTP POST request with a `Content-Type: application/json` header. The JSON request data should contain 4 fields:
|
||||||
@@ -151,7 +157,7 @@ Returns all information associated with the account of provided Pubkey
|
|||||||
- `<object>` - (optional) Configuration object containing the following optional fields:
|
- `<object>` - (optional) Configuration object containing the following optional fields:
|
||||||
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||||
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
||||||
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`.
|
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`. **jsonParsed encoding is UNSTABLE**
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
@@ -299,7 +305,7 @@ Returns identity and transaction information about a confirmed block in the ledg
|
|||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
- `<u64>` - slot, as u64 integer
|
- `<u64>` - slot, as u64 integer
|
||||||
- `<string>` - (optional) encoding for each returned Transaction, either "json", "jsonParsed", or "binary". If parameter not provided, the default encoding is JSON.
|
- `<string>` - (optional) encoding for each returned Transaction, either "json", "jsonParsed", or "binary". If parameter not provided, the default encoding is JSON. **jsonParsed encoding is UNSTABLE**
|
||||||
Parsed-JSON encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the `transaction.message.instructions` list. If parsed-JSON is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` fields).
|
Parsed-JSON encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the `transaction.message.instructions` list. If parsed-JSON is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` fields).
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
@@ -389,6 +395,8 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"m
|
|||||||
|
|
||||||
### getConfirmedSignaturesForAddress
|
### getConfirmedSignaturesForAddress
|
||||||
|
|
||||||
|
**DEPRECATED: Please use getConfirmedSignaturesForAddress2 instead**
|
||||||
|
|
||||||
Returns a list of all the confirmed signatures for transactions involving an
|
Returns a list of all the confirmed signatures for transactions involving an
|
||||||
address, within a specified Slot range. Max range allowed is 10,000 Slots
|
address, within a specified Slot range. Max range allowed is 10,000 Slots
|
||||||
|
|
||||||
@@ -416,6 +424,37 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"m
|
|||||||
{"jsonrpc":"2.0","result":{["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4bJdGN8Tt2kLWZ3Fa1dpwPSEkXWWTSszPSf1rRVsCwNjxbbUdwTeiWtmi8soA26YmwnKD4aAxNp8ci1Gjpdv4gsr","4LQ14a7BYY27578Uj8LPCaVhSdJGLn9DJqnUJHpy95FMqdKf9acAhUhecPQNjNUy6VoNFUbvwYkPociFSf87cWbG"]},"id":1}
|
{"jsonrpc":"2.0","result":{["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4bJdGN8Tt2kLWZ3Fa1dpwPSEkXWWTSszPSf1rRVsCwNjxbbUdwTeiWtmi8soA26YmwnKD4aAxNp8ci1Gjpdv4gsr","4LQ14a7BYY27578Uj8LPCaVhSdJGLn9DJqnUJHpy95FMqdKf9acAhUhecPQNjNUy6VoNFUbvwYkPociFSf87cWbG"]},"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### getConfirmedSignaturesForAddress2
|
||||||
|
|
||||||
|
Returns confirmed signatures for transactions involving an
|
||||||
|
address backwards in time from the provided signature or most recent confirmed block
|
||||||
|
|
||||||
|
#### Parameters:
|
||||||
|
* `<string>` - account address as base-58 encoded string
|
||||||
|
* `<object>` - (optional) Configuration object containing the following fields:
|
||||||
|
* `before: <string>` - (optional) start searching backwards from this transaction signature.
|
||||||
|
If not provided the search starts from the top of the highest max confirmed block.
|
||||||
|
* `limit: <number>` - (optional) maximum transaction signatures to return (between 1 and 1,000, default: 1,000).
|
||||||
|
|
||||||
|
#### Results:
|
||||||
|
The result field will be an array of transaction signature information, ordered
|
||||||
|
from newest to oldest transaction:
|
||||||
|
* `<object>`
|
||||||
|
* `signature: <string>` - transaction signature as base-58 encoded string
|
||||||
|
* `slot: <u64>` - The slot that contains the block with the transaction
|
||||||
|
* `err: <object | null>` - Error if transaction failed, null if transaction succeeded. [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
|
||||||
|
* `memo: <string |null>` - Memo associated with the transaction, null if no memo is present
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
```bash
|
||||||
|
// Request
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedSignaturesForAddress2","params":["Vote111111111111111111111111111111111111111", {"limit": 1}]}' localhost:8899
|
||||||
|
|
||||||
|
// Result
|
||||||
|
{"jsonrpc":"2.0","result":[{"err":null,"memo":null,"signature":"5h6xBEauJ3PK6SWCZ1PGjBvj8vDdWG3KpwATGy1ARAXFSDwt8GFXM7W5Ncn16wmqokgpiKRLuS83KUxyZyv2sUYv","slot":114}],"id":1}
|
||||||
|
```
|
||||||
|
|
||||||
### getConfirmedTransaction
|
### getConfirmedTransaction
|
||||||
|
|
||||||
Returns transaction details for a confirmed transaction
|
Returns transaction details for a confirmed transaction
|
||||||
@@ -424,7 +463,7 @@ Returns transaction details for a confirmed transaction
|
|||||||
|
|
||||||
- `<string>` - transaction signature as base-58 encoded string
|
- `<string>` - transaction signature as base-58 encoded string
|
||||||
N encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the `transaction.message.instructions` list. If parsed-JSON is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` fields).
|
N encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the `transaction.message.instructions` list. If parsed-JSON is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` fields).
|
||||||
- `<string>` - (optional) encoding for the returned Transaction, either "json", "jsonParsed", or "binary".
|
- `<string>` - (optional) encoding for the returned Transaction, either "json", "jsonParsed", or "binary". **jsonParsed encoding is UNSTABLE**
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
@@ -805,7 +844,7 @@ Returns all accounts owned by the provided program Pubkey
|
|||||||
- `<object>` - (optional) Configuration object containing the following optional fields:
|
- `<object>` - (optional) Configuration object containing the following optional fields:
|
||||||
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||||
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
||||||
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`.
|
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`. **jsonParsed encoding is UNSTABLE**
|
||||||
- (optional) `filters: <array>` - filter results using various [filter objects](jsonrpc-api.md#filters); account must meet all filter criteria to be included in results
|
- (optional) `filters: <array>` - filter results using various [filter objects](jsonrpc-api.md#filters); account must meet all filter criteria to be included in results
|
||||||
|
|
||||||
##### Filters:
|
##### Filters:
|
||||||
@@ -1022,7 +1061,7 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "
|
|||||||
|
|
||||||
### getTokenAccountBalance
|
### getTokenAccountBalance
|
||||||
|
|
||||||
Returns the token balance of an SPL Token account.
|
Returns the token balance of an SPL Token account. **UNSTABLE**
|
||||||
|
|
||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
@@ -1048,7 +1087,7 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "
|
|||||||
|
|
||||||
### getTokenAccountsByDelegate
|
### getTokenAccountsByDelegate
|
||||||
|
|
||||||
Returns all SPL Token accounts by approved Delegate.
|
Returns all SPL Token accounts by approved Delegate. **UNSTABLE**
|
||||||
|
|
||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
@@ -1059,7 +1098,7 @@ Returns all SPL Token accounts by approved Delegate.
|
|||||||
- `<object>` - (optional) Configuration object containing the following optional fields:
|
- `<object>` - (optional) Configuration object containing the following optional fields:
|
||||||
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||||
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
||||||
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`.
|
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`. **jsonParsed encoding is UNSTABLE**
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
@@ -1079,12 +1118,12 @@ The result will be an RpcResponse JSON object with `value` equal to an array of
|
|||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getTokenAccountsByDelegate", "params": ["4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", {"programId": "TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"}, {"encoding": "jsonParsed"}]}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getTokenAccountsByDelegate", "params": ["4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", {"programId": "TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"}, {"encoding": "jsonParsed"}]}' http://localhost:8899
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"context":{"slot":1114},"value":[{"data":{"program":"spl-token","parsed":{"accountType":"account","info":{"amount":1,"delegate":"4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T","delegatedAmount":1,"isInitialized":true,"isNative":false,"mint":"3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E","owner":"CnPoSPKXu7wJqxe59Fs72tkBeALovhsCxYeFwPCQH9TD"}}},"executable":false,"lamports":1726080,"owner":"TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o","rentEpoch":4},"pubkey":"CnPoSPKXu7wJqxe59Fs72tkBeALovhsCxYeFwPCQH9TD"}],"id":1}
|
{"jsonrpc":"2.0","result":{"context":{"slot":1114},"value":[{"data":{"program":"spl-token","parsed":{"accountType":"account","info":{"tokenAmount":{"amount":"1","uiAmount":0.1,"decimals":1},"delegate":"4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T","delegatedAmount":1,"isInitialized":true,"isNative":false,"mint":"3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E","owner":"CnPoSPKXu7wJqxe59Fs72tkBeALovhsCxYeFwPCQH9TD"}}},"executable":false,"lamports":1726080,"owner":"TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o","rentEpoch":4},"pubkey":"CnPoSPKXu7wJqxe59Fs72tkBeALovhsCxYeFwPCQH9TD"}],"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getTokenAccountsByOwner
|
### getTokenAccountsByOwner
|
||||||
|
|
||||||
Returns all SPL Token accounts by token owner.
|
Returns all SPL Token accounts by token owner. **UNSTABLE**
|
||||||
|
|
||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
@@ -1095,7 +1134,7 @@ Returns all SPL Token accounts by token owner.
|
|||||||
- `<object>` - (optional) Configuration object containing the following optional fields:
|
- `<object>` - (optional) Configuration object containing the following optional fields:
|
||||||
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||||
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
||||||
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`.
|
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`. **jsonParsed encoding is UNSTABLE**
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
@@ -1115,12 +1154,12 @@ The result will be an RpcResponse JSON object with `value` equal to an array of
|
|||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getTokenAccountsByOwner", "params": ["4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F", {"mint":"3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E"}, {"encoding": "jsonParsed"}]}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getTokenAccountsByOwner", "params": ["4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F", {"mint":"3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E"}, {"encoding": "jsonParsed"}]}' http://localhost:8899
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"context":{"slot":1114},"value":[{"data":{"program":"spl-token","parsed":{"accountType":"account","info":{"amount":1,"delegate":null,"delegatedAmount":1,"isInitialized":true,"isNative":false,"mint":"3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E","owner":"4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F"}}},"executable":false,"lamports":1726080,"owner":"TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o","rentEpoch":4},"pubkey":"CnPoSPKXu7wJqxe59Fs72tkBeALovhsCxYeFwPCQH9TD"}],"id":1}
|
{"jsonrpc":"2.0","result":{"context":{"slot":1114},"value":[{"data":{"program":"spl-token","parsed":{"accountType":"account","info":{"tokenAmount":{"amount":"1","uiAmount":0.1,"decimals":1},"delegate":null,"delegatedAmount":1,"isInitialized":true,"isNative":false,"mint":"3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E","owner":"4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F"}}},"executable":false,"lamports":1726080,"owner":"TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o","rentEpoch":4},"pubkey":"CnPoSPKXu7wJqxe59Fs72tkBeALovhsCxYeFwPCQH9TD"}],"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getTokenSupply
|
### getTokenSupply
|
||||||
|
|
||||||
Returns the total supply of an SPL Token type.
|
Returns the total supply of an SPL Token type. **UNSTABLE**
|
||||||
|
|
||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
@@ -1186,7 +1225,7 @@ The result field will be a JSON object with the following fields:
|
|||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' http://localhost:8899
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"solana-core": "1.3.0"},"id":1}
|
{"jsonrpc":"2.0","result":{"solana-core": "1.3.1"},"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getVoteAccounts
|
### getVoteAccounts
|
||||||
@@ -1387,7 +1426,7 @@ Subscribe to an account to receive notifications when the lamports or data for a
|
|||||||
- `<object>` - (optional) Configuration object containing the following optional fields:
|
- `<object>` - (optional) Configuration object containing the following optional fields:
|
||||||
- `<object>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
- `<object>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||||
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
||||||
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`.
|
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`. **jsonParsed encoding is UNSTABLE**
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
@@ -1442,8 +1481,10 @@ Subscribe to an account to receive notifications when the lamports or data for a
|
|||||||
},
|
},
|
||||||
"value": {
|
"value": {
|
||||||
"data": {
|
"data": {
|
||||||
"nonce": {
|
"program": "nonce"
|
||||||
"initialized": {
|
"parsed": {
|
||||||
|
"type": "initialized",
|
||||||
|
"info": {
|
||||||
"authority": "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX",
|
"authority": "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX",
|
||||||
"blockhash": "LUaQTmM7WbMRiATdMMHaRGakPtCkc2GHtH57STKXs6k",
|
"blockhash": "LUaQTmM7WbMRiATdMMHaRGakPtCkc2GHtH57STKXs6k",
|
||||||
"feeCalculator": {
|
"feeCalculator": {
|
||||||
@@ -1495,7 +1536,7 @@ Subscribe to a program to receive notifications when the lamports or data for a
|
|||||||
- `<object>` - (optional) Configuration object containing the following optional fields:
|
- `<object>` - (optional) Configuration object containing the following optional fields:
|
||||||
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||||
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
- (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
||||||
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`.
|
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`. **jsonParsed encoding is UNSTABLE**
|
||||||
- (optional) `filters: <array>` - filter results using various [filter objects](jsonrpc-api.md#filters); account must meet all filter criteria to be included in results
|
- (optional) `filters: <array>` - filter results using various [filter objects](jsonrpc-api.md#filters); account must meet all filter criteria to be included in results
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
@@ -1558,8 +1599,10 @@ Subscribe to a program to receive notifications when the lamports or data for a
|
|||||||
"pubkey": "H4vnBqifaSACnKa7acsxstsY1iV1bvJNxsCY7enrd1hq"
|
"pubkey": "H4vnBqifaSACnKa7acsxstsY1iV1bvJNxsCY7enrd1hq"
|
||||||
"account": {
|
"account": {
|
||||||
"data": {
|
"data": {
|
||||||
"nonce": {
|
"program": "nonce"
|
||||||
"initialized": {
|
"parsed": {
|
||||||
|
"type": "initialized",
|
||||||
|
"info": {
|
||||||
"authority": "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX",
|
"authority": "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX",
|
||||||
"blockhash": "LUaQTmM7WbMRiATdMMHaRGakPtCkc2GHtH57STKXs6k",
|
"blockhash": "LUaQTmM7WbMRiATdMMHaRGakPtCkc2GHtH57STKXs6k",
|
||||||
"feeCalculator": {
|
"feeCalculator": {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: History of the Solana Codebase
|
title: History
|
||||||
---
|
---
|
||||||
|
|
||||||
In November of 2017, Anatoly Yakovenko published a whitepaper describing Proof
|
In November of 2017, Anatoly Yakovenko published a whitepaper describing Proof
|
||||||
|
106
docs/src/implemented-proposals/rpc-transaction-history.md
Normal file
106
docs/src/implemented-proposals/rpc-transaction-history.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# Long term RPC Transaction History
|
||||||
|
There's a need for RPC to serve at least 6 months of transaction history. The
|
||||||
|
current history, on the order of days, is insufficient for downstream users.
|
||||||
|
|
||||||
|
6 months of transaction data cannot be stored practically in a validator's
|
||||||
|
rocksdb ledger so an external data store is necessary. The validator's
|
||||||
|
rocksdb ledger will continue to serve as the primary data source, and then will
|
||||||
|
fall back to the external data store.
|
||||||
|
|
||||||
|
The affected RPC endpoints are:
|
||||||
|
* [getFirstAvailableBlock](https://docs.solana.com/apps/jsonrpc-api#getfirstavailableblock)
|
||||||
|
* [getConfirmedBlock](https://docs.solana.com/apps/jsonrpc-api#getconfirmedblock)
|
||||||
|
* [getConfirmedBlocks](https://docs.solana.com/apps/jsonrpc-api#getconfirmedblocks)
|
||||||
|
* [getConfirmedSignaturesForAddress](https://docs.solana.com/apps/jsonrpc-api#getconfirmedsignaturesforaddress)
|
||||||
|
* [getConfirmedTransaction](https://docs.solana.com/apps/jsonrpc-api#getconfirmedtransaction)
|
||||||
|
* [getSignatureStatuses](https://docs.solana.com/apps/jsonrpc-api#getsignaturestatuses)
|
||||||
|
|
||||||
|
Note that [getBlockTime](https://docs.solana.com/apps/jsonrpc-api#getblocktime)
|
||||||
|
is not supported, as once https://github.com/solana-labs/solana/issues/10089 is
|
||||||
|
fixed then `getBlockTime` can be removed.
|
||||||
|
|
||||||
|
Some system design constraints:
|
||||||
|
* The volume of data to store and search can quickly jump into the terabytes,
|
||||||
|
and is immutable.
|
||||||
|
* The system should be as light as possible for SREs. For example an SQL
|
||||||
|
database cluster that requires an SRE to continually monitor and rebalance
|
||||||
|
nodes is undesirable.
|
||||||
|
* Data must be searchable in real time - batched queries that take minutes or
|
||||||
|
hours to run are unacceptable.
|
||||||
|
* Easy to replicate the data worldwide to co-locate it with the RPC endpoints
|
||||||
|
that will utilize it.
|
||||||
|
* Interfacing with the external data store should be easy and not require
|
||||||
|
depending on risky lightly-used community-supported code libraries
|
||||||
|
|
||||||
|
Based on these constraints, Google's BigTable product is selected as the data
|
||||||
|
store.
|
||||||
|
|
||||||
|
## Table Schema
|
||||||
|
A BigTable instance is used to hold all transaction data, broken up into
|
||||||
|
different tables for quick searching.
|
||||||
|
|
||||||
|
New data may be copied into the instance at anytime without affecting the existing
|
||||||
|
data, and all data is immutable. Generally the expectation is that new data
|
||||||
|
will be uploaded once an current epoch completes but there is no limitation on
|
||||||
|
the frequency of data dumps.
|
||||||
|
|
||||||
|
Cleanup of old data is automatic by configuring the data retention policy of the
|
||||||
|
instance tables appropriately, it just disappears. Therefore the order of when data is
|
||||||
|
added becomes important. For example if data from epoch N-1 is added after data
|
||||||
|
from epoch N, the older epoch data will outlive the newer data. However beyond
|
||||||
|
producing _holes_ in query results, this kind of unordered deletion will
|
||||||
|
have no ill effect. Note that this method of cleanup effectively allows for an
|
||||||
|
unlimited amount of transaction data to be stored, restricted only by the
|
||||||
|
monetary costs of doing so.
|
||||||
|
|
||||||
|
The table layout s supports the existing RPC endpoints only. New RPC endpoints
|
||||||
|
in the future may require additions to the schema and potentially iterating over
|
||||||
|
all transactions to build up the necessary metadata.
|
||||||
|
|
||||||
|
## Accessing BigTable
|
||||||
|
BigTable has a gRPC endpoint that can be accessed using the
|
||||||
|
[tonic](https://crates.io/crates/crate)] and the raw protobuf API, as currently no
|
||||||
|
higher-level Rust crate for BigTable exists. Practically this makes parsing the
|
||||||
|
results of BigTable queries more complicated but is not a significant issue.
|
||||||
|
|
||||||
|
## Data Population
|
||||||
|
The ongoing population of instance data will occur on an epoch cadence through the
|
||||||
|
use of a new `solana-ledger-tool` command that will convert rocksdb data for a
|
||||||
|
given slot range into the instance schema.
|
||||||
|
|
||||||
|
The same process will be run once, manually, to backfill the existing ledger
|
||||||
|
data.
|
||||||
|
|
||||||
|
### Block Table: `block`
|
||||||
|
|
||||||
|
This table contains the compressed block data for a given slot.
|
||||||
|
|
||||||
|
The row key is generated by taking the 16 digit lower case hexadecimal
|
||||||
|
representation of the slot, to ensure that the oldest slot with a confirmed
|
||||||
|
block will always be first when the rows are listed. eg, The row key for slot
|
||||||
|
42 would be 000000000000002a.
|
||||||
|
|
||||||
|
The row data is a compressed `StoredConfirmedBlock` struct.
|
||||||
|
|
||||||
|
|
||||||
|
### Account Address Transaction Signature Lookup Table: `tx-by-addr`
|
||||||
|
|
||||||
|
This table contains the transactions that affect a given address.
|
||||||
|
|
||||||
|
The row key is `<base58
|
||||||
|
address>/<slot-id-one's-compliment-hex-slot-0-prefixed-to-16-digits>`. The row
|
||||||
|
data is a compressed `TransactionByAddrInfo` struct.
|
||||||
|
|
||||||
|
Taking the one's compliment of the slot allows for listing of slots ensures that
|
||||||
|
the newest slot with transactions that affect an address will always
|
||||||
|
be listed first.
|
||||||
|
|
||||||
|
Sysvar addresses are not indexed. However frequently used programs such as
|
||||||
|
Vote or System are, and will likely have a row for every confirmed slot.
|
||||||
|
|
||||||
|
### Transaction Signature Lookup Table: `tx`
|
||||||
|
|
||||||
|
This table maps a transaction signature to its confirmed block, and index within that block.
|
||||||
|
|
||||||
|
The row key is the base58-encoded transaction signature.
|
||||||
|
The row data is a compressed `TransactionInfo` struct.
|
@@ -13,13 +13,13 @@ const features = [
|
|||||||
description: <>Get started building your decentralized app or marketplace.</>,
|
description: <>Get started building your decentralized app or marketplace.</>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: <>✅ Run a Validator Node</>,
|
title: <>🎛 Run a Validator Node</>,
|
||||||
imageUrl: "running-validator",
|
imageUrl: "running-validator",
|
||||||
description: <>Validate transactions, secure the network, and earn rewards.</>,
|
description: <>Validate transactions, secure the network, and earn rewards.</>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: <>🏛 Create an SPL Token</>,
|
title: <>🏛 Create an SPL Token</>,
|
||||||
imageUrl: "tour-de-sol",
|
imageUrl: "https://spl.solana.com/token",
|
||||||
description: (
|
description: (
|
||||||
<>
|
<>
|
||||||
Launch your own SPL Token, Solana's equivalent of ERC-20.
|
Launch your own SPL Token, Solana's equivalent of ERC-20.
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-dos"
|
name = "solana-dos"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -13,14 +13,14 @@ clap = "2.33.1"
|
|||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
rand = "0.7.0"
|
rand = "0.7.0"
|
||||||
rayon = "1.3.1"
|
rayon = "1.3.1"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-core = { path = "../core", version = "1.3.0" }
|
solana-core = { path = "../core", version = "1.3.1" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.3.0" }
|
solana-ledger = { path = "../ledger", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.3.0" }
|
solana-net-utils = { path = "../net-utils", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-download-utils"
|
name = "solana-download-utils"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana Download Utils"
|
description = "Solana Download Utils"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -14,8 +14,8 @@ console = "0.11.3"
|
|||||||
indicatif = "0.15.0"
|
indicatif = "0.15.0"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
reqwest = { version = "0.10.6", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
reqwest = { version = "0.10.6", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
tar = "0.4.28"
|
tar = "0.4.28"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
2
explorer/wasm/Cargo.lock
generated
2
explorer/wasm/Cargo.lock
generated
@@ -98,7 +98,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-sdk-wasm"
|
name = "solana-sdk-wasm"
|
||||||
version = "1.2.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"bs58",
|
"bs58",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-sdk-wasm"
|
name = "solana-sdk-wasm"
|
||||||
version = "1.2.0"
|
version = "1.3.1"
|
||||||
description = "Solana SDK Wasm"
|
description = "Solana SDK Wasm"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-faucet"
|
name = "solana-faucet"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana Faucet"
|
description = "Solana Faucet"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -16,11 +16,11 @@ clap = "2.33"
|
|||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.3.0" }
|
solana-metrics = { path = "../metrics", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
tokio = "0.1"
|
tokio = "0.1"
|
||||||
tokio-codec = "0.1"
|
tokio-codec = "0.1"
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-genesis-programs"
|
name = "solana-genesis-programs"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana genesis programs"
|
description = "Solana genesis programs"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -10,12 +10,12 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = { version = "0.4.8" }
|
log = { version = "0.4.8" }
|
||||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.3.0" }
|
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.3.1" }
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.3.0" }
|
solana-budget-program = { path = "../programs/budget", version = "1.3.1" }
|
||||||
solana-exchange-program = { path = "../programs/exchange", version = "1.3.0" }
|
solana-exchange-program = { path = "../programs/exchange", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-vest-program = { path = "../programs/vest", version = "1.3.0" }
|
solana-vest-program = { path = "../programs/vest", version = "1.3.1" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["lib"]
|
crate-type = ["lib"]
|
||||||
|
@@ -105,7 +105,11 @@ pub fn get_entered_epoch_callback(operating_mode: OperatingMode) -> EnteredEpoch
|
|||||||
bank.add_native_program(name, program_id);
|
bank.add_native_program(name, program_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bank.set_cross_program_support(OperatingMode::Stable != operating_mode);
|
if OperatingMode::Stable == operating_mode {
|
||||||
|
bank.set_cross_program_support(bank.epoch() >= 63);
|
||||||
|
} else {
|
||||||
|
bank.set_cross_program_support(true);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-genesis"
|
name = "solana-genesis"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -15,15 +15,15 @@ chrono = "0.4"
|
|||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
serde_yaml = "0.8.13"
|
serde_yaml = "0.8.13"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.3.0" }
|
solana-genesis-programs = { path = "../genesis-programs", version = "1.3.1" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.3.0" }
|
solana-ledger = { path = "../ledger", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.3.0" }
|
solana-stake-program = { path = "../programs/stake", version = "1.3.1" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.3.0" }
|
solana-vote-program = { path = "../programs/vote", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@@ -3,20 +3,20 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-gossip"
|
name = "solana-gossip"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33.1"
|
clap = "2.33.1"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-core = { path = "../core", version = "1.3.0" }
|
solana-core = { path = "../core", version = "1.3.1" }
|
||||||
solana-client = { path = "../client", version = "1.3.0" }
|
solana-client = { path = "../client", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.3.0" }
|
solana-net-utils = { path = "../net-utils", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-install"
|
name = "solana-install"
|
||||||
description = "The solana cluster software installer"
|
description = "The solana cluster software installer"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -24,12 +24,12 @@ reqwest = { version = "0.10.6", default-features = false, features = ["blocking"
|
|||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_yaml = "0.8.13"
|
serde_yaml = "0.8.13"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-client = { path = "../client", version = "1.3.0" }
|
solana-client = { path = "../client", version = "1.3.1" }
|
||||||
solana-config-program = { path = "../programs/config", version = "1.3.0" }
|
solana-config-program = { path = "../programs/config", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
semver = "0.9.0"
|
semver = "0.9.0"
|
||||||
tar = "0.4.28"
|
tar = "0.4.28"
|
||||||
tempdir = "0.3.7"
|
tempdir = "0.3.7"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-keygen"
|
name = "solana-keygen"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana key generation utility"
|
description = "Solana key generation utility"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -13,11 +13,11 @@ bs58 = "0.3.1"
|
|||||||
clap = "2.33"
|
clap = "2.33"
|
||||||
dirs = "2.0.2"
|
dirs = "2.0.2"
|
||||||
num_cpus = "1.13.0"
|
num_cpus = "1.13.0"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-cli-config = { path = "../cli-config", version = "1.3.0" }
|
solana-cli-config = { path = "../cli-config", version = "1.3.1" }
|
||||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.3.0" }
|
solana-remote-wallet = { path = "../remote-wallet", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
tiny-bip39 = "0.7.0"
|
tiny-bip39 = "0.7.0"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-ledger-tool"
|
name = "solana-ledger-tool"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -12,22 +12,27 @@ homepage = "https://solana.com/"
|
|||||||
bs58 = "0.3.1"
|
bs58 = "0.3.1"
|
||||||
bytecount = "0.6.0"
|
bytecount = "0.6.0"
|
||||||
clap = "2.33.1"
|
clap = "2.33.1"
|
||||||
|
futures = "0.3.5"
|
||||||
|
futures-util = "0.3.5"
|
||||||
histogram = "*"
|
histogram = "*"
|
||||||
log = { version = "0.4.8" }
|
log = { version = "0.4.8" }
|
||||||
|
regex = "1"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
serde_yaml = "0.8.13"
|
serde_yaml = "0.8.13"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-cli = { path = "../cli", version = "1.3.0" }
|
solana-cli = { path = "../cli", version = "1.3.1" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.3.0" }
|
solana-ledger = { path = "../ledger", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-measure = { path = "../measure", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.3.0" }
|
solana-stake-program = { path = "../programs/stake", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-storage-bigtable = { path = "../storage-bigtable", version = "1.3.1" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.3.0" }
|
solana-transaction-status = { path = "../transaction-status", version = "1.3.1" }
|
||||||
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
|
solana-vote-program = { path = "../programs/vote", version = "1.3.1" }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
regex = "1"
|
tokio = { version = "0.2.22", features = ["full"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "1.0"
|
assert_cmd = "1.0"
|
||||||
|
551
ledger-tool/src/bigtable.rs
Normal file
551
ledger-tool/src/bigtable.rs
Normal file
@@ -0,0 +1,551 @@
|
|||||||
|
/// The `bigtable` subcommand
|
||||||
|
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||||
|
use log::*;
|
||||||
|
use solana_clap_utils::{
|
||||||
|
input_parsers::pubkey_of,
|
||||||
|
input_validators::{is_slot, is_valid_pubkey},
|
||||||
|
};
|
||||||
|
use solana_cli::display::println_transaction;
|
||||||
|
use solana_ledger::{blockstore::Blockstore, blockstore_db::AccessType};
|
||||||
|
use solana_measure::measure::Measure;
|
||||||
|
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature};
|
||||||
|
use solana_transaction_status::UiTransactionEncoding;
|
||||||
|
use std::{collections::HashSet, path::Path, process::exit, result::Result, time::Duration};
|
||||||
|
use tokio::time::delay_for;
|
||||||
|
|
||||||
|
// Attempt to upload this many blocks in parallel
|
||||||
|
const NUM_BLOCKS_TO_UPLOAD_IN_PARALLEL: usize = 32;
|
||||||
|
|
||||||
|
// Read up to this many blocks from blockstore before blocking on the upload process
|
||||||
|
const BLOCK_READ_AHEAD_DEPTH: usize = NUM_BLOCKS_TO_UPLOAD_IN_PARALLEL * 2;
|
||||||
|
|
||||||
|
async fn upload(
|
||||||
|
blockstore: Blockstore,
|
||||||
|
starting_slot: Slot,
|
||||||
|
ending_slot: Option<Slot>,
|
||||||
|
allow_missing_metadata: bool,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut measure = Measure::start("entire upload");
|
||||||
|
|
||||||
|
let bigtable = solana_storage_bigtable::LedgerStorage::new(false)
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Failed to connect to storage: {:?}", err))?;
|
||||||
|
|
||||||
|
info!("Loading ledger slots...");
|
||||||
|
let blockstore_slots: Vec<_> = blockstore
|
||||||
|
.slot_meta_iterator(starting_slot)
|
||||||
|
.map_err(|err| {
|
||||||
|
format!(
|
||||||
|
"Failed to load entries starting from slot {}: {:?}",
|
||||||
|
starting_slot, err
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.filter_map(|(slot, _slot_meta)| {
|
||||||
|
if let Some(ending_slot) = &ending_slot {
|
||||||
|
if slot > *ending_slot {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(slot)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if blockstore_slots.is_empty() {
|
||||||
|
info!("Ledger has no slots in the specified range");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
info!(
|
||||||
|
"Found {} slots in the range ({}, {})",
|
||||||
|
blockstore_slots.len(),
|
||||||
|
blockstore_slots.first().unwrap(),
|
||||||
|
blockstore_slots.last().unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut blockstore_slots_with_no_confirmed_block = HashSet::new();
|
||||||
|
|
||||||
|
// Gather the blocks that are already present in bigtable, by slot
|
||||||
|
let bigtable_slots = {
|
||||||
|
let mut bigtable_slots = vec![];
|
||||||
|
let first_blockstore_slot = *blockstore_slots.first().unwrap();
|
||||||
|
let last_blockstore_slot = *blockstore_slots.last().unwrap();
|
||||||
|
info!(
|
||||||
|
"Loading list of bigtable blocks between slots {} and {}...",
|
||||||
|
first_blockstore_slot, last_blockstore_slot
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut start_slot = *blockstore_slots.first().unwrap();
|
||||||
|
while start_slot <= last_blockstore_slot {
|
||||||
|
let mut next_bigtable_slots = loop {
|
||||||
|
match bigtable.get_confirmed_blocks(start_slot, 1000).await {
|
||||||
|
Ok(slots) => break slots,
|
||||||
|
Err(err) => {
|
||||||
|
error!("get_confirmed_blocks for {} failed: {:?}", start_slot, err);
|
||||||
|
// Consider exponential backoff...
|
||||||
|
delay_for(Duration::from_secs(2)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if next_bigtable_slots.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bigtable_slots.append(&mut next_bigtable_slots);
|
||||||
|
start_slot = bigtable_slots.last().unwrap() + 1;
|
||||||
|
}
|
||||||
|
bigtable_slots
|
||||||
|
.into_iter()
|
||||||
|
.filter(|slot| *slot <= last_blockstore_slot)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
};
|
||||||
|
|
||||||
|
// The blocks that still need to be uploaded is the difference between what's already in the
|
||||||
|
// bigtable and what's in blockstore...
|
||||||
|
let blocks_to_upload = {
|
||||||
|
let blockstore_slots = blockstore_slots.iter().cloned().collect::<HashSet<_>>();
|
||||||
|
let bigtable_slots = bigtable_slots.into_iter().collect::<HashSet<_>>();
|
||||||
|
|
||||||
|
let mut blocks_to_upload = blockstore_slots
|
||||||
|
.difference(&blockstore_slots_with_no_confirmed_block)
|
||||||
|
.cloned()
|
||||||
|
.collect::<HashSet<_>>()
|
||||||
|
.difference(&bigtable_slots)
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
blocks_to_upload.sort();
|
||||||
|
blocks_to_upload
|
||||||
|
};
|
||||||
|
|
||||||
|
if blocks_to_upload.is_empty() {
|
||||||
|
info!("No blocks need to be uploaded to bigtable");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
info!(
|
||||||
|
"{} blocks to be uploaded to the bucket in the range ({}, {})",
|
||||||
|
blocks_to_upload.len(),
|
||||||
|
blocks_to_upload.first().unwrap(),
|
||||||
|
blocks_to_upload.last().unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Load the blocks out of blockstore in a separate thread to allow for concurrent block uploading
|
||||||
|
let (_loader_thread, receiver) = {
|
||||||
|
let (sender, receiver) = std::sync::mpsc::sync_channel(BLOCK_READ_AHEAD_DEPTH);
|
||||||
|
(
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let mut measure = Measure::start("block loader thread");
|
||||||
|
for (i, slot) in blocks_to_upload.iter().enumerate() {
|
||||||
|
let _ = match blockstore.get_confirmed_block(
|
||||||
|
*slot,
|
||||||
|
Some(solana_transaction_status::UiTransactionEncoding::Binary),
|
||||||
|
) {
|
||||||
|
Ok(confirmed_block) => sender.send((*slot, Some(confirmed_block))),
|
||||||
|
Err(err) => {
|
||||||
|
warn!(
|
||||||
|
"Failed to get load confirmed block from slot {}: {:?}",
|
||||||
|
slot, err
|
||||||
|
);
|
||||||
|
sender.send((*slot, None))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if i % NUM_BLOCKS_TO_UPLOAD_IN_PARALLEL == 0 {
|
||||||
|
info!(
|
||||||
|
"{}% of blocks processed ({}/{})",
|
||||||
|
i * 100 / blocks_to_upload.len(),
|
||||||
|
i,
|
||||||
|
blocks_to_upload.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
measure.stop();
|
||||||
|
info!("{} to load {} blocks", measure, blocks_to_upload.len());
|
||||||
|
}),
|
||||||
|
receiver,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut failures = 0;
|
||||||
|
use futures::stream::StreamExt;
|
||||||
|
|
||||||
|
let mut stream =
|
||||||
|
tokio::stream::iter(receiver.into_iter()).chunks(NUM_BLOCKS_TO_UPLOAD_IN_PARALLEL);
|
||||||
|
|
||||||
|
while let Some(blocks) = stream.next().await {
|
||||||
|
let mut measure_upload = Measure::start("Upload");
|
||||||
|
let mut num_blocks = blocks.len();
|
||||||
|
info!("Preparing the next {} blocks for upload", num_blocks);
|
||||||
|
|
||||||
|
let uploads = blocks.into_iter().filter_map(|(slot, block)| match block {
|
||||||
|
None => {
|
||||||
|
blockstore_slots_with_no_confirmed_block.insert(slot);
|
||||||
|
num_blocks -= 1;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Some(confirmed_block) => {
|
||||||
|
if confirmed_block
|
||||||
|
.transactions
|
||||||
|
.iter()
|
||||||
|
.any(|transaction| transaction.meta.is_none())
|
||||||
|
{
|
||||||
|
if allow_missing_metadata {
|
||||||
|
info!("Transaction metadata missing from slot {}", slot);
|
||||||
|
} else {
|
||||||
|
panic!("Transaction metadata missing from slot {}", slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(bigtable.upload_confirmed_block(slot, confirmed_block))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for result in futures::future::join_all(uploads).await {
|
||||||
|
if result.is_err() {
|
||||||
|
error!("upload_confirmed_block() failed: {:?}", result.err());
|
||||||
|
failures += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
measure_upload.stop();
|
||||||
|
info!("{} for {} blocks", measure_upload, num_blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
measure.stop();
|
||||||
|
info!("{}", measure);
|
||||||
|
if failures > 0 {
|
||||||
|
Err(format!("Incomplete upload, {} operations failed", failures).into())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn first_available_block() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let bigtable = solana_storage_bigtable::LedgerStorage::new(true).await?;
|
||||||
|
match bigtable.get_first_available_block().await? {
|
||||||
|
Some(block) => println!("{}", block),
|
||||||
|
None => println!("No blocks available"),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn block(slot: Slot) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let bigtable = solana_storage_bigtable::LedgerStorage::new(false)
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Failed to connect to storage: {:?}", err))?;
|
||||||
|
|
||||||
|
let block = bigtable
|
||||||
|
.get_confirmed_block(slot, UiTransactionEncoding::Binary)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Slot: {}", slot);
|
||||||
|
println!("Parent Slot: {}", block.parent_slot);
|
||||||
|
println!("Blockhash: {}", block.blockhash);
|
||||||
|
println!("Previous Blockhash: {}", block.previous_blockhash);
|
||||||
|
if block.block_time.is_some() {
|
||||||
|
println!("Block Time: {:?}", block.block_time);
|
||||||
|
}
|
||||||
|
if !block.rewards.is_empty() {
|
||||||
|
println!("Rewards: {:?}", block.rewards);
|
||||||
|
}
|
||||||
|
for (index, transaction_with_meta) in block.transactions.iter().enumerate() {
|
||||||
|
println!("Transaction {}:", index);
|
||||||
|
println_transaction(
|
||||||
|
&transaction_with_meta.transaction.decode().unwrap(),
|
||||||
|
&transaction_with_meta.meta,
|
||||||
|
" ",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn blocks(starting_slot: Slot, limit: usize) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let bigtable = solana_storage_bigtable::LedgerStorage::new(false)
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Failed to connect to storage: {:?}", err))?;
|
||||||
|
|
||||||
|
let slots = bigtable.get_confirmed_blocks(starting_slot, limit).await?;
|
||||||
|
println!("{:?}", slots);
|
||||||
|
println!("{} blocks found", slots.len());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn confirm(signature: &Signature, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let bigtable = solana_storage_bigtable::LedgerStorage::new(false)
|
||||||
|
.await
|
||||||
|
.map_err(|err| format!("Failed to connect to storage: {:?}", err))?;
|
||||||
|
|
||||||
|
let transaction_status = bigtable.get_signature_status(signature).await?;
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
match bigtable
|
||||||
|
.get_confirmed_transaction(signature, UiTransactionEncoding::Binary)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(Some(confirmed_transaction)) => {
|
||||||
|
println!(
|
||||||
|
"\nTransaction executed in slot {}:",
|
||||||
|
confirmed_transaction.slot
|
||||||
|
);
|
||||||
|
println_transaction(
|
||||||
|
&confirmed_transaction
|
||||||
|
.transaction
|
||||||
|
.transaction
|
||||||
|
.decode()
|
||||||
|
.expect("Successful decode"),
|
||||||
|
&confirmed_transaction.transaction.meta,
|
||||||
|
" ",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(None) => println!("Confirmed transaction details not available"),
|
||||||
|
Err(err) => println!("Unable to get confirmed transaction details: {}", err),
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
match transaction_status.status {
|
||||||
|
Ok(_) => println!("Confirmed"),
|
||||||
|
Err(err) => println!("Transaction failed: {}", err),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn transaction_history(
|
||||||
|
address: &Pubkey,
|
||||||
|
mut limit: usize,
|
||||||
|
mut before: Option<Signature>,
|
||||||
|
verbose: bool,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let bigtable = solana_storage_bigtable::LedgerStorage::new(true).await?;
|
||||||
|
|
||||||
|
while limit > 0 {
|
||||||
|
let results = bigtable
|
||||||
|
.get_confirmed_signatures_for_address(address, before.as_ref(), limit.min(1000))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if results.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
before = Some(results.last().unwrap().signature);
|
||||||
|
assert!(limit >= results.len());
|
||||||
|
limit = limit.saturating_sub(results.len());
|
||||||
|
|
||||||
|
for result in results {
|
||||||
|
if verbose {
|
||||||
|
println!(
|
||||||
|
"{}, slot={}, memo=\"{}\", status={}",
|
||||||
|
result.signature,
|
||||||
|
result.slot,
|
||||||
|
result.memo.unwrap_or_else(|| "".to_string()),
|
||||||
|
match result.err {
|
||||||
|
None => "Confirmed".to_string(),
|
||||||
|
Some(err) => format!("Failed: {:?}", err),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("{}", result.signature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait BigTableSubCommand {
|
||||||
|
fn bigtable_subcommand(self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BigTableSubCommand for App<'_, '_> {
|
||||||
|
fn bigtable_subcommand(self) -> Self {
|
||||||
|
self.subcommand(
|
||||||
|
SubCommand::with_name("bigtable")
|
||||||
|
.about("Ledger data on a BigTable instance")
|
||||||
|
.setting(AppSettings::ArgRequiredElseHelp)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("upload")
|
||||||
|
.about("Upload the ledger to BigTable")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("starting_slot")
|
||||||
|
.long("starting-slot")
|
||||||
|
.validator(is_slot)
|
||||||
|
.value_name("SLOT")
|
||||||
|
.takes_value(true)
|
||||||
|
.index(1)
|
||||||
|
.help(
|
||||||
|
"Start uploading at this slot [default: first available slot]",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("ending_slot")
|
||||||
|
.long("ending-slot")
|
||||||
|
.validator(is_slot)
|
||||||
|
.value_name("SLOT")
|
||||||
|
.takes_value(true)
|
||||||
|
.index(2)
|
||||||
|
.help("Stop uploading at this slot [default: last available slot]"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("allow_missing_metadata")
|
||||||
|
.long("allow-missing-metadata")
|
||||||
|
.takes_value(false)
|
||||||
|
.help("Don't panic if transaction metadata is missing"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("first-available-block")
|
||||||
|
.about("Get the first available block in the storage"),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("blocks")
|
||||||
|
.about("Get a list of slots with confirmed blocks for the given range")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("starting_slot")
|
||||||
|
.long("starting-slot")
|
||||||
|
.validator(is_slot)
|
||||||
|
.value_name("SLOT")
|
||||||
|
.takes_value(true)
|
||||||
|
.index(1)
|
||||||
|
.required(true)
|
||||||
|
.default_value("0")
|
||||||
|
.help("Start listing at this slot"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("limit")
|
||||||
|
.long("limit")
|
||||||
|
.validator(is_slot)
|
||||||
|
.value_name("LIMIT")
|
||||||
|
.takes_value(true)
|
||||||
|
.index(2)
|
||||||
|
.required(true)
|
||||||
|
.default_value("1000")
|
||||||
|
.help("Maximum number of slots to return"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("block")
|
||||||
|
.about("Get a confirmed block")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("slot")
|
||||||
|
.long("slot")
|
||||||
|
.validator(is_slot)
|
||||||
|
.value_name("SLOT")
|
||||||
|
.takes_value(true)
|
||||||
|
.index(1)
|
||||||
|
.required(true),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("confirm")
|
||||||
|
.about("Confirm transaction by signature")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("signature")
|
||||||
|
.long("signature")
|
||||||
|
.value_name("TRANSACTION_SIGNATURE")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.index(1)
|
||||||
|
.help("The transaction signature to confirm"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("verbose")
|
||||||
|
.short("v")
|
||||||
|
.long("verbose")
|
||||||
|
.takes_value(false)
|
||||||
|
.help("Show additional information"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("transaction-history")
|
||||||
|
.about(
|
||||||
|
"Show historical transactions affecting the given address \
|
||||||
|
from newest to oldest",
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("address")
|
||||||
|
.index(1)
|
||||||
|
.value_name("ADDRESS")
|
||||||
|
.required(true)
|
||||||
|
.validator(is_valid_pubkey)
|
||||||
|
.help("Account address"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("limit")
|
||||||
|
.long("limit")
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("LIMIT")
|
||||||
|
.validator(is_slot)
|
||||||
|
.index(2)
|
||||||
|
.default_value("18446744073709551615")
|
||||||
|
.help("Maximum number of transaction signatures to return"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("before")
|
||||||
|
.long("before")
|
||||||
|
.value_name("TRANSACTION_SIGNATURE")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("Start with the first signature older than this one"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("verbose")
|
||||||
|
.short("v")
|
||||||
|
.long("verbose")
|
||||||
|
.takes_value(false)
|
||||||
|
.help("Show additional information"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
||||||
|
let mut runtime = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
|
||||||
|
let future = match matches.subcommand() {
|
||||||
|
("upload", Some(arg_matches)) => {
|
||||||
|
let starting_slot = value_t!(arg_matches, "starting_slot", Slot).unwrap_or(0);
|
||||||
|
let ending_slot = value_t!(arg_matches, "ending_slot", Slot).ok();
|
||||||
|
let allow_missing_metadata = arg_matches.is_present("allow_missing_metadata");
|
||||||
|
let blockstore =
|
||||||
|
crate::open_blockstore(&ledger_path, AccessType::TryPrimaryThenSecondary, None);
|
||||||
|
|
||||||
|
runtime.block_on(upload(
|
||||||
|
blockstore,
|
||||||
|
starting_slot,
|
||||||
|
ending_slot,
|
||||||
|
allow_missing_metadata,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
("first-available-block", Some(_arg_matches)) => runtime.block_on(first_available_block()),
|
||||||
|
("block", Some(arg_matches)) => {
|
||||||
|
let slot = value_t_or_exit!(arg_matches, "slot", Slot);
|
||||||
|
runtime.block_on(block(slot))
|
||||||
|
}
|
||||||
|
("blocks", Some(arg_matches)) => {
|
||||||
|
let starting_slot = value_t_or_exit!(arg_matches, "starting_slot", Slot);
|
||||||
|
let limit = value_t_or_exit!(arg_matches, "limit", usize);
|
||||||
|
|
||||||
|
runtime.block_on(blocks(starting_slot, limit))
|
||||||
|
}
|
||||||
|
("confirm", Some(arg_matches)) => {
|
||||||
|
let signature = arg_matches
|
||||||
|
.value_of("signature")
|
||||||
|
.unwrap()
|
||||||
|
.parse()
|
||||||
|
.expect("Invalid signature");
|
||||||
|
let verbose = arg_matches.is_present("verbose");
|
||||||
|
|
||||||
|
runtime.block_on(confirm(&signature, verbose))
|
||||||
|
}
|
||||||
|
("transaction-history", Some(arg_matches)) => {
|
||||||
|
let address = pubkey_of(arg_matches, "address").unwrap();
|
||||||
|
let limit = value_t_or_exit!(arg_matches, "limit", usize);
|
||||||
|
let before = arg_matches
|
||||||
|
.value_of("before")
|
||||||
|
.map(|signature| signature.parse().expect("Invalid signature"));
|
||||||
|
let verbose = arg_matches.is_present("verbose");
|
||||||
|
|
||||||
|
runtime.block_on(transaction_history(&address, limit, before, verbose))
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
future.unwrap_or_else(|err| {
|
||||||
|
eprintln!("{:?}", err);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
}
|
@@ -2,6 +2,7 @@ use clap::{
|
|||||||
crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App, Arg,
|
crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App, Arg,
|
||||||
ArgMatches, SubCommand,
|
ArgMatches, SubCommand,
|
||||||
};
|
};
|
||||||
|
use log::*;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use solana_clap_utils::input_validators::{is_parsable, is_slot};
|
use solana_clap_utils::input_validators::{is_parsable, is_slot};
|
||||||
@@ -43,7 +44,8 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::*;
|
mod bigtable;
|
||||||
|
use bigtable::*;
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
enum LedgerOutputMethod {
|
enum LedgerOutputMethod {
|
||||||
@@ -686,7 +688,6 @@ fn load_bank_forks(
|
|||||||
snapshot_config.as_ref(),
|
snapshot_config.as_ref(),
|
||||||
process_options,
|
process_options,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -805,6 +806,7 @@ fn main() {
|
|||||||
.global(true)
|
.global(true)
|
||||||
.help("Use DIR for ledger location"),
|
.help("Use DIR for ledger location"),
|
||||||
)
|
)
|
||||||
|
.bigtable_subcommand()
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("print")
|
SubCommand::with_name("print")
|
||||||
.about("Print the ledger")
|
.about("Print the ledger")
|
||||||
@@ -1145,6 +1147,7 @@ fn main() {
|
|||||||
.map(BlockstoreRecoveryMode::from);
|
.map(BlockstoreRecoveryMode::from);
|
||||||
|
|
||||||
match matches.subcommand() {
|
match matches.subcommand() {
|
||||||
|
("bigtable", Some(arg_matches)) => bigtable_process_command(&ledger_path, arg_matches),
|
||||||
("print", Some(arg_matches)) => {
|
("print", Some(arg_matches)) => {
|
||||||
let starting_slot = value_t_or_exit!(arg_matches, "starting_slot", Slot);
|
let starting_slot = value_t_or_exit!(arg_matches, "starting_slot", Slot);
|
||||||
let num_slots = value_t!(arg_matches, "num_slots", Slot).ok();
|
let num_slots = value_t!(arg_matches, "num_slots", Slot).ok();
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-ledger"
|
name = "solana-ledger"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana ledger"
|
description = "Solana ledger"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -29,18 +29,18 @@ reed-solomon-erasure = { version = "4.0.2", features = ["simd-accel"] }
|
|||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_bytes = "0.11.4"
|
serde_bytes = "0.11.4"
|
||||||
sha2 = "0.8.2"
|
sha2 = "0.8.2"
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.3.0" }
|
solana-transaction-status = { path = "../transaction-status", version = "1.3.1" }
|
||||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.3.0" }
|
solana-genesis-programs = { path = "../genesis-programs", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-measure = { path = "../measure", version = "1.3.0" }
|
solana-measure = { path = "../measure", version = "1.3.1" }
|
||||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.3.0" }
|
solana-merkle-tree = { path = "../merkle-tree", version = "1.3.1" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.3.0" }
|
solana-metrics = { path = "../metrics", version = "1.3.1" }
|
||||||
solana-perf = { path = "../perf", version = "1.3.0" }
|
solana-perf = { path = "../perf", version = "1.3.1" }
|
||||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.3.0" }
|
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.3.0" }
|
solana-stake-program = { path = "../programs/stake", version = "1.3.1" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.3.0" }
|
solana-vote-program = { path = "../programs/vote", version = "1.3.1" }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
trees = "0.2.1"
|
trees = "0.2.1"
|
||||||
@@ -55,7 +55,7 @@ features = ["lz4"]
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
matches = "0.1.6"
|
matches = "0.1.6"
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.3.0" }
|
solana-budget-program = { path = "../programs/budget", version = "1.3.1" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["lib"]
|
crate-type = ["lib"]
|
||||||
|
@@ -2,7 +2,7 @@ use crate::{
|
|||||||
blockstore::Blockstore,
|
blockstore::Blockstore,
|
||||||
blockstore_processor::{
|
blockstore_processor::{
|
||||||
self, BlockstoreProcessorError, BlockstoreProcessorResult, ProcessOptions,
|
self, BlockstoreProcessorError, BlockstoreProcessorResult, ProcessOptions,
|
||||||
ReplayVotesSender, TransactionStatusSender,
|
TransactionStatusSender,
|
||||||
},
|
},
|
||||||
entry::VerifyRecyclers,
|
entry::VerifyRecyclers,
|
||||||
leader_schedule_cache::LeaderScheduleCache,
|
leader_schedule_cache::LeaderScheduleCache,
|
||||||
@@ -36,7 +36,6 @@ pub fn load(
|
|||||||
snapshot_config: Option<&SnapshotConfig>,
|
snapshot_config: Option<&SnapshotConfig>,
|
||||||
process_options: ProcessOptions,
|
process_options: ProcessOptions,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
replay_votes_sender: Option<&ReplayVotesSender>,
|
|
||||||
) -> LoadResult {
|
) -> LoadResult {
|
||||||
if let Some(snapshot_config) = snapshot_config.as_ref() {
|
if let Some(snapshot_config) = snapshot_config.as_ref() {
|
||||||
info!(
|
info!(
|
||||||
@@ -90,7 +89,6 @@ pub fn load(
|
|||||||
&process_options,
|
&process_options,
|
||||||
&VerifyRecyclers::default(),
|
&VerifyRecyclers::default(),
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
replay_votes_sender,
|
|
||||||
),
|
),
|
||||||
Some(deserialized_snapshot_hash),
|
Some(deserialized_snapshot_hash),
|
||||||
);
|
);
|
||||||
|
@@ -37,14 +37,15 @@ use solana_sdk::{
|
|||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::{
|
||||||
ConfirmedBlock, ConfirmedTransaction, EncodedTransaction, Rewards, TransactionStatusMeta,
|
ConfirmedBlock, ConfirmedTransaction, ConfirmedTransactionStatusWithSignature,
|
||||||
TransactionWithStatusMeta, UiTransactionEncoding, UiTransactionStatusMeta,
|
EncodedTransaction, Rewards, TransactionStatusMeta, TransactionWithStatusMeta,
|
||||||
|
UiTransactionEncoding, UiTransactionStatusMeta,
|
||||||
};
|
};
|
||||||
use solana_vote_program::{vote_instruction::VoteInstruction, vote_state::TIMESTAMP_SLOT_INTERVAL};
|
use solana_vote_program::{vote_instruction::VoteInstruction, vote_state::TIMESTAMP_SLOT_INTERVAL};
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
cmp,
|
cmp,
|
||||||
collections::HashMap,
|
collections::{HashMap, HashSet},
|
||||||
fs,
|
fs,
|
||||||
io::{Error as IOError, ErrorKind},
|
io::{Error as IOError, ErrorKind},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
@@ -1658,7 +1659,7 @@ impl Blockstore {
|
|||||||
iterator
|
iterator
|
||||||
.map(|transaction| {
|
.map(|transaction| {
|
||||||
let signature = transaction.signatures[0];
|
let signature = transaction.signatures[0];
|
||||||
let encoded_transaction = EncodedTransaction::encode(transaction, encoding.clone());
|
let encoded_transaction = EncodedTransaction::encode(transaction, encoding);
|
||||||
TransactionWithStatusMeta {
|
TransactionWithStatusMeta {
|
||||||
transaction: encoded_transaction,
|
transaction: encoded_transaction,
|
||||||
meta: self
|
meta: self
|
||||||
@@ -1803,9 +1804,9 @@ impl Blockstore {
|
|||||||
(transaction_status_cf_primary_index, signature, 0),
|
(transaction_status_cf_primary_index, signature, 0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))?;
|
))?;
|
||||||
for ((_, sig, slot), data) in index_iterator {
|
for ((i, sig, slot), data) in index_iterator {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
if sig != signature {
|
if i != transaction_status_cf_primary_index || sig != signature {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if self.is_root(slot) {
|
if self.is_root(slot) {
|
||||||
@@ -1841,8 +1842,9 @@ impl Blockstore {
|
|||||||
("method", "get_confirmed_transaction".to_string(), String)
|
("method", "get_confirmed_transaction".to_string(), String)
|
||||||
);
|
);
|
||||||
if let Some((slot, status)) = self.get_transaction_status(signature)? {
|
if let Some((slot, status)) = self.get_transaction_status(signature)? {
|
||||||
let transaction = self.find_transaction_in_slot(slot, signature)?
|
let transaction = self
|
||||||
.expect("Transaction to exist in slot entries if it exists in statuses and hasn't been cleaned up");
|
.find_transaction_in_slot(slot, signature)?
|
||||||
|
.ok_or(BlockstoreError::TransactionStatusSlotMismatch)?; // Should not happen
|
||||||
let encoding = encoding.unwrap_or(UiTransactionEncoding::Json);
|
let encoding = encoding.unwrap_or(UiTransactionEncoding::Json);
|
||||||
let encoded_transaction = EncodedTransaction::encode(transaction, encoding);
|
let encoded_transaction = EncodedTransaction::encode(transaction, encoding);
|
||||||
Ok(Some(ConfirmedTransaction {
|
Ok(Some(ConfirmedTransaction {
|
||||||
@@ -1871,7 +1873,8 @@ impl Blockstore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns all cached signatures for an address, ordered by slot that the transaction was
|
// Returns all cached signatures for an address, ordered by slot that the transaction was
|
||||||
// processed in
|
// processed in. Within each slot the transactions will be ordered by signature, and NOT by
|
||||||
|
// the order in which the transactions exist in the block
|
||||||
fn find_address_signatures(
|
fn find_address_signatures(
|
||||||
&self,
|
&self,
|
||||||
pubkey: Pubkey,
|
pubkey: Pubkey,
|
||||||
@@ -1903,6 +1906,30 @@ impl Blockstore {
|
|||||||
Ok(signatures)
|
Ok(signatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_lowest_slot_for_address(&self, address: Pubkey) -> Result<Option<Slot>> {
|
||||||
|
let mut lowest_slot = None;
|
||||||
|
for transaction_status_cf_primary_index in 0..=1 {
|
||||||
|
let mut index_iterator = self.address_signatures_cf.iter(IteratorMode::From(
|
||||||
|
(
|
||||||
|
transaction_status_cf_primary_index,
|
||||||
|
address,
|
||||||
|
0,
|
||||||
|
Signature::default(),
|
||||||
|
),
|
||||||
|
IteratorDirection::Forward,
|
||||||
|
))?;
|
||||||
|
if let Some(((i, key_address, slot, _), _)) = index_iterator.next() {
|
||||||
|
if i == transaction_status_cf_primary_index
|
||||||
|
&& key_address == address
|
||||||
|
&& slot < lowest_slot.unwrap_or(Slot::MAX)
|
||||||
|
{
|
||||||
|
lowest_slot = Some(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(lowest_slot)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_confirmed_signatures_for_address(
|
pub fn get_confirmed_signatures_for_address(
|
||||||
&self,
|
&self,
|
||||||
pubkey: Pubkey,
|
pubkey: Pubkey,
|
||||||
@@ -1921,6 +1948,126 @@ impl Blockstore {
|
|||||||
.map(|signatures| signatures.iter().map(|(_, signature)| *signature).collect())
|
.map(|signatures| signatures.iter().map(|(_, signature)| *signature).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_confirmed_signatures_for_address2(
|
||||||
|
&self,
|
||||||
|
address: Pubkey,
|
||||||
|
highest_confirmed_root: Slot,
|
||||||
|
before: Option<Signature>,
|
||||||
|
limit: usize,
|
||||||
|
) -> Result<Vec<ConfirmedTransactionStatusWithSignature>> {
|
||||||
|
datapoint_info!(
|
||||||
|
"blockstore-rpc-api",
|
||||||
|
(
|
||||||
|
"method",
|
||||||
|
"get_confirmed_signatures_for_address2".to_string(),
|
||||||
|
String
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Figure the `slot` to start listing signatures at, based on the ledger location of the
|
||||||
|
// `before` signature if present. Also generate a HashSet of signatures that should
|
||||||
|
// be excluded from the results.
|
||||||
|
let (mut slot, mut excluded_signatures) = match before {
|
||||||
|
None => (highest_confirmed_root, None),
|
||||||
|
Some(before) => {
|
||||||
|
let transaction_status = self.get_transaction_status(before)?;
|
||||||
|
match transaction_status {
|
||||||
|
None => return Ok(vec![]),
|
||||||
|
Some((slot, _)) => {
|
||||||
|
let confirmed_block = self
|
||||||
|
.get_confirmed_block(slot, Some(UiTransactionEncoding::Binary))
|
||||||
|
.map_err(|err| {
|
||||||
|
BlockstoreError::IO(IOError::new(
|
||||||
|
ErrorKind::Other,
|
||||||
|
format!("Unable to get confirmed block: {}", err),
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Load all signatures for the block
|
||||||
|
let mut slot_signatures: Vec<_> = confirmed_block
|
||||||
|
.transactions
|
||||||
|
.iter()
|
||||||
|
.filter_map(|transaction_with_meta| {
|
||||||
|
if let Some(transaction) =
|
||||||
|
transaction_with_meta.transaction.decode()
|
||||||
|
{
|
||||||
|
transaction.signatures.into_iter().next()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Sort signatures as a way to entire a stable ordering within a slot, as
|
||||||
|
// `self.find_address_signatures()` is ordered by signatures ordered and
|
||||||
|
// not by block ordering
|
||||||
|
slot_signatures.sort();
|
||||||
|
|
||||||
|
if let Some(pos) = slot_signatures.iter().position(|&x| x == before) {
|
||||||
|
slot_signatures.truncate(pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
slot,
|
||||||
|
Some(slot_signatures.into_iter().collect::<HashSet<_>>()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch the list of signatures that affect the given address
|
||||||
|
let first_available_block = self.get_first_available_block()?;
|
||||||
|
let first_address_slot = self.get_lowest_slot_for_address(address)?;
|
||||||
|
if first_address_slot.is_none() {
|
||||||
|
return Ok(vec![]);
|
||||||
|
}
|
||||||
|
let lower_bound = cmp::max(first_available_block, first_address_slot.unwrap());
|
||||||
|
let mut address_signatures = vec![];
|
||||||
|
loop {
|
||||||
|
if address_signatures.len() >= limit {
|
||||||
|
address_signatures.truncate(limit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut signatures = self.find_address_signatures(address, slot, slot)?;
|
||||||
|
if let Some(excluded_signatures) = excluded_signatures.take() {
|
||||||
|
address_signatures.extend(
|
||||||
|
signatures
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(_, signature)| !excluded_signatures.contains(&signature)),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
address_signatures.append(&mut signatures);
|
||||||
|
}
|
||||||
|
excluded_signatures = None;
|
||||||
|
|
||||||
|
if slot == lower_bound {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
slot -= 1;
|
||||||
|
}
|
||||||
|
address_signatures.truncate(limit);
|
||||||
|
|
||||||
|
// Fill in the status information for each found transaction
|
||||||
|
let mut infos = vec![];
|
||||||
|
for (slot, signature) in address_signatures.into_iter() {
|
||||||
|
let transaction_status = self.get_transaction_status(signature)?;
|
||||||
|
let err = match transaction_status {
|
||||||
|
None => None,
|
||||||
|
Some((_slot, status)) => status.status.err(),
|
||||||
|
};
|
||||||
|
infos.push(ConfirmedTransactionStatusWithSignature {
|
||||||
|
signature,
|
||||||
|
slot,
|
||||||
|
err,
|
||||||
|
memo: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(infos)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_rewards(&self, index: Slot) -> Result<Option<Rewards>> {
|
pub fn read_rewards(&self, index: Slot) -> Result<Option<Rewards>> {
|
||||||
self.rewards_cf.get(index)
|
self.rewards_cf.get(index)
|
||||||
}
|
}
|
||||||
@@ -5942,6 +6089,19 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_transaction_status() {
|
||||||
|
let blockstore_path = get_tmp_ledger_path!();
|
||||||
|
let blockstore = Blockstore::open(&blockstore_path).unwrap();
|
||||||
|
blockstore.set_roots(&[0]).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
blockstore
|
||||||
|
.get_confirmed_transaction(Signature::default(), None)
|
||||||
|
.unwrap(),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_confirmed_signatures_for_address() {
|
fn test_get_confirmed_signatures_for_address() {
|
||||||
let blockstore_path = get_tmp_ledger_path!();
|
let blockstore_path = get_tmp_ledger_path!();
|
||||||
@@ -6082,6 +6242,244 @@ pub mod tests {
|
|||||||
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_lowest_slot_for_address() {
|
||||||
|
let blockstore_path = get_tmp_ledger_path!();
|
||||||
|
{
|
||||||
|
let blockstore = Blockstore::open(&blockstore_path).unwrap();
|
||||||
|
let address = Pubkey::new_rand();
|
||||||
|
let address2 = Pubkey::new_rand();
|
||||||
|
let slot = 5;
|
||||||
|
// Add an additional to record to ensure that existent or lower slots in entries for
|
||||||
|
// other addresses do not affect return
|
||||||
|
blockstore
|
||||||
|
.address_signatures_cf
|
||||||
|
.put(
|
||||||
|
(0, address2, slot, Signature::default()),
|
||||||
|
&AddressSignatureMeta { writeable: false },
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
blockstore.get_lowest_slot_for_address(address).unwrap(),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
|
||||||
|
let slot = 200;
|
||||||
|
blockstore
|
||||||
|
.address_signatures_cf
|
||||||
|
.put(
|
||||||
|
(0, address, slot, Signature::default()),
|
||||||
|
&AddressSignatureMeta { writeable: false },
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
blockstore.get_lowest_slot_for_address(address).unwrap(),
|
||||||
|
Some(200)
|
||||||
|
);
|
||||||
|
|
||||||
|
blockstore
|
||||||
|
.address_signatures_cf
|
||||||
|
.put(
|
||||||
|
(1, address, slot, Signature::default()),
|
||||||
|
&AddressSignatureMeta { writeable: false },
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
blockstore.get_lowest_slot_for_address(address).unwrap(),
|
||||||
|
Some(200)
|
||||||
|
);
|
||||||
|
|
||||||
|
let slot = 300;
|
||||||
|
blockstore
|
||||||
|
.address_signatures_cf
|
||||||
|
.put(
|
||||||
|
(1, address, slot, Signature::default()),
|
||||||
|
&AddressSignatureMeta { writeable: false },
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
blockstore.get_lowest_slot_for_address(address).unwrap(),
|
||||||
|
Some(200)
|
||||||
|
);
|
||||||
|
|
||||||
|
let slot = 100;
|
||||||
|
blockstore
|
||||||
|
.address_signatures_cf
|
||||||
|
.put(
|
||||||
|
(1, address, slot, Signature::default()),
|
||||||
|
&AddressSignatureMeta { writeable: false },
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
blockstore.get_lowest_slot_for_address(address).unwrap(),
|
||||||
|
Some(100)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_confirmed_signatures_for_address2() {
|
||||||
|
let blockstore_path = get_tmp_ledger_path!();
|
||||||
|
{
|
||||||
|
let blockstore = Blockstore::open(&blockstore_path).unwrap();
|
||||||
|
|
||||||
|
fn make_slot_entries_with_transaction_addresses(addresses: &[Pubkey]) -> Vec<Entry> {
|
||||||
|
let mut entries: Vec<Entry> = Vec::new();
|
||||||
|
for address in addresses {
|
||||||
|
let transaction = Transaction::new_with_compiled_instructions(
|
||||||
|
&[&Keypair::new()],
|
||||||
|
&[*address],
|
||||||
|
Hash::default(),
|
||||||
|
vec![Pubkey::new_rand()],
|
||||||
|
vec![CompiledInstruction::new(1, &(), vec![0])],
|
||||||
|
);
|
||||||
|
entries.push(next_entry_mut(&mut Hash::default(), 0, vec![transaction]));
|
||||||
|
let mut tick = create_ticks(1, 0, hash(&serialize(address).unwrap()));
|
||||||
|
entries.append(&mut tick);
|
||||||
|
}
|
||||||
|
entries
|
||||||
|
}
|
||||||
|
|
||||||
|
let address0 = Pubkey::new_rand();
|
||||||
|
let address1 = Pubkey::new_rand();
|
||||||
|
|
||||||
|
for slot in 2..=4 {
|
||||||
|
let entries = make_slot_entries_with_transaction_addresses(&[
|
||||||
|
address0, address1, address0, address1,
|
||||||
|
]);
|
||||||
|
let shreds = entries_to_test_shreds(entries.clone(), slot, slot - 1, true, 0);
|
||||||
|
blockstore.insert_shreds(shreds, None, false).unwrap();
|
||||||
|
|
||||||
|
for entry in &entries {
|
||||||
|
for transaction in &entry.transactions {
|
||||||
|
assert_eq!(transaction.signatures.len(), 1);
|
||||||
|
blockstore
|
||||||
|
.write_transaction_status(
|
||||||
|
slot,
|
||||||
|
transaction.signatures[0],
|
||||||
|
transaction.message.account_keys.iter().collect(),
|
||||||
|
vec![],
|
||||||
|
&TransactionStatusMeta::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blockstore.set_roots(&[1, 2, 3, 4]).unwrap();
|
||||||
|
let highest_confirmed_root = 4;
|
||||||
|
|
||||||
|
// Fetch all signatures for address 0 at once...
|
||||||
|
let all0 = blockstore
|
||||||
|
.get_confirmed_signatures_for_address2(
|
||||||
|
address0,
|
||||||
|
highest_confirmed_root,
|
||||||
|
None,
|
||||||
|
usize::MAX,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(all0.len(), 6);
|
||||||
|
|
||||||
|
// Fetch all signatures for address 1 at once...
|
||||||
|
let all1 = blockstore
|
||||||
|
.get_confirmed_signatures_for_address2(
|
||||||
|
address1,
|
||||||
|
highest_confirmed_root,
|
||||||
|
None,
|
||||||
|
usize::MAX,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(all1.len(), 6);
|
||||||
|
|
||||||
|
assert!(all0 != all1);
|
||||||
|
|
||||||
|
// Fetch all signatures for address 0 individually
|
||||||
|
for i in 0..all0.len() {
|
||||||
|
let results = blockstore
|
||||||
|
.get_confirmed_signatures_for_address2(
|
||||||
|
address0,
|
||||||
|
highest_confirmed_root,
|
||||||
|
if i == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(all0[i - 1].signature)
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(results.len(), 1);
|
||||||
|
assert_eq!(results[0], all0[i], "Unexpected result for {}", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(blockstore
|
||||||
|
.get_confirmed_signatures_for_address2(
|
||||||
|
address0,
|
||||||
|
highest_confirmed_root,
|
||||||
|
Some(all0[all0.len() - 1].signature),
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.is_empty());
|
||||||
|
|
||||||
|
// Fetch all signatures for address 0, three at a time
|
||||||
|
assert!(all0.len() % 3 == 0);
|
||||||
|
for i in (0..all0.len()).step_by(3) {
|
||||||
|
let results = blockstore
|
||||||
|
.get_confirmed_signatures_for_address2(
|
||||||
|
address0,
|
||||||
|
highest_confirmed_root,
|
||||||
|
if i == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(all0[i - 1].signature)
|
||||||
|
},
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(results.len(), 3);
|
||||||
|
assert_eq!(results[0], all0[i]);
|
||||||
|
assert_eq!(results[1], all0[i + 1]);
|
||||||
|
assert_eq!(results[2], all0[i + 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the signatures within a slot are ordered by signature
|
||||||
|
// (current limitation of the .get_confirmed_signatures_for_address2())
|
||||||
|
for i in (0..all1.len()).step_by(2) {
|
||||||
|
let results = blockstore
|
||||||
|
.get_confirmed_signatures_for_address2(
|
||||||
|
address1,
|
||||||
|
highest_confirmed_root,
|
||||||
|
if i == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(all1[i - 1].signature)
|
||||||
|
},
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(results.len(), 2);
|
||||||
|
assert_eq!(results[0].slot, results[1].slot);
|
||||||
|
assert!(results[0].signature <= results[1].signature);
|
||||||
|
assert_eq!(results[0], all1[i]);
|
||||||
|
assert_eq!(results[1], all1[i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A search for address 0 with a `before` signature from address1 should also work
|
||||||
|
let results = blockstore
|
||||||
|
.get_confirmed_signatures_for_address2(
|
||||||
|
address0,
|
||||||
|
highest_confirmed_root,
|
||||||
|
Some(all1[0].signature),
|
||||||
|
usize::MAX,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
// The exact number of results returned is variable, based on the sort order of the
|
||||||
|
// random signatures that are generated
|
||||||
|
assert!(!results.is_empty());
|
||||||
|
}
|
||||||
|
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_last_hash() {
|
fn test_get_last_hash() {
|
||||||
let mut entries: Vec<Entry> = vec![];
|
let mut entries: Vec<Entry> = vec![];
|
||||||
|
@@ -58,6 +58,7 @@ pub enum BlockstoreError {
|
|||||||
SlotCleanedUp,
|
SlotCleanedUp,
|
||||||
UnpackError(#[from] UnpackError),
|
UnpackError(#[from] UnpackError),
|
||||||
UnableToSetOpenFileDescriptorLimit,
|
UnableToSetOpenFileDescriptorLimit,
|
||||||
|
TransactionStatusSlotMismatch,
|
||||||
}
|
}
|
||||||
pub type Result<T> = std::result::Result<T, BlockstoreError>;
|
pub type Result<T> = std::result::Result<T, BlockstoreError>;
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@ use crate::{
|
|||||||
entry::{create_ticks, Entry, EntrySlice, EntryVerificationStatus, VerifyRecyclers},
|
entry::{create_ticks, Entry, EntrySlice, EntryVerificationStatus, VerifyRecyclers},
|
||||||
leader_schedule_cache::LeaderScheduleCache,
|
leader_schedule_cache::LeaderScheduleCache,
|
||||||
};
|
};
|
||||||
use crossbeam_channel::{Receiver, Sender};
|
use crossbeam_channel::Sender;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use log::*;
|
use log::*;
|
||||||
use rand::{seq::SliceRandom, thread_rng};
|
use rand::{seq::SliceRandom, thread_rng};
|
||||||
@@ -17,8 +17,10 @@ use solana_rayon_threadlimit::get_thread_count;
|
|||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
bank::{Bank, TransactionBalancesSet, TransactionProcessResult, TransactionResults},
|
bank::{Bank, TransactionBalancesSet, TransactionProcessResult, TransactionResults},
|
||||||
bank_forks::BankForks,
|
bank_forks::BankForks,
|
||||||
|
bank_utils,
|
||||||
transaction_batch::TransactionBatch,
|
transaction_batch::TransactionBatch,
|
||||||
transaction_utils::OrderedIterator,
|
transaction_utils::OrderedIterator,
|
||||||
|
vote_sender_types::ReplayVoteSender,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{Slot, MAX_PROCESSING_AGE},
|
clock::{Slot, MAX_PROCESSING_AGE},
|
||||||
@@ -29,7 +31,6 @@ use solana_sdk::{
|
|||||||
timing::duration_as_ms,
|
timing::duration_as_ms,
|
||||||
transaction::{Result, Transaction, TransactionError},
|
transaction::{Result, Transaction, TransactionError},
|
||||||
};
|
};
|
||||||
use solana_vote_program::{vote_state::Vote, vote_transaction};
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@@ -43,10 +44,6 @@ use thiserror::Error;
|
|||||||
pub type BlockstoreProcessorResult =
|
pub type BlockstoreProcessorResult =
|
||||||
result::Result<(BankForks, LeaderScheduleCache), BlockstoreProcessorError>;
|
result::Result<(BankForks, LeaderScheduleCache), BlockstoreProcessorError>;
|
||||||
|
|
||||||
pub type ReplayedVote = (Pubkey, Vote, Option<Hash>);
|
|
||||||
pub type ReplayVotesSender = Sender<ReplayedVote>;
|
|
||||||
pub type ReplayVotesReceiver = Receiver<ReplayedVote>;
|
|
||||||
|
|
||||||
thread_local!(static PAR_THREAD_POOL: RefCell<ThreadPool> = RefCell::new(rayon::ThreadPoolBuilder::new()
|
thread_local!(static PAR_THREAD_POOL: RefCell<ThreadPool> = RefCell::new(rayon::ThreadPoolBuilder::new()
|
||||||
.num_threads(get_thread_count())
|
.num_threads(get_thread_count())
|
||||||
.thread_name(|ix| format!("blockstore_processor_{}", ix))
|
.thread_name(|ix| format!("blockstore_processor_{}", ix))
|
||||||
@@ -69,7 +66,7 @@ fn get_first_error(
|
|||||||
fee_collection_results: Vec<Result<()>>,
|
fee_collection_results: Vec<Result<()>>,
|
||||||
) -> Option<(Result<()>, Signature)> {
|
) -> Option<(Result<()>, Signature)> {
|
||||||
let mut first_err = None;
|
let mut first_err = None;
|
||||||
for (result, transaction) in fee_collection_results.iter().zip(OrderedIterator::new(
|
for (result, (_, transaction)) in fee_collection_results.iter().zip(OrderedIterator::new(
|
||||||
batch.transactions(),
|
batch.transactions(),
|
||||||
batch.iteration_order(),
|
batch.iteration_order(),
|
||||||
)) {
|
)) {
|
||||||
@@ -98,32 +95,21 @@ fn execute_batch(
|
|||||||
batch: &TransactionBatch,
|
batch: &TransactionBatch,
|
||||||
bank: &Arc<Bank>,
|
bank: &Arc<Bank>,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
replay_votes_sender: Option<&ReplayVotesSender>,
|
replay_vote_sender: Option<&ReplayVoteSender>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (
|
let (tx_results, balances) = batch.bank().load_execute_and_commit_transactions(
|
||||||
TransactionResults {
|
|
||||||
fee_collection_results,
|
|
||||||
processing_results,
|
|
||||||
},
|
|
||||||
balances,
|
|
||||||
) = batch.bank().load_execute_and_commit_transactions(
|
|
||||||
batch,
|
batch,
|
||||||
MAX_PROCESSING_AGE,
|
MAX_PROCESSING_AGE,
|
||||||
transaction_status_sender.is_some(),
|
transaction_status_sender.is_some(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(replay_votes_sender) = replay_votes_sender {
|
bank_utils::find_and_send_votes(batch.transactions(), &tx_results, replay_vote_sender);
|
||||||
for (transaction, (processing_result, _)) in
|
|
||||||
OrderedIterator::new(batch.transactions(), batch.iteration_order())
|
let TransactionResults {
|
||||||
.zip(&processing_results)
|
fee_collection_results,
|
||||||
{
|
processing_results,
|
||||||
if processing_result.is_ok() {
|
..
|
||||||
if let Some(parsed_vote) = vote_transaction::parse_vote_transaction(transaction) {
|
} = tx_results;
|
||||||
let _ = replay_votes_sender.send(parsed_vote);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(sender) = transaction_status_sender {
|
if let Some(sender) = transaction_status_sender {
|
||||||
send_transaction_status_batch(
|
send_transaction_status_batch(
|
||||||
@@ -145,7 +131,7 @@ fn execute_batches(
|
|||||||
batches: &[TransactionBatch],
|
batches: &[TransactionBatch],
|
||||||
entry_callback: Option<&ProcessCallback>,
|
entry_callback: Option<&ProcessCallback>,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
replay_votes_sender: Option<&ReplayVotesSender>,
|
replay_vote_sender: Option<&ReplayVoteSender>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
inc_new_counter_debug!("bank-par_execute_entries-count", batches.len());
|
inc_new_counter_debug!("bank-par_execute_entries-count", batches.len());
|
||||||
let results: Vec<Result<()>> = PAR_THREAD_POOL.with(|thread_pool| {
|
let results: Vec<Result<()>> = PAR_THREAD_POOL.with(|thread_pool| {
|
||||||
@@ -153,7 +139,7 @@ fn execute_batches(
|
|||||||
batches
|
batches
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map_with(transaction_status_sender, |sender, batch| {
|
.map_with(transaction_status_sender, |sender, batch| {
|
||||||
let result = execute_batch(batch, bank, sender.clone(), replay_votes_sender);
|
let result = execute_batch(batch, bank, sender.clone(), replay_vote_sender);
|
||||||
if let Some(entry_callback) = entry_callback {
|
if let Some(entry_callback) = entry_callback {
|
||||||
entry_callback(bank);
|
entry_callback(bank);
|
||||||
}
|
}
|
||||||
@@ -176,7 +162,7 @@ pub fn process_entries(
|
|||||||
entries: &[Entry],
|
entries: &[Entry],
|
||||||
randomize: bool,
|
randomize: bool,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
replay_votes_sender: Option<&ReplayVotesSender>,
|
replay_vote_sender: Option<&ReplayVoteSender>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
process_entries_with_callback(
|
process_entries_with_callback(
|
||||||
bank,
|
bank,
|
||||||
@@ -184,7 +170,7 @@ pub fn process_entries(
|
|||||||
randomize,
|
randomize,
|
||||||
None,
|
None,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
replay_votes_sender,
|
replay_vote_sender,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +180,7 @@ fn process_entries_with_callback(
|
|||||||
randomize: bool,
|
randomize: bool,
|
||||||
entry_callback: Option<&ProcessCallback>,
|
entry_callback: Option<&ProcessCallback>,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
replay_votes_sender: Option<&ReplayVotesSender>,
|
replay_vote_sender: Option<&ReplayVoteSender>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// accumulator for entries that can be processed in parallel
|
// accumulator for entries that can be processed in parallel
|
||||||
let mut batches = vec![];
|
let mut batches = vec![];
|
||||||
@@ -211,7 +197,7 @@ fn process_entries_with_callback(
|
|||||||
&batches,
|
&batches,
|
||||||
entry_callback,
|
entry_callback,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
replay_votes_sender,
|
replay_vote_sender,
|
||||||
)?;
|
)?;
|
||||||
batches.clear();
|
batches.clear();
|
||||||
for hash in &tick_hashes {
|
for hash in &tick_hashes {
|
||||||
@@ -267,7 +253,7 @@ fn process_entries_with_callback(
|
|||||||
&batches,
|
&batches,
|
||||||
entry_callback,
|
entry_callback,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
replay_votes_sender,
|
replay_vote_sender,
|
||||||
)?;
|
)?;
|
||||||
batches.clear();
|
batches.clear();
|
||||||
}
|
}
|
||||||
@@ -278,7 +264,7 @@ fn process_entries_with_callback(
|
|||||||
&batches,
|
&batches,
|
||||||
entry_callback,
|
entry_callback,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
replay_votes_sender,
|
replay_vote_sender,
|
||||||
)?;
|
)?;
|
||||||
for hash in tick_hashes {
|
for hash in tick_hashes {
|
||||||
bank.register_tick(&hash);
|
bank.register_tick(&hash);
|
||||||
@@ -345,15 +331,7 @@ pub fn process_blockstore(
|
|||||||
info!("processing ledger for slot 0...");
|
info!("processing ledger for slot 0...");
|
||||||
let recyclers = VerifyRecyclers::default();
|
let recyclers = VerifyRecyclers::default();
|
||||||
process_bank_0(&bank0, blockstore, &opts, &recyclers)?;
|
process_bank_0(&bank0, blockstore, &opts, &recyclers)?;
|
||||||
process_blockstore_from_root(
|
process_blockstore_from_root(genesis_config, blockstore, bank0, &opts, &recyclers, None)
|
||||||
genesis_config,
|
|
||||||
blockstore,
|
|
||||||
bank0,
|
|
||||||
&opts,
|
|
||||||
&recyclers,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process blockstore from a known root bank
|
// Process blockstore from a known root bank
|
||||||
@@ -364,7 +342,6 @@ pub fn process_blockstore_from_root(
|
|||||||
opts: &ProcessOptions,
|
opts: &ProcessOptions,
|
||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
replay_votes_sender: Option<&ReplayVotesSender>,
|
|
||||||
) -> BlockstoreProcessorResult {
|
) -> BlockstoreProcessorResult {
|
||||||
info!("processing ledger from slot {}...", bank.slot());
|
info!("processing ledger from slot {}...", bank.slot());
|
||||||
let allocated = thread_mem_usage::Allocatedp::default();
|
let allocated = thread_mem_usage::Allocatedp::default();
|
||||||
@@ -430,7 +407,6 @@ pub fn process_blockstore_from_root(
|
|||||||
opts,
|
opts,
|
||||||
recyclers,
|
recyclers,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
replay_votes_sender,
|
|
||||||
)?;
|
)?;
|
||||||
(initial_forks, leader_schedule_cache)
|
(initial_forks, leader_schedule_cache)
|
||||||
} else {
|
} else {
|
||||||
@@ -520,7 +496,7 @@ fn confirm_full_slot(
|
|||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
progress: &mut ConfirmationProgress,
|
progress: &mut ConfirmationProgress,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
replay_votes_sender: Option<&ReplayVotesSender>,
|
replay_vote_sender: Option<&ReplayVoteSender>,
|
||||||
) -> result::Result<(), BlockstoreProcessorError> {
|
) -> result::Result<(), BlockstoreProcessorError> {
|
||||||
let mut timing = ConfirmationTiming::default();
|
let mut timing = ConfirmationTiming::default();
|
||||||
let skip_verification = !opts.poh_verify;
|
let skip_verification = !opts.poh_verify;
|
||||||
@@ -531,7 +507,7 @@ fn confirm_full_slot(
|
|||||||
progress,
|
progress,
|
||||||
skip_verification,
|
skip_verification,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
replay_votes_sender,
|
replay_vote_sender,
|
||||||
opts.entry_callback.as_ref(),
|
opts.entry_callback.as_ref(),
|
||||||
recyclers,
|
recyclers,
|
||||||
)?;
|
)?;
|
||||||
@@ -592,7 +568,7 @@ pub fn confirm_slot(
|
|||||||
progress: &mut ConfirmationProgress,
|
progress: &mut ConfirmationProgress,
|
||||||
skip_verification: bool,
|
skip_verification: bool,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
replay_votes_sender: Option<&ReplayVotesSender>,
|
replay_vote_sender: Option<&ReplayVoteSender>,
|
||||||
entry_callback: Option<&ProcessCallback>,
|
entry_callback: Option<&ProcessCallback>,
|
||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
) -> result::Result<(), BlockstoreProcessorError> {
|
) -> result::Result<(), BlockstoreProcessorError> {
|
||||||
@@ -660,7 +636,7 @@ pub fn confirm_slot(
|
|||||||
true,
|
true,
|
||||||
entry_callback,
|
entry_callback,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
replay_votes_sender,
|
replay_vote_sender,
|
||||||
)
|
)
|
||||||
.map_err(BlockstoreProcessorError::from);
|
.map_err(BlockstoreProcessorError::from);
|
||||||
replay_elapsed.stop();
|
replay_elapsed.stop();
|
||||||
@@ -779,7 +755,6 @@ fn load_frozen_forks(
|
|||||||
opts: &ProcessOptions,
|
opts: &ProcessOptions,
|
||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
replay_votes_sender: Option<&ReplayVotesSender>,
|
|
||||||
) -> result::Result<Vec<Arc<Bank>>, BlockstoreProcessorError> {
|
) -> result::Result<Vec<Arc<Bank>>, BlockstoreProcessorError> {
|
||||||
let mut initial_forks = HashMap::new();
|
let mut initial_forks = HashMap::new();
|
||||||
let mut last_status_report = Instant::now();
|
let mut last_status_report = Instant::now();
|
||||||
@@ -819,6 +794,7 @@ fn load_frozen_forks(
|
|||||||
let initial_allocation = allocated.get();
|
let initial_allocation = allocated.get();
|
||||||
|
|
||||||
let mut progress = ConfirmationProgress::new(last_entry_hash);
|
let mut progress = ConfirmationProgress::new(last_entry_hash);
|
||||||
|
|
||||||
if process_single_slot(
|
if process_single_slot(
|
||||||
blockstore,
|
blockstore,
|
||||||
&bank,
|
&bank,
|
||||||
@@ -826,7 +802,7 @@ fn load_frozen_forks(
|
|||||||
recyclers,
|
recyclers,
|
||||||
&mut progress,
|
&mut progress,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
replay_votes_sender,
|
None,
|
||||||
)
|
)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
@@ -877,11 +853,11 @@ fn process_single_slot(
|
|||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
progress: &mut ConfirmationProgress,
|
progress: &mut ConfirmationProgress,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
replay_votes_sender: Option<&ReplayVotesSender>,
|
replay_vote_sender: Option<&ReplayVoteSender>,
|
||||||
) -> result::Result<(), BlockstoreProcessorError> {
|
) -> result::Result<(), BlockstoreProcessorError> {
|
||||||
// Mark corrupt slots as dead so validators don't replay this slot and
|
// Mark corrupt slots as dead so validators don't replay this slot and
|
||||||
// see DuplicateSignature errors later in ReplayStage
|
// see DuplicateSignature errors later in ReplayStage
|
||||||
confirm_full_slot(blockstore, bank, opts, recyclers, progress, transaction_status_sender, replay_votes_sender).map_err(|err| {
|
confirm_full_slot(blockstore, bank, opts, recyclers, progress, transaction_status_sender, replay_vote_sender).map_err(|err| {
|
||||||
let slot = bank.slot();
|
let slot = bank.slot();
|
||||||
warn!("slot {} failed to verify: {}", slot, err);
|
warn!("slot {} failed to verify: {}", slot, err);
|
||||||
if blockstore.is_primary_access() {
|
if blockstore.is_primary_access() {
|
||||||
@@ -987,6 +963,7 @@ pub mod tests {
|
|||||||
system_transaction,
|
system_transaction,
|
||||||
transaction::{Transaction, TransactionError},
|
transaction::{Transaction, TransactionError},
|
||||||
};
|
};
|
||||||
|
use solana_vote_program::vote_transaction;
|
||||||
use std::{collections::BTreeSet, sync::RwLock};
|
use std::{collections::BTreeSet, sync::RwLock};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -2532,7 +2509,6 @@ pub mod tests {
|
|||||||
&opts,
|
&opts,
|
||||||
&recyclers,
|
&recyclers,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -2760,7 +2736,7 @@ pub mod tests {
|
|||||||
let (
|
let (
|
||||||
TransactionResults {
|
TransactionResults {
|
||||||
fee_collection_results,
|
fee_collection_results,
|
||||||
processing_results: _,
|
..
|
||||||
},
|
},
|
||||||
_balances,
|
_balances,
|
||||||
) = batch
|
) = batch
|
||||||
@@ -2840,9 +2816,9 @@ pub mod tests {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let entry = next_entry(&bank_1_blockhash, 1, vote_txs);
|
let entry = next_entry(&bank_1_blockhash, 1, vote_txs);
|
||||||
let (replay_votes_sender, replay_votes_receiver) = unbounded();
|
let (replay_vote_sender, replay_vote_receiver) = unbounded();
|
||||||
let _ = process_entries(&bank1, &[entry], true, None, Some(&replay_votes_sender));
|
let _ = process_entries(&bank1, &[entry], true, None, Some(&replay_vote_sender));
|
||||||
let successes: BTreeSet<Pubkey> = replay_votes_receiver
|
let successes: BTreeSet<Pubkey> = replay_vote_receiver
|
||||||
.try_iter()
|
.try_iter()
|
||||||
.map(|(vote_pubkey, _, _)| vote_pubkey)
|
.map(|(vote_pubkey, _, _)| vote_pubkey)
|
||||||
.collect();
|
.collect();
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-local-cluster"
|
name = "solana-local-cluster"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -13,22 +13,22 @@ itertools = "0.9.0"
|
|||||||
gag = "0.1.10"
|
gag = "0.1.10"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
rand = "0.7.0"
|
rand = "0.7.0"
|
||||||
solana-config-program = { path = "../programs/config", version = "1.3.0" }
|
solana-config-program = { path = "../programs/config", version = "1.3.1" }
|
||||||
solana-core = { path = "../core", version = "1.3.0" }
|
solana-core = { path = "../core", version = "1.3.1" }
|
||||||
solana-client = { path = "../client", version = "1.3.0" }
|
solana-client = { path = "../client", version = "1.3.1" }
|
||||||
solana-download-utils = { path = "../download-utils", version = "1.3.0" }
|
solana-download-utils = { path = "../download-utils", version = "1.3.1" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.3.0" }
|
solana-faucet = { path = "../faucet", version = "1.3.1" }
|
||||||
solana-exchange-program = { path = "../programs/exchange", version = "1.3.0" }
|
solana-exchange-program = { path = "../programs/exchange", version = "1.3.1" }
|
||||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.3.0" }
|
solana-genesis-programs = { path = "../genesis-programs", version = "1.3.1" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.3.0" }
|
solana-ledger = { path = "../ledger", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../runtime", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.3.0" }
|
solana-stake-program = { path = "../programs/stake", version = "1.3.1" }
|
||||||
solana-vest-program = { path = "../programs/vest", version = "1.3.0" }
|
solana-vest-program = { path = "../programs/vest", version = "1.3.1" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.3.0" }
|
solana-vote-program = { path = "../programs/vote", version = "1.3.1" }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.3.0" }
|
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.3.1" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-log-analyzer"
|
name = "solana-log-analyzer"
|
||||||
description = "The solana cluster network analysis tool"
|
description = "The solana cluster network analysis tool"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -14,9 +14,9 @@ byte-unit = "4.0.8"
|
|||||||
clap = "2.33.1"
|
clap = "2.33.1"
|
||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "solana-log-analyzer"
|
name = "solana-log-analyzer"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-logger"
|
name = "solana-logger"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana Logger"
|
description = "Solana Logger"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-measure"
|
name = "solana-measure"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
documentation = "https://docs.rs/solana"
|
documentation = "https://docs.rs/solana"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
readme = "../README.md"
|
readme = "../README.md"
|
||||||
@@ -12,8 +12,8 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.3.0" }
|
solana-metrics = { path = "../metrics", version = "1.3.1" }
|
||||||
|
|
||||||
[target."cfg(unix)".dependencies]
|
[target."cfg(unix)".dependencies]
|
||||||
jemallocator = "0.3.2"
|
jemallocator = "0.3.2"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-merkle-tree"
|
name = "solana-merkle-tree"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana Merkle Tree"
|
description = "Solana Merkle Tree"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -9,7 +9,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
fast-math = "0.1"
|
fast-math = "0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-metrics"
|
name = "solana-metrics"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana Metrics"
|
description = "Solana Metrics"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -14,7 +14,7 @@ gethostname = "0.2.1"
|
|||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
reqwest = { version = "0.10.6", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
reqwest = { version = "0.10.6", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.7.0"
|
rand = "0.7.0"
|
||||||
|
@@ -48,6 +48,9 @@ while [[ -n $1 ]]; do
|
|||||||
elif [[ $1 = --enable-rpc-transaction-history ]]; then
|
elif [[ $1 = --enable-rpc-transaction-history ]]; then
|
||||||
args+=("$1")
|
args+=("$1")
|
||||||
shift
|
shift
|
||||||
|
elif [[ $1 = --enable-rpc-bigtable-ledger-storage ]]; then
|
||||||
|
args+=("$1")
|
||||||
|
shift
|
||||||
elif [[ $1 = --skip-poh-verify ]]; then
|
elif [[ $1 = --skip-poh-verify ]]; then
|
||||||
args+=("$1")
|
args+=("$1")
|
||||||
shift
|
shift
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-net-shaper"
|
name = "solana-net-shaper"
|
||||||
description = "The solana cluster network shaping tool"
|
description = "The solana cluster network shaping tool"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -13,8 +13,8 @@ publish = false
|
|||||||
clap = "2.33.1"
|
clap = "2.33.1"
|
||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
rand = "0.7.0"
|
rand = "0.7.0"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-net-utils"
|
name = "solana-net-utils"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana Network Utilities"
|
description = "Solana Network Utilities"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -18,9 +18,9 @@ rand = "0.7.0"
|
|||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
socket2 = "0.3.12"
|
socket2 = "0.3.12"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
tokio = "0.1"
|
tokio = "0.1"
|
||||||
tokio-codec = "0.1"
|
tokio-codec = "0.1"
|
||||||
url = "2.1.1"
|
url = "2.1.1"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-notifier"
|
name = "solana-notifier"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana Notifier"
|
description = "Solana Notifier"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-perf"
|
name = "solana-perf"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana Performance APIs"
|
description = "Solana Performance APIs"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -17,11 +17,11 @@ serde = "1.0.112"
|
|||||||
dlopen_derive = "0.1.4"
|
dlopen_derive = "0.1.4"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.3.0" }
|
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.3.1" }
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.3.0" }
|
solana-budget-program = { path = "../programs/budget", version = "1.3.1" }
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.3.0" }
|
solana-metrics = { path = "../metrics", version = "1.3.1" }
|
||||||
curve25519-dalek = { version = "2" }
|
curve25519-dalek = { version = "2" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-poh-bench"
|
name = "solana-poh-bench"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -12,13 +12,13 @@ clap = "2.33.1"
|
|||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
rand = "0.7.0"
|
rand = "0.7.0"
|
||||||
rayon = "1.3.0"
|
rayon = "1.3.0"
|
||||||
solana-logger = { path = "../logger", version = "1.3.0" }
|
solana-logger = { path = "../logger", version = "1.3.1" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.3.0" }
|
solana-ledger = { path = "../ledger", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../sdk", version = "1.3.1" }
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.3.1" }
|
||||||
solana-measure = { path = "../measure", version = "1.3.0" }
|
solana-measure = { path = "../measure", version = "1.3.1" }
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.1" }
|
||||||
solana-perf = { path = "../perf", version = "1.3.0" }
|
solana-perf = { path = "../perf", version = "1.3.1" }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
74
programs/bpf/Cargo.lock
generated
74
programs/bpf/Cargo.lock
generated
@@ -250,6 +250,16 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-deque"
|
name = "crossbeam-deque"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
@@ -1602,7 +1612,7 @@ checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-loader-program"
|
name = "solana-bpf-loader-program"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"byteorder 1.3.4",
|
"byteorder 1.3.4",
|
||||||
@@ -1617,7 +1627,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-programs"
|
name = "solana-bpf-programs"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"byteorder 1.3.4",
|
"byteorder 1.3.4",
|
||||||
@@ -1632,7 +1642,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-128bit"
|
name = "solana-bpf-rust-128bit"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-bpf-rust-128bit-dep",
|
"solana-bpf-rust-128bit-dep",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
@@ -1640,21 +1650,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-128bit-dep"
|
name = "solana-bpf-rust-128bit-dep"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-alloc"
|
name = "solana-bpf-rust-alloc"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-dep-crate"
|
name = "solana-bpf-rust-dep-crate"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.4",
|
"byteorder 1.3.4",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
@@ -1662,14 +1672,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-dup-accounts"
|
name = "solana-bpf-rust-dup-accounts"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-error-handling"
|
name = "solana-bpf-rust-error-handling"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-derive 0.2.5",
|
"num-derive 0.2.5",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -1679,14 +1689,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-external-spend"
|
name = "solana-bpf-rust-external-spend"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-invoke"
|
name = "solana-bpf-rust-invoke"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-bpf-rust-invoked",
|
"solana-bpf-rust-invoked",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
@@ -1694,21 +1704,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-invoked"
|
name = "solana-bpf-rust-invoked"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-iter"
|
name = "solana-bpf-rust-iter"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-many-args"
|
name = "solana-bpf-rust-many-args"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-bpf-rust-many-args-dep",
|
"solana-bpf-rust-many-args-dep",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
@@ -1716,28 +1726,28 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-many-args-dep"
|
name = "solana-bpf-rust-many-args-dep"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-noop"
|
name = "solana-bpf-rust-noop"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-panic"
|
name = "solana-bpf-rust-panic"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-param-passing"
|
name = "solana-bpf-rust-param-passing"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-bpf-rust-param-passing-dep",
|
"solana-bpf-rust-param-passing-dep",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
@@ -1745,21 +1755,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-param-passing-dep"
|
name = "solana-bpf-rust-param-passing-dep"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-sysval"
|
name = "solana-bpf-rust-sysval"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-config-program"
|
name = "solana-config-program"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -1771,7 +1781,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-crate-features"
|
name = "solana-crate-features"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes 0.4.12",
|
"bytes 0.4.12",
|
||||||
@@ -1794,7 +1804,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-logger"
|
name = "solana-logger"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@@ -1803,7 +1813,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-measure"
|
name = "solana-measure"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jemalloc-ctl",
|
"jemalloc-ctl",
|
||||||
"jemallocator",
|
"jemallocator",
|
||||||
@@ -1814,7 +1824,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-metrics"
|
name = "solana-metrics"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"gethostname",
|
"gethostname",
|
||||||
@@ -1826,7 +1836,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-rayon-threadlimit"
|
name = "solana-rayon-threadlimit"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
@@ -1834,12 +1844,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-runtime"
|
name = "solana-runtime"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"bv",
|
"bv",
|
||||||
"byteorder 1.3.4",
|
"byteorder 1.3.4",
|
||||||
"bzip2",
|
"bzip2",
|
||||||
|
"crossbeam-channel",
|
||||||
"dir-diff",
|
"dir-diff",
|
||||||
"flate2",
|
"flate2",
|
||||||
"fnv",
|
"fnv",
|
||||||
@@ -1877,7 +1888,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-sdk"
|
name = "solana-sdk"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"bincode",
|
"bincode",
|
||||||
@@ -1885,6 +1896,7 @@ dependencies = [
|
|||||||
"bv",
|
"bv",
|
||||||
"byteorder 1.3.4",
|
"byteorder 1.3.4",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"curve25519-dalek",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
"generic-array 0.14.3",
|
"generic-array 0.14.3",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -1913,7 +1925,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-sdk-macro"
|
name = "solana-sdk-macro"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bs58",
|
"bs58",
|
||||||
"proc-macro2 1.0.19",
|
"proc-macro2 1.0.19",
|
||||||
@@ -1924,7 +1936,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-sdk-macro-frozen-abi"
|
name = "solana-sdk-macro-frozen-abi"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"proc-macro2 1.0.19",
|
"proc-macro2 1.0.19",
|
||||||
@@ -1935,7 +1947,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-stake-program"
|
name = "solana-stake-program"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"log",
|
"log",
|
||||||
@@ -1954,7 +1966,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-vote-program"
|
name = "solana-vote-program"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"log",
|
"log",
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-programs"
|
name = "solana-bpf-programs"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
documentation = "https://docs.rs/solana"
|
documentation = "https://docs.rs/solana"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
@@ -22,10 +22,10 @@ walkdir = "2"
|
|||||||
bincode = "1.1.4"
|
bincode = "1.1.4"
|
||||||
byteorder = "1.3.2"
|
byteorder = "1.3.2"
|
||||||
elf = "0.0.10"
|
elf = "0.0.10"
|
||||||
solana-bpf-loader-program = { path = "../bpf_loader", version = "1.3.0" }
|
solana-bpf-loader-program = { path = "../bpf_loader", version = "1.3.1" }
|
||||||
solana-logger = { path = "../../logger", version = "1.3.0" }
|
solana-logger = { path = "../../logger", version = "1.3.1" }
|
||||||
solana-runtime = { path = "../../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../../runtime", version = "1.3.1" }
|
||||||
solana-sdk = { path = "../../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../../sdk", version = "1.3.1" }
|
||||||
solana_rbpf = "=0.1.28"
|
solana_rbpf = "=0.1.28"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
|
@@ -30,6 +30,10 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||||||
return ERROR_INVALID_ARGUMENT;
|
return ERROR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t nonce1 = params.data[1];
|
||||||
|
uint8_t nonce2 = params.data[2];
|
||||||
|
uint8_t nonce3 = params.data[3];
|
||||||
|
|
||||||
switch (params.data[0]) {
|
switch (params.data[0]) {
|
||||||
case TEST_SUCCESS: {
|
case TEST_SUCCESS: {
|
||||||
sol_log("Call system program");
|
sol_log("Call system program");
|
||||||
@@ -81,6 +85,18 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||||||
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
|
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sol_log("Test create_program_address");
|
||||||
|
{
|
||||||
|
uint8_t seed1[] = {'Y', 'o', 'u', ' ', 'p', 'a', 's', 's',
|
||||||
|
' ', 'b', 'u', 't', 't', 'e', 'r'};
|
||||||
|
const SolSignerSeed seeds1[] = {{seed1, SOL_ARRAY_SIZE(seed1)},
|
||||||
|
{&nonce1, 1}};
|
||||||
|
SolPubkey address;
|
||||||
|
sol_assert(SUCCESS == sol_create_program_address(seeds1, SOL_ARRAY_SIZE(seeds1),
|
||||||
|
params.program_id, &address));
|
||||||
|
sol_assert(SolPubkey_same(&address, accounts[DERIVED_KEY1_INDEX].key));
|
||||||
|
}
|
||||||
|
|
||||||
sol_log("Test derived signers");
|
sol_log("Test derived signers");
|
||||||
{
|
{
|
||||||
sol_assert(!accounts[DERIVED_KEY1_INDEX].is_signer);
|
sol_assert(!accounts[DERIVED_KEY1_INDEX].is_signer);
|
||||||
@@ -92,19 +108,15 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||||||
{accounts[DERIVED_KEY1_INDEX].key, true, true},
|
{accounts[DERIVED_KEY1_INDEX].key, true, true},
|
||||||
{accounts[DERIVED_KEY2_INDEX].key, true, false},
|
{accounts[DERIVED_KEY2_INDEX].key, true, false},
|
||||||
{accounts[DERIVED_KEY3_INDEX].key, false, false}};
|
{accounts[DERIVED_KEY3_INDEX].key, false, false}};
|
||||||
uint8_t data[] = {TEST_DERIVED_SIGNERS};
|
uint8_t data[] = {TEST_DERIVED_SIGNERS, nonce2, nonce3};
|
||||||
const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
|
const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
|
||||||
arguments, SOL_ARRAY_SIZE(arguments),
|
arguments, SOL_ARRAY_SIZE(arguments),
|
||||||
data, SOL_ARRAY_SIZE(data)};
|
data, SOL_ARRAY_SIZE(data)};
|
||||||
uint8_t seed1[] = {'Y', 'o', 'u', ' ', 'p', 'a', 's', 's',
|
uint8_t seed1[] = {'Y', 'o', 'u', ' ', 'p', 'a', 's', 's',
|
||||||
' ', 'b', 'u', 't', 't', 'e', 'r'};
|
' ', 'b', 'u', 't', 't', 'e', 'r'};
|
||||||
uint8_t seed2[] = {'L', 'i', 'l', '\''};
|
const SolSignerSeed seeds1[] = {{seed1, SOL_ARRAY_SIZE(seed1)},
|
||||||
uint8_t seed3[] = {'B', 'i', 't', 's'};
|
{&nonce1, 1}};
|
||||||
const SolSignerSeed seeds1[] = {{seed1, SOL_ARRAY_SIZE(seed1)}};
|
const SolSignerSeeds signers_seeds[] = {{seeds1, SOL_ARRAY_SIZE(seeds1)}};
|
||||||
const SolSignerSeed seeds2[] = {{seed2, SOL_ARRAY_SIZE(seed2)},
|
|
||||||
{seed3, SOL_ARRAY_SIZE(seed3)}};
|
|
||||||
const SolSignerSeeds signers_seeds[] = {{seeds1, SOL_ARRAY_SIZE(seeds1)},
|
|
||||||
{seeds2, SOL_ARRAY_SIZE(seeds2)}};
|
|
||||||
sol_assert(SUCCESS == sol_invoke_signed(&instruction, accounts,
|
sol_assert(SUCCESS == sol_invoke_signed(&instruction, accounts,
|
||||||
SOL_ARRAY_SIZE(accounts),
|
SOL_ARRAY_SIZE(accounts),
|
||||||
signers_seeds,
|
signers_seeds,
|
||||||
|
@@ -92,6 +92,9 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||||||
sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer);
|
sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer);
|
||||||
sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer);
|
sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer);
|
||||||
|
|
||||||
|
uint8_t nonce2 = params.data[1];
|
||||||
|
uint8_t nonce3 = params.data[2];
|
||||||
|
|
||||||
SolAccountMeta arguments[] = {
|
SolAccountMeta arguments[] = {
|
||||||
{accounts[DERIVED_KEY1_INDEX].key, true, false},
|
{accounts[DERIVED_KEY1_INDEX].key, true, false},
|
||||||
{accounts[DERIVED_KEY2_INDEX].key, true, true},
|
{accounts[DERIVED_KEY2_INDEX].key, true, true},
|
||||||
@@ -103,9 +106,11 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||||||
uint8_t seed1[] = {'L', 'i', 'l', '\''};
|
uint8_t seed1[] = {'L', 'i', 'l', '\''};
|
||||||
uint8_t seed2[] = {'B', 'i', 't', 's'};
|
uint8_t seed2[] = {'B', 'i', 't', 's'};
|
||||||
const SolSignerSeed seeds1[] = {{seed1, SOL_ARRAY_SIZE(seed1)},
|
const SolSignerSeed seeds1[] = {{seed1, SOL_ARRAY_SIZE(seed1)},
|
||||||
{seed2, SOL_ARRAY_SIZE(seed2)}};
|
{seed2, SOL_ARRAY_SIZE(seed2)},
|
||||||
|
{&nonce2, 1}};
|
||||||
const SolSignerSeed seeds2[] = {
|
const SolSignerSeed seeds2[] = {
|
||||||
{(uint8_t *)accounts[DERIVED_KEY2_INDEX].key, SIZE_PUBKEY}};
|
{(uint8_t *)accounts[DERIVED_KEY2_INDEX].key, SIZE_PUBKEY},
|
||||||
|
{&nonce3, 1}};
|
||||||
const SolSignerSeeds signers_seeds[] = {{seeds1, SOL_ARRAY_SIZE(seeds1)},
|
const SolSignerSeeds signers_seeds[] = {{seeds1, SOL_ARRAY_SIZE(seeds1)},
|
||||||
{seeds2, SOL_ARRAY_SIZE(seeds2)}};
|
{seeds2, SOL_ARRAY_SIZE(seeds2)}};
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-128bit"
|
name = "solana-bpf-rust-128bit"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,8 +12,8 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "1.3.0" }
|
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "1.3.1" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-128bit-dep"
|
name = "solana-bpf-rust-128bit-dep"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,7 +12,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-alloc"
|
name = "solana-bpf-rust-alloc"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,7 +12,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-dep-crate"
|
name = "solana-bpf-rust-dep-crate"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -13,7 +13,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = { version = "1", default-features = false }
|
byteorder = { version = "1", default-features = false }
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-dup-accounts"
|
name = "solana-bpf-rust-dup-accounts"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,7 +12,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-error-handling"
|
name = "solana-bpf-rust-error-handling"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -14,7 +14,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
num-derive = "0.2"
|
num-derive = "0.2"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-external-spend"
|
name = "solana-bpf-rust-external-spend"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,7 +12,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-invoke"
|
name = "solana-bpf-rust-invoke"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -13,7 +13,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-bpf-rust-invoked = { path = "../invoked"}
|
solana-bpf-rust-invoked = { path = "../invoked"}
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -10,7 +10,7 @@ use solana_sdk::{
|
|||||||
entrypoint,
|
entrypoint,
|
||||||
entrypoint::ProgramResult,
|
entrypoint::ProgramResult,
|
||||||
info,
|
info,
|
||||||
program::{invoke, invoke_signed},
|
program::{create_program_address, invoke, invoke_signed},
|
||||||
program_error::ProgramError,
|
program_error::ProgramError,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
system_instruction,
|
system_instruction,
|
||||||
@@ -34,12 +34,16 @@ const FROM_INDEX: usize = 10;
|
|||||||
|
|
||||||
entrypoint!(process_instruction);
|
entrypoint!(process_instruction);
|
||||||
fn process_instruction(
|
fn process_instruction(
|
||||||
_program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
accounts: &[AccountInfo],
|
accounts: &[AccountInfo],
|
||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
) -> ProgramResult {
|
) -> ProgramResult {
|
||||||
info!("invoke Rust program");
|
info!("invoke Rust program");
|
||||||
|
|
||||||
|
let nonce1 = instruction_data[1];
|
||||||
|
let nonce2 = instruction_data[2];
|
||||||
|
let nonce3 = instruction_data[3];
|
||||||
|
|
||||||
match instruction_data[0] {
|
match instruction_data[0] {
|
||||||
TEST_SUCCESS => {
|
TEST_SUCCESS => {
|
||||||
info!("Call system program");
|
info!("Call system program");
|
||||||
@@ -91,6 +95,12 @@ fn process_instruction(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!("Test create_program_address");
|
||||||
|
{
|
||||||
|
let address = create_program_address(&[b"You pass butter", &[nonce1]], program_id)?;
|
||||||
|
assert_eq!(&address, accounts[DERIVED_KEY1_INDEX].key);
|
||||||
|
}
|
||||||
|
|
||||||
info!("Test derived signers");
|
info!("Test derived signers");
|
||||||
{
|
{
|
||||||
assert!(!accounts[DERIVED_KEY1_INDEX].is_signer);
|
assert!(!accounts[DERIVED_KEY1_INDEX].is_signer);
|
||||||
@@ -105,12 +115,12 @@ fn process_instruction(
|
|||||||
(accounts[DERIVED_KEY2_INDEX].key, true, false),
|
(accounts[DERIVED_KEY2_INDEX].key, true, false),
|
||||||
(accounts[DERIVED_KEY3_INDEX].key, false, false),
|
(accounts[DERIVED_KEY3_INDEX].key, false, false),
|
||||||
],
|
],
|
||||||
vec![TEST_DERIVED_SIGNERS],
|
vec![TEST_DERIVED_SIGNERS, nonce2, nonce3],
|
||||||
);
|
);
|
||||||
invoke_signed(
|
invoke_signed(
|
||||||
&invoked_instruction,
|
&invoked_instruction,
|
||||||
accounts,
|
accounts,
|
||||||
&[&[b"You pass butter"], &[b"Lil'", b"Bits"]],
|
&[&[b"You pass butter", &[nonce1]]],
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-invoked"
|
name = "solana-bpf-rust-invoked"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,7 +12,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -120,6 +120,8 @@ fn process_instruction(
|
|||||||
assert!(!accounts[DERIVED_KEY2_INDEX].is_signer);
|
assert!(!accounts[DERIVED_KEY2_INDEX].is_signer);
|
||||||
assert!(!accounts[DERIVED_KEY3_INDEX].is_signer);
|
assert!(!accounts[DERIVED_KEY3_INDEX].is_signer);
|
||||||
|
|
||||||
|
let nonce2 = instruction_data[1];
|
||||||
|
let nonce3 = instruction_data[2];
|
||||||
let invoked_instruction = create_instruction(
|
let invoked_instruction = create_instruction(
|
||||||
*accounts[INVOKED_PROGRAM_INDEX].key,
|
*accounts[INVOKED_PROGRAM_INDEX].key,
|
||||||
&[
|
&[
|
||||||
@@ -133,8 +135,8 @@ fn process_instruction(
|
|||||||
&invoked_instruction,
|
&invoked_instruction,
|
||||||
accounts,
|
accounts,
|
||||||
&[
|
&[
|
||||||
&[b"Lil'", b"Bits"],
|
&[b"Lil'", b"Bits", &[nonce2]],
|
||||||
&[accounts[DERIVED_KEY2_INDEX].key.as_ref()],
|
&[accounts[DERIVED_KEY2_INDEX].key.as_ref(), &[nonce3]],
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-iter"
|
name = "solana-bpf-rust-iter"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,7 +12,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-many-args"
|
name = "solana-bpf-rust-many-args"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,8 +12,8 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "1.3.0" }
|
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "1.3.1" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-many-args-dep"
|
name = "solana-bpf-rust-many-args-dep"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,7 +12,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-noop"
|
name = "solana-bpf-rust-noop"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,7 +12,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-panic"
|
name = "solana-bpf-rust-panic"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,7 +12,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-param-passing"
|
name = "solana-bpf-rust-param-passing"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,8 +12,8 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
solana-bpf-rust-param-passing-dep = { path = "../param_passing_dep", version = "1.3.0" }
|
solana-bpf-rust-param-passing-dep = { path = "../param_passing_dep", version = "1.3.1" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-param-passing-dep"
|
name = "solana-bpf-rust-param-passing-dep"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF program written in Rust"
|
description = "Solana BPF program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,7 +12,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-sysval"
|
name = "solana-bpf-rust-sysval"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,7 +12,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.3.0", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.3.1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user