Compare commits
2 Commits
61a5e2344a
...
c8879a72c9
Author | SHA1 | Date |
---|---|---|
musitdev | c8879a72c9 | |
musitdev | c63da03e56 |
|
@ -50,8 +50,10 @@ yellowstone-grpc-proto = { path = "../../yellowstone-grpc/yellowstone-grpc-proto
|
||||||
#yellowstone-grpc-client = "1.8.0+solana.1.16.1"
|
#yellowstone-grpc-client = "1.8.0+solana.1.16.1"
|
||||||
#yellowstone-grpc-proto = "1.8.0+solana.1.16.1"
|
#yellowstone-grpc-proto = "1.8.0+solana.1.16.1"
|
||||||
|
|
||||||
solana-sdk = "1.16.*"
|
solana-sdk = "1.16.14"
|
||||||
solana-client = "1.16.*"
|
solana-client = "1.16.14"
|
||||||
solana-ledger = "1.16.*"
|
solana-ledger = "1.16.14"
|
||||||
solana-rpc-client-api = "1.16.*"
|
solana-rpc-client-api = "1.16.14"
|
||||||
solana-version = "1.16.*"
|
solana-version = "1.16.14"
|
||||||
|
solana-account-decoder = "1.16.14"
|
||||||
|
solana-program = "1.16.14"
|
||||||
|
|
|
@ -57,17 +57,13 @@ pub fn run_bootstrap_events(
|
||||||
|
|
||||||
pub enum BootstrapEvent {
|
pub enum BootstrapEvent {
|
||||||
InitBootstrap,
|
InitBootstrap,
|
||||||
BootstrapAccountsFetched(
|
BootstrapAccountsFetched(Vec<(Pubkey, Account)>, Vec<(Pubkey, Account)>, Account),
|
||||||
Vec<(Pubkey, Account)>,
|
|
||||||
Vec<(Pubkey, Account)>,
|
|
||||||
Vec<(Pubkey, Account)>,
|
|
||||||
),
|
|
||||||
StoreExtracted(
|
StoreExtracted(
|
||||||
StakeMap,
|
StakeMap,
|
||||||
VoteMap,
|
VoteMap,
|
||||||
Vec<(Pubkey, Account)>,
|
Vec<(Pubkey, Account)>,
|
||||||
Vec<(Pubkey, Account)>,
|
Vec<(Pubkey, Account)>,
|
||||||
Vec<(Pubkey, Account)>,
|
Account,
|
||||||
),
|
),
|
||||||
AccountsMerged(StakeMap, VoteMap),
|
AccountsMerged(StakeMap, VoteMap),
|
||||||
Exit,
|
Exit,
|
||||||
|
@ -135,6 +131,18 @@ fn process_bootstrap_event(
|
||||||
}
|
}
|
||||||
BootstrapEvent::StoreExtracted(mut stake_map, mut vote_map, stakes, votes, history) => {
|
BootstrapEvent::StoreExtracted(mut stake_map, mut vote_map, stakes, votes, history) => {
|
||||||
log::info!("BootstrapEvent::StoreExtracted RECV");
|
log::info!("BootstrapEvent::StoreExtracted RECV");
|
||||||
|
|
||||||
|
match crate::stakestore::read_historystake_from_account(history) {
|
||||||
|
Some(stake_history) => {
|
||||||
|
log::info!(
|
||||||
|
"Read stake history done with history len:{}",
|
||||||
|
stake_history.len()
|
||||||
|
);
|
||||||
|
stakestore.set_stake_history(stake_history);
|
||||||
|
}
|
||||||
|
None => log::error!("Bootstrap error, can't read stake history."),
|
||||||
|
}
|
||||||
|
|
||||||
//merge new PA with stake map and vote map in a specific task
|
//merge new PA with stake map and vote map in a specific task
|
||||||
let jh = tokio::task::spawn_blocking({
|
let jh = tokio::task::spawn_blocking({
|
||||||
let current_epoch = data.current_epoch;
|
let current_epoch = data.current_epoch;
|
||||||
|
@ -143,7 +151,6 @@ fn process_bootstrap_event(
|
||||||
crate::stakestore::merge_program_account_in_strake_map(
|
crate::stakestore::merge_program_account_in_strake_map(
|
||||||
&mut stake_map,
|
&mut stake_map,
|
||||||
stakes,
|
stakes,
|
||||||
history,
|
|
||||||
0, //with RPC no way to know the slot of the account update. Set to 0.
|
0, //with RPC no way to know the slot of the account update. Set to 0.
|
||||||
current_epoch,
|
current_epoch,
|
||||||
);
|
);
|
||||||
|
@ -152,6 +159,7 @@ fn process_bootstrap_event(
|
||||||
votes,
|
votes,
|
||||||
0, //with RPC no way to know the slot of the account update. Set to 0.
|
0, //with RPC no way to know the slot of the account update. Set to 0.
|
||||||
);
|
);
|
||||||
|
|
||||||
BootstrapEvent::AccountsMerged(stake_map, vote_map)
|
BootstrapEvent::AccountsMerged(stake_map, vote_map)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -177,14 +185,7 @@ fn process_bootstrap_event(
|
||||||
|
|
||||||
async fn bootstrap_accounts(
|
async fn bootstrap_accounts(
|
||||||
rpc_url: String,
|
rpc_url: String,
|
||||||
) -> Result<
|
) -> Result<(Vec<(Pubkey, Account)>, Vec<(Pubkey, Account)>, Account), ClientError> {
|
||||||
(
|
|
||||||
Vec<(Pubkey, Account)>,
|
|
||||||
Vec<(Pubkey, Account)>,
|
|
||||||
Vec<(Pubkey, Account)>,
|
|
||||||
),
|
|
||||||
ClientError,
|
|
||||||
> {
|
|
||||||
let furure = get_stake_account(rpc_url)
|
let furure = get_stake_account(rpc_url)
|
||||||
.and_then(|(stakes, rpc_url)| async move {
|
.and_then(|(stakes, rpc_url)| async move {
|
||||||
get_vote_account(rpc_url)
|
get_vote_account(rpc_url)
|
||||||
|
@ -231,7 +232,7 @@ async fn get_vote_account(
|
||||||
res_vote.map(|votes| (votes, rpc_url))
|
res_vote.map(|votes| (votes, rpc_url))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_stakehistory_account(rpc_url: String) -> Result<Vec<(Pubkey, Account)>, ClientError> {
|
async fn get_stakehistory_account(rpc_url: String) -> Result<Account, ClientError> {
|
||||||
log::info!("TaskToExec RpcGetStakeHistory start");
|
log::info!("TaskToExec RpcGetStakeHistory start");
|
||||||
let rpc_client = RpcClient::new_with_timeout_and_commitment(
|
let rpc_client = RpcClient::new_with_timeout_and_commitment(
|
||||||
rpc_url,
|
rpc_url,
|
||||||
|
@ -239,11 +240,8 @@ async fn get_stakehistory_account(rpc_url: String) -> Result<Vec<(Pubkey, Accoun
|
||||||
CommitmentConfig::finalized(),
|
CommitmentConfig::finalized(),
|
||||||
);
|
);
|
||||||
let res_stake = rpc_client
|
let res_stake = rpc_client
|
||||||
.get_program_accounts(&solana_sdk::sysvar::stake_history::id())
|
.get_account(&solana_sdk::sysvar::stake_history::id())
|
||||||
.await;
|
.await;
|
||||||
log::info!(
|
log::info!("TaskToExec RpcGetStakeHistory END",);
|
||||||
"TaskToExec RpcGetStakeHistory END with len:{:?}",
|
|
||||||
res_stake.as_ref().map(|history| history.len())
|
|
||||||
);
|
|
||||||
res_stake
|
res_stake
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use crate::leader_schedule::LeaderScheduleEvent;
|
use crate::leader_schedule::LeaderScheduleEvent;
|
||||||
use crate::Slot;
|
use crate::Slot;
|
||||||
|
use solana_account_decoder::parse_sysvar::SysvarAccountType;
|
||||||
use solana_client::client_error::ClientError;
|
use solana_client::client_error::ClientError;
|
||||||
use solana_client::nonblocking::rpc_client::RpcClient;
|
use solana_client::nonblocking::rpc_client::RpcClient;
|
||||||
|
use solana_program::epoch_schedule::EpochSchedule;
|
||||||
use solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel};
|
use solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel};
|
||||||
use solana_sdk::epoch_info::EpochInfo;
|
use solana_sdk::epoch_info::EpochInfo;
|
||||||
use yellowstone_grpc_proto::geyser::CommitmentLevel as GeyserCommitmentLevel;
|
use yellowstone_grpc_proto::geyser::CommitmentLevel as GeyserCommitmentLevel;
|
||||||
|
@ -30,6 +32,27 @@ pub struct CurrentEpochSlotState {
|
||||||
impl CurrentEpochSlotState {
|
impl CurrentEpochSlotState {
|
||||||
pub async fn bootstrap(rpc_url: String) -> Result<CurrentEpochSlotState, ClientError> {
|
pub async fn bootstrap(rpc_url: String) -> Result<CurrentEpochSlotState, ClientError> {
|
||||||
let rpc_client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::finalized());
|
let rpc_client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::finalized());
|
||||||
|
|
||||||
|
//get reduce_stake_warmup_cooldown feature info.
|
||||||
|
//NOT AND ACCOUNT. Get from config.
|
||||||
|
// let reduce_stake_warmup_cooldown_epoch = rpc_client
|
||||||
|
// .get_account(&feature_set::reduce_stake_warmup_cooldown::id())
|
||||||
|
// .await?;
|
||||||
|
|
||||||
|
// let reduce_stake_warmup_cooldown_epoch = bincode::deserialize(&reduce_stake_warmup_cooldown_epoch.data[..])
|
||||||
|
// .ok()
|
||||||
|
// .map(SysvarAccountType::EpochSchedule);
|
||||||
|
// log::info!("reduce_stake_warmup_cooldown_epoch {reduce_stake_warmup_cooldown_epoch:?}");
|
||||||
|
|
||||||
|
//get epoch sysvar account to init epoch. More compatible with a snapshot bootstrap.
|
||||||
|
let res_epoch = rpc_client
|
||||||
|
.get_account(&solana_sdk::sysvar::epoch_schedule::id())
|
||||||
|
.await?;
|
||||||
|
let sysvar_epoch_schedule = bincode::deserialize(&res_epoch.data[..])
|
||||||
|
.ok()
|
||||||
|
.map(SysvarAccountType::EpochSchedule);
|
||||||
|
log::info!("sysvar_epoch_schedule {sysvar_epoch_schedule:?}");
|
||||||
|
|
||||||
// Fetch current epoch
|
// Fetch current epoch
|
||||||
let current_epoch = rpc_client.get_epoch_info().await?;
|
let current_epoch = rpc_client.get_epoch_info().await?;
|
||||||
let next_epoch_start_slot =
|
let next_epoch_start_slot =
|
||||||
|
|
|
@ -10,7 +10,7 @@ use solana_sdk::clock::NUM_CONSECUTIVE_LEADER_SLOTS;
|
||||||
use solana_sdk::commitment_config::CommitmentConfig;
|
use solana_sdk::commitment_config::CommitmentConfig;
|
||||||
use solana_sdk::epoch_info::EpochInfo;
|
use solana_sdk::epoch_info::EpochInfo;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::stake::state::Delegation;
|
use solana_sdk::stake_history::StakeHistory;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
@ -166,7 +166,7 @@ pub fn run_leader_schedule_events(
|
||||||
|
|
||||||
pub enum LeaderScheduleEvent {
|
pub enum LeaderScheduleEvent {
|
||||||
InitLeaderschedule(EpochInfo),
|
InitLeaderschedule(EpochInfo),
|
||||||
CalculateScedule(StakeMap, VoteMap, EpochInfo),
|
CalculateScedule(StakeMap, VoteMap, EpochInfo, Option<StakeHistory>),
|
||||||
MergeStoreAndSaveSchedule(
|
MergeStoreAndSaveSchedule(
|
||||||
StakeMap,
|
StakeMap,
|
||||||
VoteMap,
|
VoteMap,
|
||||||
|
@ -193,10 +193,17 @@ fn process_leadershedule_event(
|
||||||
match event {
|
match event {
|
||||||
LeaderScheduleEvent::InitLeaderschedule(schedule_epoch) => {
|
LeaderScheduleEvent::InitLeaderschedule(schedule_epoch) => {
|
||||||
log::info!("LeaderScheduleEvent::InitLeaderschedule RECV");
|
log::info!("LeaderScheduleEvent::InitLeaderschedule RECV");
|
||||||
|
//For test TODO put in extract and restore process to avoid to clone.
|
||||||
|
let stake_history = stakestore.get_cloned_stake_history();
|
||||||
match (extract_stakestore(stakestore), extract_votestore(votestore)) {
|
match (extract_stakestore(stakestore), extract_votestore(votestore)) {
|
||||||
(Ok(stake_map), Ok(vote_map)) => LeaderScheduleResult::Event(
|
(Ok(stake_map), Ok(vote_map)) => {
|
||||||
LeaderScheduleEvent::CalculateScedule(stake_map, vote_map, schedule_epoch),
|
LeaderScheduleResult::Event(LeaderScheduleEvent::CalculateScedule(
|
||||||
),
|
stake_map,
|
||||||
|
vote_map,
|
||||||
|
schedule_epoch,
|
||||||
|
stake_history,
|
||||||
|
))
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::warn!("process_leadershedule_event error during extract store");
|
log::warn!("process_leadershedule_event error during extract store");
|
||||||
let jh = tokio::spawn(async move {
|
let jh = tokio::spawn(async move {
|
||||||
|
@ -207,7 +214,12 @@ fn process_leadershedule_event(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LeaderScheduleEvent::CalculateScedule(stake_map, vote_map, schedule_epoch) => {
|
LeaderScheduleEvent::CalculateScedule(
|
||||||
|
stake_map,
|
||||||
|
vote_map,
|
||||||
|
schedule_epoch,
|
||||||
|
stake_history,
|
||||||
|
) => {
|
||||||
log::info!("LeaderScheduleEvent::CalculateScedule RECV");
|
log::info!("LeaderScheduleEvent::CalculateScedule RECV");
|
||||||
let jh = tokio::task::spawn_blocking({
|
let jh = tokio::task::spawn_blocking({
|
||||||
move || {
|
move || {
|
||||||
|
@ -216,6 +228,7 @@ fn process_leadershedule_event(
|
||||||
&stake_map,
|
&stake_map,
|
||||||
&vote_map,
|
&vote_map,
|
||||||
&schedule_epoch,
|
&schedule_epoch,
|
||||||
|
stake_history.as_ref(),
|
||||||
);
|
);
|
||||||
if let Ok((_, vote_stakes)) = &schedule_and_stakes {
|
if let Ok((_, vote_stakes)) = &schedule_and_stakes {
|
||||||
if let Err(err) = save_schedule_vote_stakes(
|
if let Err(err) = save_schedule_vote_stakes(
|
||||||
|
@ -269,12 +282,14 @@ fn calculate_leader_schedule_from_stake_map(
|
||||||
stake_map: &crate::stakestore::StakeMap,
|
stake_map: &crate::stakestore::StakeMap,
|
||||||
vote_map: &crate::votestore::VoteMap,
|
vote_map: &crate::votestore::VoteMap,
|
||||||
current_epoch_info: &EpochInfo,
|
current_epoch_info: &EpochInfo,
|
||||||
|
stake_history: Option<&StakeHistory>,
|
||||||
) -> anyhow::Result<(HashMap<String, Vec<usize>>, Vec<(Pubkey, u64)>)> {
|
) -> anyhow::Result<(HashMap<String, Vec<usize>>, Vec<(Pubkey, u64)>)> {
|
||||||
let mut stakes = HashMap::<Pubkey, u64>::new();
|
let mut stakes = HashMap::<Pubkey, u64>::new();
|
||||||
log::trace!(
|
log::info!(
|
||||||
"calculate_leader_schedule_from_stake_map vote map len:{} stake map len:{}",
|
"calculate_leader_schedule_from_stake_map vote map len:{} stake map len:{} history len:{:?}",
|
||||||
vote_map.len(),
|
vote_map.len(),
|
||||||
stake_map.len()
|
stake_map.len(),
|
||||||
|
stake_history.as_ref().map(|h| h.len())
|
||||||
);
|
);
|
||||||
|
|
||||||
let ten_epoch_slot_long = 10 * current_epoch_info.slots_in_epoch;
|
let ten_epoch_slot_long = 10 * current_epoch_info.slots_in_epoch;
|
||||||
|
@ -282,35 +297,41 @@ fn calculate_leader_schedule_from_stake_map(
|
||||||
//log::trace!("calculate_leader_schedule_from_stake_map stake_map:{stake_map:?} current_epoch_info:{current_epoch_info:?}");
|
//log::trace!("calculate_leader_schedule_from_stake_map stake_map:{stake_map:?} current_epoch_info:{current_epoch_info:?}");
|
||||||
for storestake in stake_map.values() {
|
for storestake in stake_map.values() {
|
||||||
//log::info!("Program_accounts stake:{stake:#?}");
|
//log::info!("Program_accounts stake:{stake:#?}");
|
||||||
if is_stake_to_add(storestake.pubkey, &storestake.stake, ¤t_epoch_info) {
|
// if is_stake_to_add(storestake.pubkey, &storestake.stake, ¤t_epoch_info) {
|
||||||
// Add the stake in this stake account to the total for the delegated-to vote account
|
// Add the stake in this stake account to the total for the delegated-to vote account
|
||||||
//get nodeid for vote account
|
//get nodeid for vote account
|
||||||
let Some(vote_account) = vote_map.get(&storestake.stake.voter_pubkey) else {
|
let Some(vote_account) = vote_map.get(&storestake.stake.voter_pubkey) else {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Vote account not found in vote map for stake vote account:{}",
|
"Vote account not found in vote map for stake vote account:{}",
|
||||||
&storestake.stake.voter_pubkey
|
&storestake.stake.voter_pubkey
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
//remove vote account that hasn't vote since 10 epoch.
|
//TODO validate the number of epoch.
|
||||||
//on testnet the vote account CY7gjryUPV6Pwbsn4aArkMBL7HSaRHB8sPZUvhw558Tm node_id:6YpwLjgXcMWAj29govWQr87kaAGKS7CnoqWsEDJE4h8P
|
//remove vote account that hasn't vote since 10 epoch.
|
||||||
//hasn't vote since a long time but still return on RPC call get_voteaccounts.
|
//on testnet the vote account CY7gjryUPV6Pwbsn4aArkMBL7HSaRHB8sPZUvhw558Tm node_id:6YpwLjgXcMWAj29govWQr87kaAGKS7CnoqWsEDJE4h8P
|
||||||
//the validator don't use it for leader schedule.
|
//hasn't vote since a long time but still return on RPC call get_voteaccounts.
|
||||||
if vote_account.vote_data.root_slot.unwrap_or(0)
|
//the validator don't use it for leader schedule.
|
||||||
< current_epoch_info
|
if vote_account.vote_data.root_slot.unwrap_or(0)
|
||||||
.absolute_slot
|
< current_epoch_info
|
||||||
.saturating_sub(ten_epoch_slot_long)
|
.absolute_slot
|
||||||
{
|
.saturating_sub(ten_epoch_slot_long)
|
||||||
log::warn!("Vote account:{} nodeid:{} that hasn't vote since 10 epochs. Remove leader_schedule."
|
{
|
||||||
|
log::warn!("Vote account:{} nodeid:{} that hasn't vote since 10 epochs. Stake for account:{:?}. Remove leader_schedule."
|
||||||
, storestake.stake.voter_pubkey
|
, storestake.stake.voter_pubkey
|
||||||
,vote_account.vote_data.node_pubkey
|
,vote_account.vote_data.node_pubkey
|
||||||
|
//TODO us the right reduce_stake_warmup_cooldown_epoch value from validator feature.
|
||||||
|
, storestake.stake.stake(current_epoch_info.epoch, stake_history, Some(0)),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
*(stakes
|
*(stakes
|
||||||
.entry(vote_account.vote_data.node_pubkey)
|
.entry(vote_account.vote_data.node_pubkey)
|
||||||
.or_insert(0)) += storestake.stake.stake;
|
.or_insert(0)) += storestake
|
||||||
}
|
.stake
|
||||||
|
//TODO us the right reduce_stake_warmup_cooldown_epoch value from validator feature.
|
||||||
|
.stake(current_epoch_info.epoch, stake_history, Some(0));
|
||||||
}
|
}
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut schedule_stakes: Vec<(Pubkey, u64)> = vec![];
|
let mut schedule_stakes: Vec<(Pubkey, u64)> = vec![];
|
||||||
|
@ -324,31 +345,31 @@ fn calculate_leader_schedule_from_stake_map(
|
||||||
Ok((leader_schedule, schedule_stakes))
|
Ok((leader_schedule, schedule_stakes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_stake_to_add(
|
// fn is_stake_to_add(
|
||||||
stake_pubkey: Pubkey,
|
// stake_pubkey: Pubkey,
|
||||||
stake: &Delegation,
|
// stake: &Delegation,
|
||||||
current_epoch_info: &EpochInfo,
|
// current_epoch_info: &EpochInfo,
|
||||||
) -> bool {
|
// ) -> bool {
|
||||||
//On test validator all stakes are attributes to an account with stake.delegation.activation_epoch == MAX_EPOCH_VALUE.
|
// //On test validator all stakes are attributes to an account with stake.delegation.activation_epoch == MAX_EPOCH_VALUE.
|
||||||
//It's considered as activated stake.
|
// //It's considered as activated stake.
|
||||||
if stake.activation_epoch == MAX_EPOCH_VALUE {
|
// if stake.activation_epoch == MAX_EPOCH_VALUE {
|
||||||
log::info!(
|
// log::info!(
|
||||||
"Found account with stake.delegation.activation_epoch == MAX_EPOCH_VALUE use it: {}",
|
// "Found account with stake.delegation.activation_epoch == MAX_EPOCH_VALUE use it: {}",
|
||||||
stake_pubkey.to_string()
|
// stake_pubkey.to_string()
|
||||||
);
|
// );
|
||||||
} else {
|
// } else {
|
||||||
// Ignore stake accounts activated in this epoch (or later, to include activation_epoch of
|
// // Ignore stake accounts activated in this epoch (or later, to include activation_epoch of
|
||||||
// u64::MAX which indicates no activation ever happened)
|
// // u64::MAX which indicates no activation ever happened)
|
||||||
if stake.activation_epoch >= current_epoch_info.epoch {
|
// if stake.activation_epoch >= current_epoch_info.epoch {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
// Ignore stake accounts deactivated before this epoch
|
// // Ignore stake accounts deactivated before this epoch
|
||||||
if stake.deactivation_epoch < current_epoch_info.epoch {
|
// if stake.deactivation_epoch < current_epoch_info.epoch {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
true
|
// true
|
||||||
}
|
// }
|
||||||
|
|
||||||
//Copied from leader_schedule_utils.rs
|
//Copied from leader_schedule_utils.rs
|
||||||
// Mostly cribbed from leader_schedule_utils
|
// Mostly cribbed from leader_schedule_utils
|
||||||
|
@ -493,6 +514,7 @@ use borsh::BorshDeserialize;
|
||||||
use solana_sdk::stake::state::StakeState;
|
use solana_sdk::stake::state::StakeState;
|
||||||
pub fn build_current_stakes(
|
pub fn build_current_stakes(
|
||||||
stake_map: &crate::stakestore::StakeMap,
|
stake_map: &crate::stakestore::StakeMap,
|
||||||
|
stake_history: Option<&StakeHistory>,
|
||||||
current_epoch_info: &EpochInfo,
|
current_epoch_info: &EpochInfo,
|
||||||
rpc_url: String,
|
rpc_url: String,
|
||||||
commitment: CommitmentConfig,
|
commitment: CommitmentConfig,
|
||||||
|
@ -518,7 +540,11 @@ pub fn build_current_stakes(
|
||||||
match BorshDeserialize::deserialize(&mut account.data.as_slice()).unwrap() {
|
match BorshDeserialize::deserialize(&mut account.data.as_slice()).unwrap() {
|
||||||
StakeState::Stake(_, stake) => {
|
StakeState::Stake(_, stake) => {
|
||||||
//vote account version
|
//vote account version
|
||||||
if is_stake_to_add(pubkey, &stake.delegation, current_epoch_info) {
|
let effective_stake =
|
||||||
|
stake
|
||||||
|
.delegation
|
||||||
|
.stake(current_epoch_info.epoch, stake_history, Some(0));
|
||||||
|
if effective_stake > 0 {
|
||||||
// Add the stake in this stake account to the total for the delegated-to vote account
|
// Add the stake in this stake account to the total for the delegated-to vote account
|
||||||
log::trace!("RPC Stake {pubkey} account:{account:?} stake:{stake:?}");
|
log::trace!("RPC Stake {pubkey} account:{account:?} stake:{stake:?}");
|
||||||
(stakes_aggregated
|
(stakes_aggregated
|
||||||
|
@ -530,7 +556,7 @@ pub fn build_current_stakes(
|
||||||
.or_insert(vec![]);
|
.or_insert(vec![]);
|
||||||
st_list.push((
|
st_list.push((
|
||||||
pubkey.to_string(),
|
pubkey.to_string(),
|
||||||
stake.delegation.stake,
|
effective_stake,
|
||||||
stake.delegation.activation_epoch,
|
stake.delegation.activation_epoch,
|
||||||
stake.delegation.deactivation_epoch,
|
stake.delegation.deactivation_epoch,
|
||||||
));
|
));
|
||||||
|
@ -542,8 +568,14 @@ pub fn build_current_stakes(
|
||||||
let mut local_stakes = BTreeMap::<String, Vec<(String, u64, u64, u64)>>::new();
|
let mut local_stakes = BTreeMap::<String, Vec<(String, u64, u64, u64)>>::new();
|
||||||
stake_map
|
stake_map
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(pubkey, stake)| is_stake_to_add(**pubkey, &stake.stake, current_epoch_info))
|
.filter_map(|(pubkey, stake)| {
|
||||||
.for_each(|(pubkey, stake)| {
|
let effective_stake =
|
||||||
|
stake
|
||||||
|
.stake
|
||||||
|
.stake(current_epoch_info.epoch, stake_history, Some(0));
|
||||||
|
(effective_stake > 0).then(|| (pubkey, stake, effective_stake))
|
||||||
|
})
|
||||||
|
.for_each(|(pubkey, stake, effective_stake)| {
|
||||||
// log::trace!(
|
// log::trace!(
|
||||||
// "LCOAL Stake {pubkey} account:{:?} stake:{stake:?}",
|
// "LCOAL Stake {pubkey} account:{:?} stake:{stake:?}",
|
||||||
// stake.stake.voter_pubkey
|
// stake.stake.voter_pubkey
|
||||||
|
@ -557,7 +589,7 @@ pub fn build_current_stakes(
|
||||||
.or_insert(vec![]);
|
.or_insert(vec![]);
|
||||||
st_list.push((
|
st_list.push((
|
||||||
pubkey.to_string(),
|
pubkey.to_string(),
|
||||||
stake.stake.stake,
|
effective_stake,
|
||||||
stake.stake.activation_epoch,
|
stake.stake.activation_epoch,
|
||||||
stake.stake.deactivation_epoch,
|
stake.stake.deactivation_epoch,
|
||||||
));
|
));
|
||||||
|
|
|
@ -53,13 +53,9 @@ use crate::votestore::VoteStore;
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use futures_util::stream::FuturesUnordered;
|
use futures_util::stream::FuturesUnordered;
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use solana_sdk::account::Account;
|
|
||||||
use solana_sdk::account::AccountSharedData;
|
|
||||||
use solana_sdk::commitment_config::CommitmentConfig;
|
use solana_sdk::commitment_config::CommitmentConfig;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::stake::state::Delegation;
|
use solana_sdk::stake::state::Delegation;
|
||||||
use solana_sdk::stake_history::StakeHistory;
|
|
||||||
use solana_sdk::sysvar::rent::Rent;
|
|
||||||
use solana_sdk::vote::state::VoteState;
|
use solana_sdk::vote::state::VoteState;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -282,10 +278,12 @@ async fn run_loop<F: Interceptor>(mut client: GeyserGrpcClient<F>) -> anyhow::Re
|
||||||
tokio::task::spawn_blocking({
|
tokio::task::spawn_blocking({
|
||||||
log::info!("RPC start save_stakes");
|
log::info!("RPC start save_stakes");
|
||||||
let current_stakes = stakestore.get_cloned_stake_map();
|
let current_stakes = stakestore.get_cloned_stake_map();
|
||||||
|
let history = stakestore.get_cloned_stake_history();
|
||||||
let move_epoch = current_epoch_state.current_epoch.clone();
|
let move_epoch = current_epoch_state.current_epoch.clone();
|
||||||
move || {
|
move || {
|
||||||
let current_stake = crate::leader_schedule::build_current_stakes(
|
let current_stake = crate::leader_schedule::build_current_stakes(
|
||||||
¤t_stakes,
|
¤t_stakes,
|
||||||
|
history.as_ref(),
|
||||||
&move_epoch,
|
&move_epoch,
|
||||||
RPC_URL.to_string(),
|
RPC_URL.to_string(),
|
||||||
CommitmentConfig::confirmed(),
|
CommitmentConfig::confirmed(),
|
||||||
|
@ -554,16 +552,6 @@ impl AccountPretty {
|
||||||
}
|
}
|
||||||
Ok(VoteState::deserialize(&self.data)?)
|
Ok(VoteState::deserialize(&self.data)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_stake_history(&self) -> Option<StakeHistory> {
|
|
||||||
// if self.data.is_empty() {
|
|
||||||
// log::warn!("Stake history account with empty data. Can't read StakeHistory.");
|
|
||||||
// bail!("Error: read StakeHistory account with empty data");
|
|
||||||
// }
|
|
||||||
solana_sdk::account::from_account::<StakeHistory, _>(&program_account(&self.data))
|
|
||||||
|
|
||||||
// Ok(StakeHistory::deserialize(&self.data)?)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for AccountPretty {
|
impl std::fmt::Display for AccountPretty {
|
||||||
|
@ -608,12 +596,12 @@ fn read_account(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn program_account(program_data: &[u8]) -> AccountSharedData {
|
// fn program_account(program_data: &[u8]) -> AccountSharedData {
|
||||||
AccountSharedData::from(Account {
|
// AccountSharedData::from(Account {
|
||||||
lamports: Rent::default().minimum_balance(program_data.len()).min(1),
|
// lamports: Rent::default().minimum_balance(program_data.len()).min(1),
|
||||||
data: program_data.to_vec(),
|
// data: program_data.to_vec(),
|
||||||
owner: solana_sdk::bpf_loader::id(),
|
// owner: solana_sdk::bpf_loader::id(),
|
||||||
executable: true,
|
// executable: true,
|
||||||
rent_epoch: 0,
|
// rent_epoch: 0,
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
|
@ -12,6 +12,7 @@ use solana_sdk::stake::state::Delegation;
|
||||||
use solana_sdk::stake::state::StakeState;
|
use solana_sdk::stake::state::StakeState;
|
||||||
use solana_sdk::stake_history::StakeHistory;
|
use solana_sdk::stake_history::StakeHistory;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::str::FromStr;
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
use yellowstone_grpc_proto::solana::storage::confirmed_block::CompiledInstruction;
|
use yellowstone_grpc_proto::solana::storage::confirmed_block::CompiledInstruction;
|
||||||
|
|
||||||
|
@ -127,12 +128,11 @@ impl StoredStake {
|
||||||
self.stake.activation_epoch == crate::leader_schedule::MAX_EPOCH_VALUE
|
self.stake.activation_epoch == crate::leader_schedule::MAX_EPOCH_VALUE
|
||||||
|| self.stake.deactivation_epoch >= current_epoch
|
|| self.stake.deactivation_epoch >= current_epoch
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_history(&mut self) {}
|
|
||||||
}
|
}
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct StakeStore {
|
pub struct StakeStore {
|
||||||
stakes: StakeMap,
|
stakes: StakeMap,
|
||||||
|
stake_history: Option<StakeHistory>,
|
||||||
updates: Vec<ExtractedAction>,
|
updates: Vec<ExtractedAction>,
|
||||||
extracted: bool,
|
extracted: bool,
|
||||||
}
|
}
|
||||||
|
@ -141,11 +141,16 @@ impl StakeStore {
|
||||||
pub fn new(capacity: usize) -> Self {
|
pub fn new(capacity: usize) -> Self {
|
||||||
StakeStore {
|
StakeStore {
|
||||||
stakes: HashMap::with_capacity(capacity),
|
stakes: HashMap::with_capacity(capacity),
|
||||||
|
stake_history: None,
|
||||||
updates: vec![],
|
updates: vec![],
|
||||||
extracted: false,
|
extracted: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_stake_history(&mut self, stake_history: StakeHistory) {
|
||||||
|
self.stake_history = Some(stake_history);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn nb_stake_account(&self) -> usize {
|
pub fn nb_stake_account(&self) -> usize {
|
||||||
self.stakes.len()
|
self.stakes.len()
|
||||||
}
|
}
|
||||||
|
@ -153,6 +158,9 @@ impl StakeStore {
|
||||||
pub fn get_cloned_stake_map(&self) -> StakeMap {
|
pub fn get_cloned_stake_map(&self) -> StakeMap {
|
||||||
self.stakes.clone()
|
self.stakes.clone()
|
||||||
}
|
}
|
||||||
|
pub fn get_cloned_stake_history(&self) -> Option<StakeHistory> {
|
||||||
|
self.stake_history.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn notify_stake_change(
|
pub fn notify_stake_change(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -238,6 +246,7 @@ impl StakeStore {
|
||||||
}
|
}
|
||||||
let stakestore = StakeStore {
|
let stakestore = StakeStore {
|
||||||
stakes: HashMap::new(),
|
stakes: HashMap::new(),
|
||||||
|
stake_history: self.stake_history,
|
||||||
updates: self.updates,
|
updates: self.updates,
|
||||||
extracted: true,
|
extracted: true,
|
||||||
};
|
};
|
||||||
|
@ -251,6 +260,7 @@ impl StakeStore {
|
||||||
}
|
}
|
||||||
let mut stakestore = StakeStore {
|
let mut stakestore = StakeStore {
|
||||||
stakes,
|
stakes,
|
||||||
|
stake_history: self.stake_history,
|
||||||
updates: vec![],
|
updates: vec![],
|
||||||
extracted: false,
|
extracted: false,
|
||||||
};
|
};
|
||||||
|
@ -262,6 +272,21 @@ impl StakeStore {
|
||||||
action.update_epoch(current_epoch);
|
action.update_epoch(current_epoch);
|
||||||
stakestore.process_stake_action(action);
|
stakestore.process_stake_action(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//verify one stake account to test. TODO remove
|
||||||
|
let stake_account = stakestore
|
||||||
|
.stakes
|
||||||
|
.get(&Pubkey::from_str("2wAVZS68P6frWqpwMu7q67A3j54RFmBjq4oH94sYi7ce").unwrap());
|
||||||
|
let stake = stake_account.map(|stake| {
|
||||||
|
stake
|
||||||
|
.stake
|
||||||
|
.stake(current_epoch, stakestore.stake_history.as_ref(), Some(0))
|
||||||
|
});
|
||||||
|
log::info!(
|
||||||
|
"merge_stakes 2wAVZS68P6frWqpwMu7q67A3j54RFmBjq4oH94sYi7ce:{:?}",
|
||||||
|
stake
|
||||||
|
);
|
||||||
|
|
||||||
Ok(stakestore)
|
Ok(stakestore)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,12 +306,9 @@ impl StakeStore {
|
||||||
pub fn merge_program_account_in_strake_map(
|
pub fn merge_program_account_in_strake_map(
|
||||||
stake_map: &mut StakeMap,
|
stake_map: &mut StakeMap,
|
||||||
stakes_list: Vec<(Pubkey, Account)>,
|
stakes_list: Vec<(Pubkey, Account)>,
|
||||||
stakehistory_list: Vec<(Pubkey, Account)>,
|
|
||||||
last_update_slot: Slot,
|
last_update_slot: Slot,
|
||||||
current_epoch: u64,
|
current_epoch: u64,
|
||||||
) {
|
) {
|
||||||
let mut stake_history_map: HashMap<Pubkey, Account> = stakehistory_list.into_iter().collect();
|
|
||||||
|
|
||||||
stakes_list
|
stakes_list
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(
|
.filter_map(
|
||||||
|
@ -306,24 +328,9 @@ pub fn merge_program_account_in_strake_map(
|
||||||
last_update_slot,
|
last_update_slot,
|
||||||
write_version: 0,
|
write_version: 0,
|
||||||
};
|
};
|
||||||
if let Some(history) = stake_history_map.remove(&stake.pubkey) {
|
|
||||||
log::info!(
|
|
||||||
"merge_program_account_in_strake_map found stake history for account:{}",
|
|
||||||
stake.pubkey
|
|
||||||
);
|
|
||||||
match read_historystake_from_account(history) {
|
|
||||||
Some(history) => (),
|
|
||||||
None => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stake_map_notify_stake(stake_map, stake, current_epoch);
|
stake_map_notify_stake(stake_map, stake, current_epoch);
|
||||||
});
|
});
|
||||||
|
|
||||||
log::info!(
|
|
||||||
"merge_program_account_in_strake_map history account not processed:{}",
|
|
||||||
stake_history_map.len()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_stake_from_account_data(mut data: &[u8]) -> anyhow::Result<Option<Delegation>> {
|
pub fn read_stake_from_account_data(mut data: &[u8]) -> anyhow::Result<Option<Delegation>> {
|
||||||
|
|
Loading…
Reference in New Issue