2023-09-11 10:05:01 -07:00
|
|
|
//RUST_BACKTRACE=1 RUST_LOG=stake_aggregate=trace cargo run --release --bin stake_aggregate
|
2023-09-13 11:45:29 -07:00
|
|
|
//RUST_BACKTRACE=1 RUST_LOG=stake_aggregate=info cargo run --release --bin stake_aggregate &> stake_logs.txt &
|
2023-09-05 07:18:34 -07:00
|
|
|
/*
|
|
|
|
RPC calls;
|
2023-10-09 07:20:23 -07:00
|
|
|
curl http://localhost:3001 -X POST -H "Content-Type: application/json" -d '
|
2023-09-05 07:18:34 -07:00
|
|
|
{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id" : 1,
|
|
|
|
"method": "save_stakes",
|
|
|
|
"params": []
|
|
|
|
}
|
|
|
|
'
|
2023-09-11 09:27:21 -07:00
|
|
|
|
2023-10-09 07:20:23 -07:00
|
|
|
curl http://localhost:3001 -X POST -H "Content-Type: application/json" -d '
|
2023-09-27 09:52:35 -07:00
|
|
|
{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id" : 1,
|
|
|
|
"method": "stake_accounts",
|
|
|
|
"params": []
|
|
|
|
}
|
2023-09-29 03:03:17 -07:00
|
|
|
' -o extract_stake_533_3.json
|
2023-09-27 09:52:35 -07:00
|
|
|
|
|
|
|
|
2023-10-09 07:20:23 -07:00
|
|
|
curl http://localhost:3001 -X POST -H "Content-Type: application/json" -d '
|
2023-09-27 09:52:35 -07:00
|
|
|
{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id" : 1,
|
|
|
|
"method": "getLeaderSchedule",
|
|
|
|
"params": []
|
|
|
|
}
|
|
|
|
'
|
|
|
|
|
2023-09-05 07:18:34 -07:00
|
|
|
*/
|
2023-09-06 04:50:36 -07:00
|
|
|
|
|
|
|
//TODO: add stake verify that it' not already desactivated.
|
|
|
|
|
2023-09-13 11:45:29 -07:00
|
|
|
use crate::bootstrap::BootstrapData;
|
|
|
|
use crate::bootstrap::BootstrapEvent;
|
|
|
|
use crate::leader_schedule::LeaderScheduleData;
|
2023-08-11 00:13:31 -07:00
|
|
|
use crate::stakestore::StakeStore;
|
2023-09-08 11:07:43 -07:00
|
|
|
use crate::votestore::VoteStore;
|
2023-08-29 03:16:57 -07:00
|
|
|
use anyhow::bail;
|
2023-08-11 00:13:31 -07:00
|
|
|
use futures_util::stream::FuturesUnordered;
|
|
|
|
use futures_util::StreamExt;
|
|
|
|
use solana_sdk::commitment_config::CommitmentConfig;
|
|
|
|
use solana_sdk::pubkey::Pubkey;
|
|
|
|
use solana_sdk::stake::state::Delegation;
|
2023-08-29 03:16:57 -07:00
|
|
|
use solana_sdk::vote::state::VoteState;
|
2023-08-11 00:13:31 -07:00
|
|
|
use std::collections::HashMap;
|
2023-09-27 09:52:35 -07:00
|
|
|
use std::env;
|
2023-08-30 07:06:11 -07:00
|
|
|
use tokio::time::Duration;
|
2023-08-11 00:13:31 -07:00
|
|
|
use yellowstone_grpc_client::GeyserGrpcClient;
|
|
|
|
use yellowstone_grpc_proto::geyser::CommitmentLevel;
|
|
|
|
use yellowstone_grpc_proto::geyser::SubscribeUpdateAccount;
|
|
|
|
use yellowstone_grpc_proto::prelude::SubscribeRequestFilterAccounts;
|
2023-09-02 08:52:28 -07:00
|
|
|
use yellowstone_grpc_proto::prelude::SubscribeRequestFilterBlocks;
|
|
|
|
use yellowstone_grpc_proto::prelude::SubscribeRequestFilterBlocksMeta;
|
2023-08-11 00:13:31 -07:00
|
|
|
use yellowstone_grpc_proto::{
|
2023-09-13 11:45:29 -07:00
|
|
|
prelude::{subscribe_update::UpdateOneof, SubscribeRequestFilterSlots},
|
2023-08-11 00:13:31 -07:00
|
|
|
tonic::service::Interceptor,
|
|
|
|
};
|
|
|
|
|
2023-09-13 11:45:29 -07:00
|
|
|
mod bootstrap;
|
|
|
|
mod epoch;
|
2023-08-11 00:13:31 -07:00
|
|
|
mod leader_schedule;
|
2023-09-05 03:53:28 -07:00
|
|
|
mod rpc;
|
2023-08-11 00:13:31 -07:00
|
|
|
mod stakestore;
|
2023-09-08 11:07:43 -07:00
|
|
|
mod votestore;
|
2023-08-11 00:13:31 -07:00
|
|
|
|
|
|
|
type Slot = u64;
|
|
|
|
|
2023-09-25 11:15:26 -07:00
|
|
|
const CURRENT_SCHEDULE_VOTE_STAKES_FILE: &str = "current_vote_stakes.json";
|
|
|
|
const NEXT_SCHEDULE_VOTE_STAKES_FILE: &str = "next_vote_stakes.json";
|
2023-08-12 01:58:41 -07:00
|
|
|
|
2023-09-01 01:07:42 -07:00
|
|
|
const GRPC_URL: &str = "http://localhost:10000";
|
|
|
|
const RPC_URL: &str = "http://localhost:8899";
|
2023-08-30 07:06:11 -07:00
|
|
|
|
2023-08-12 01:58:41 -07:00
|
|
|
//const RPC_URL: &str = "https://api.mainnet-beta.solana.com";
|
2023-08-11 00:13:31 -07:00
|
|
|
//const RPC_URL: &str = "https://api.testnet.solana.com";
|
|
|
|
//const RPC_URL: &str = "https://api.devnet.solana.com";
|
|
|
|
|
|
|
|
const STAKESTORE_INITIAL_CAPACITY: usize = 600000;
|
2023-09-08 11:07:43 -07:00
|
|
|
const VOTESTORE_INITIAL_CAPACITY: usize = 600000;
|
2023-08-11 00:13:31 -07:00
|
|
|
|
2023-09-25 11:15:26 -07:00
|
|
|
/*
|
|
|
|
TODO:
|
|
|
|
* load current and next epoch vote stake list
|
|
|
|
* calculate schedule for the 2 epoch
|
|
|
|
* save new schedule in next epoch.
|
|
|
|
* schedule cycle:
|
|
|
|
- current: loaded start
|
|
|
|
- next: loaded start
|
|
|
|
- new epoch:
|
|
|
|
- calculate schedule
|
|
|
|
- next -> current
|
|
|
|
- new -> next
|
|
|
|
*/
|
|
|
|
|
2023-09-05 07:18:34 -07:00
|
|
|
pub fn log_end_epoch(
|
|
|
|
current_slot: Slot,
|
|
|
|
end_epoch_slot: Slot,
|
|
|
|
epoch_slot_index: Slot,
|
|
|
|
msg: String,
|
|
|
|
) {
|
2023-09-02 08:52:28 -07:00
|
|
|
//log 50 end slot.
|
2023-09-13 11:45:29 -07:00
|
|
|
if current_slot != 0 && current_slot + 10 > end_epoch_slot {
|
2023-09-05 07:18:34 -07:00
|
|
|
log::info!("{current_slot}/{end_epoch_slot} {}", msg);
|
|
|
|
}
|
2023-09-13 11:45:29 -07:00
|
|
|
if epoch_slot_index < 10 {
|
2023-09-02 08:52:28 -07:00
|
|
|
log::info!("{current_slot}/{end_epoch_slot} {}", msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-11 00:13:31 -07:00
|
|
|
/// Connect to yellow stone plugin using yellow stone gRpc Client
|
|
|
|
#[tokio::main]
|
|
|
|
async fn main() -> anyhow::Result<()> {
|
|
|
|
tracing_subscriber::fmt::init();
|
|
|
|
|
|
|
|
let mut client = GeyserGrpcClient::connect(GRPC_URL, None::<&'static str>, None)?;
|
|
|
|
|
|
|
|
let version = client.get_version().await?;
|
|
|
|
println!("Version: {:?}", version);
|
|
|
|
|
|
|
|
let ctrl_c_signal = tokio::signal::ctrl_c();
|
|
|
|
|
|
|
|
tokio::select! {
|
|
|
|
res = run_loop(client) => {
|
|
|
|
// This should never happen
|
|
|
|
log::error!("Services quit unexpectedly {res:?}");
|
|
|
|
}
|
|
|
|
_ = ctrl_c_signal => {
|
|
|
|
log::info!("Received ctrl+c signal");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn run_loop<F: Interceptor>(mut client: GeyserGrpcClient<F>) -> anyhow::Result<()> {
|
|
|
|
//local vars
|
2023-09-13 11:45:29 -07:00
|
|
|
//slot and epoch
|
|
|
|
let mut current_epoch_state =
|
|
|
|
epoch::CurrentEpochSlotState::bootstrap(RPC_URL.to_string()).await?;
|
|
|
|
|
|
|
|
//Stake account management struct
|
2023-08-11 00:13:31 -07:00
|
|
|
let mut stakestore = StakeStore::new(STAKESTORE_INITIAL_CAPACITY);
|
|
|
|
|
2023-09-13 11:45:29 -07:00
|
|
|
//Vote account management struct
|
|
|
|
let mut votestore = VoteStore::new(VOTESTORE_INITIAL_CAPACITY);
|
|
|
|
|
|
|
|
//leader schedule
|
2023-09-27 09:52:35 -07:00
|
|
|
let args: Vec<String> = env::args().collect();
|
|
|
|
log::info!("agrs:{:?}", args);
|
|
|
|
let (schedule_current_file, schedule_next_file) = if args.len() == 3 {
|
|
|
|
let current_path: String = args[1]
|
|
|
|
.parse()
|
|
|
|
.unwrap_or(CURRENT_SCHEDULE_VOTE_STAKES_FILE.to_string());
|
|
|
|
let next_path: String = args[2]
|
|
|
|
.parse()
|
|
|
|
.unwrap_or(NEXT_SCHEDULE_VOTE_STAKES_FILE.to_string());
|
|
|
|
(current_path, next_path)
|
|
|
|
} else {
|
|
|
|
(
|
|
|
|
CURRENT_SCHEDULE_VOTE_STAKES_FILE.to_string(),
|
|
|
|
NEXT_SCHEDULE_VOTE_STAKES_FILE.to_string(),
|
|
|
|
)
|
|
|
|
};
|
|
|
|
let mut leader_schedule_data = match crate::leader_schedule::bootstrap_leader_schedule(
|
|
|
|
&schedule_current_file,
|
|
|
|
&schedule_next_file,
|
2023-10-06 07:25:21 -07:00
|
|
|
¤t_epoch_state,
|
2023-09-27 09:52:35 -07:00
|
|
|
) {
|
|
|
|
Ok(data) => data,
|
|
|
|
Err(err) => {
|
|
|
|
log::warn!("Can't load vote stakes using these files: current:{schedule_current_file} next:{schedule_next_file}. Error:{err}");
|
|
|
|
crate::leader_schedule::CalculatedSchedule::default()
|
|
|
|
}
|
|
|
|
};
|
2023-09-13 11:45:29 -07:00
|
|
|
|
|
|
|
//future execution collection.
|
|
|
|
let mut spawned_bootstrap_task = FuturesUnordered::new();
|
|
|
|
let mut spawned_leader_schedule_task = FuturesUnordered::new();
|
2023-08-11 00:13:31 -07:00
|
|
|
|
2023-08-29 03:16:57 -07:00
|
|
|
//subscribe Geyser grpc
|
2023-09-02 08:52:28 -07:00
|
|
|
//slot subscription
|
2023-08-11 00:13:31 -07:00
|
|
|
let mut slots = HashMap::new();
|
|
|
|
slots.insert("client".to_string(), SubscribeRequestFilterSlots {});
|
|
|
|
|
2023-09-02 08:52:28 -07:00
|
|
|
//account subscription
|
2023-08-11 00:13:31 -07:00
|
|
|
let mut accounts: HashMap<String, SubscribeRequestFilterAccounts> = HashMap::new();
|
|
|
|
accounts.insert(
|
|
|
|
"client".to_owned(),
|
|
|
|
SubscribeRequestFilterAccounts {
|
|
|
|
account: vec![],
|
2023-08-29 03:16:57 -07:00
|
|
|
owner: vec![
|
|
|
|
solana_sdk::stake::program::ID.to_string(),
|
2023-09-11 09:27:21 -07:00
|
|
|
solana_sdk::vote::program::ID.to_string(),
|
2023-11-06 02:36:53 -08:00
|
|
|
solana_sdk::sysvar::stake_history::ID.to_string(),
|
2023-09-13 11:45:29 -07:00
|
|
|
// solana_sdk::system_program::ID.to_string(),
|
2023-08-29 03:16:57 -07:00
|
|
|
],
|
2023-08-11 00:13:31 -07:00
|
|
|
filters: vec![],
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2023-09-02 08:52:28 -07:00
|
|
|
//block subscription
|
|
|
|
let mut blocks = HashMap::new();
|
|
|
|
blocks.insert(
|
|
|
|
"client".to_string(),
|
|
|
|
SubscribeRequestFilterBlocks {
|
|
|
|
account_include: Default::default(),
|
|
|
|
include_transactions: Some(true),
|
|
|
|
include_accounts: Some(false),
|
2023-09-02 09:11:01 -07:00
|
|
|
include_entries: None,
|
2023-09-02 08:52:28 -07:00
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
//block Meta subscription filter
|
|
|
|
let mut blocks_meta = HashMap::new();
|
|
|
|
blocks_meta.insert("client".to_string(), SubscribeRequestFilterBlocksMeta {});
|
|
|
|
|
2023-08-11 00:13:31 -07:00
|
|
|
let mut confirmed_stream = client
|
|
|
|
.subscribe_once(
|
2023-08-30 09:21:10 -07:00
|
|
|
slots.clone(),
|
|
|
|
accounts.clone(), //accounts
|
2023-08-11 00:13:31 -07:00
|
|
|
Default::default(), //tx
|
|
|
|
Default::default(), //entry
|
2023-09-15 08:47:34 -07:00
|
|
|
blocks.clone(), //full block
|
|
|
|
//Default::default(), //full block
|
2023-09-02 08:52:28 -07:00
|
|
|
//blocks_meta, //block meta
|
2023-08-11 00:13:31 -07:00
|
|
|
Default::default(), //block meta
|
|
|
|
Some(CommitmentLevel::Confirmed),
|
|
|
|
vec![],
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
2023-09-13 11:45:29 -07:00
|
|
|
//log current data at interval TODO to be removed. only for test.
|
2023-09-15 08:47:34 -07:00
|
|
|
let mut log_interval = tokio::time::interval(Duration::from_millis(600000));
|
2023-08-31 03:13:27 -07:00
|
|
|
|
2023-09-13 11:45:29 -07:00
|
|
|
//start local rpc access to get RPC request.
|
2023-09-05 03:53:28 -07:00
|
|
|
let (request_tx, mut request_rx) = tokio::sync::mpsc::channel(100);
|
|
|
|
let rpc_handle = crate::rpc::run_server(request_tx).await?;
|
|
|
|
//make it run forever
|
|
|
|
tokio::spawn(rpc_handle.stopped());
|
|
|
|
|
2023-09-13 11:45:29 -07:00
|
|
|
//Init bootstrap process
|
2023-09-27 09:52:35 -07:00
|
|
|
let mut bootstrap_data = BootstrapData {
|
|
|
|
done: false,
|
2023-09-13 11:45:29 -07:00
|
|
|
sleep_time: 1,
|
|
|
|
rpc_url: RPC_URL.to_string(),
|
2023-10-18 03:58:54 -07:00
|
|
|
current_epoch: current_epoch_state.get_current_epoch().epoch,
|
2023-09-13 11:45:29 -07:00
|
|
|
};
|
|
|
|
let jh = tokio::spawn(async move { BootstrapEvent::InitBootstrap });
|
|
|
|
spawned_bootstrap_task.push(jh);
|
2023-09-08 11:07:43 -07:00
|
|
|
|
2023-09-18 07:13:09 -07:00
|
|
|
//For DEBUG TODO remove:
|
|
|
|
//start stake verification loop
|
|
|
|
let mut stake_verification_sender =
|
|
|
|
crate::stakestore::start_stake_verification_loop(RPC_URL.to_string()).await;
|
|
|
|
|
2023-10-04 06:54:50 -07:00
|
|
|
//TODO remove. Store parent hash to see if we don't miss a block.
|
|
|
|
let mut parent_block_slot = None;
|
2023-08-11 00:13:31 -07:00
|
|
|
loop {
|
|
|
|
tokio::select! {
|
2023-09-11 09:27:21 -07:00
|
|
|
Some(req) = request_rx.recv() => {
|
|
|
|
match req {
|
|
|
|
crate::rpc::Requests::SaveStakes => {
|
|
|
|
tokio::task::spawn_blocking({
|
|
|
|
log::info!("RPC start save_stakes");
|
|
|
|
let current_stakes = stakestore.get_cloned_stake_map();
|
2023-10-06 07:25:21 -07:00
|
|
|
let move_epoch = current_epoch_state.get_current_epoch();
|
|
|
|
let stake_history = stakestore.get_stake_history();
|
2023-09-11 09:27:21 -07:00
|
|
|
move || {
|
2023-09-13 11:45:29 -07:00
|
|
|
let current_stake = crate::leader_schedule::build_current_stakes(
|
|
|
|
¤t_stakes,
|
2023-10-06 07:25:21 -07:00
|
|
|
stake_history.as_ref(),
|
|
|
|
move_epoch.epoch,
|
2023-09-13 11:45:29 -07:00
|
|
|
RPC_URL.to_string(),
|
|
|
|
CommitmentConfig::confirmed(),
|
|
|
|
);
|
2023-09-11 09:27:21 -07:00
|
|
|
log::info!("RPC save_stakes generation done");
|
|
|
|
if let Err(err) = crate::leader_schedule::save_schedule_on_file("stakes", ¤t_stake) {
|
|
|
|
log::error!("Error during current stakes saving:{err}");
|
|
|
|
}
|
2023-10-16 03:23:53 -07:00
|
|
|
log::warn!("RPC save_stakes END");
|
2023-09-05 03:53:28 -07:00
|
|
|
|
2023-09-11 09:27:21 -07:00
|
|
|
}
|
|
|
|
});
|
2023-09-05 03:53:28 -07:00
|
|
|
}
|
2023-09-27 09:52:35 -07:00
|
|
|
crate::rpc::Requests::GetStakestore(tx) => {
|
2023-09-11 09:27:21 -07:00
|
|
|
let current_stakes = stakestore.get_cloned_stake_map();
|
2023-09-29 02:19:29 -07:00
|
|
|
let extract_slot = if stakestore.extracted {
|
|
|
|
log::error!("Stakestore extracted:{}", stakestore.extracted);
|
|
|
|
0
|
|
|
|
}
|
|
|
|
else if stakestore.updates.len() > 0 {
|
|
|
|
log::error!("Extract with pending stake:{}", stakestore.updates.len());
|
|
|
|
0
|
|
|
|
} else {
|
|
|
|
current_epoch_state.current_slot.confirmed_slot
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Err(err) = tx.send((current_stakes, extract_slot)){
|
2023-11-03 02:04:03 -07:00
|
|
|
log::error!("Channel error during sending back request status error:{err:?}");
|
2023-09-11 09:27:21 -07:00
|
|
|
}
|
2023-09-29 02:19:29 -07:00
|
|
|
|
2023-09-27 09:52:35 -07:00
|
|
|
log::info!("RPC GetStakestore account send");
|
2023-09-19 09:30:02 -07:00
|
|
|
},
|
2023-09-27 09:52:35 -07:00
|
|
|
crate::rpc::Requests::GetVotestore(tx) => {
|
|
|
|
let current_votes = votestore.get_cloned_vote_map();
|
|
|
|
if let Err(err) = tx.send((current_votes, current_epoch_state.current_slot.confirmed_slot)){
|
|
|
|
println!("Channel error during sending back request status error:{err:?}");
|
|
|
|
}
|
|
|
|
log::info!("RPC GetVotestore account send");
|
|
|
|
},
|
|
|
|
_ => crate::rpc::server_rpc_request(req, ¤t_epoch_state, &leader_schedule_data),
|
2023-09-11 09:27:21 -07:00
|
|
|
}
|
|
|
|
|
2023-09-05 03:53:28 -07:00
|
|
|
},
|
2023-09-13 11:45:29 -07:00
|
|
|
//log interval TODO remove
|
2023-08-31 03:13:27 -07:00
|
|
|
_ = log_interval.tick() => {
|
2023-09-13 11:45:29 -07:00
|
|
|
log::info!("Run_loop update new epoch:{current_epoch_state:?}");
|
|
|
|
log::info!("Change epoch equality {} >= {}", current_epoch_state.current_slot.confirmed_slot, current_epoch_state.current_epoch_end_slot());
|
2023-08-31 03:13:27 -07:00
|
|
|
log::info!("number of stake accounts:{}", stakestore.nb_stake_account());
|
|
|
|
}
|
2023-09-13 11:45:29 -07:00
|
|
|
|
|
|
|
//exec bootstrap task
|
|
|
|
Some(Ok(event)) = spawned_bootstrap_task.next() => {
|
2023-09-27 09:52:35 -07:00
|
|
|
crate::bootstrap::run_bootstrap_events(event, &mut spawned_bootstrap_task, &mut stakestore, &mut votestore, &mut bootstrap_data);
|
2023-08-11 00:13:31 -07:00
|
|
|
}
|
|
|
|
//Manage RPC call result execution
|
2023-09-13 11:45:29 -07:00
|
|
|
Some(Ok(event)) = spawned_leader_schedule_task.next() => {
|
2023-10-06 07:25:21 -07:00
|
|
|
let new_leader_schedule = crate::leader_schedule::run_leader_schedule_events(
|
2023-09-13 11:45:29 -07:00
|
|
|
event,
|
|
|
|
&mut spawned_leader_schedule_task,
|
|
|
|
&mut stakestore,
|
|
|
|
&mut votestore,
|
2023-10-06 07:25:21 -07:00
|
|
|
);
|
|
|
|
leader_schedule_data.current = leader_schedule_data.next.take();
|
|
|
|
leader_schedule_data.next = new_leader_schedule;
|
2023-08-11 00:13:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//get confirmed slot or account
|
|
|
|
ret = confirmed_stream.next() => {
|
|
|
|
match ret {
|
|
|
|
Some(message) => {
|
|
|
|
//process the message
|
|
|
|
match message {
|
|
|
|
Ok(msg) => {
|
2023-08-18 07:14:04 -07:00
|
|
|
//log::info!("new message: {msg:?}");
|
2023-08-11 00:13:31 -07:00
|
|
|
match msg.update_oneof {
|
|
|
|
Some(UpdateOneof::Account(account)) => {
|
|
|
|
//store new account stake.
|
2023-09-13 11:45:29 -07:00
|
|
|
if let Some(account) = read_account(account, current_epoch_state.current_slot.confirmed_slot) {
|
2023-08-29 03:16:57 -07:00
|
|
|
//log::trace!("Geyser receive new account");
|
|
|
|
match account.owner {
|
|
|
|
solana_sdk::stake::program::ID => {
|
2023-11-03 02:04:03 -07:00
|
|
|
//log::info!("Geyser notif stake account:{}", account);
|
2023-09-18 12:56:23 -07:00
|
|
|
if let Err(err) = stakestore.notify_stake_change(
|
2023-09-13 11:45:29 -07:00
|
|
|
account,
|
|
|
|
current_epoch_state.current_epoch_end_slot(),
|
|
|
|
) {
|
2023-08-29 03:16:57 -07:00
|
|
|
log::warn!("Can't add new stake from account data err:{}", err);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
solana_sdk::vote::program::ID => {
|
2023-09-29 05:56:44 -07:00
|
|
|
// Generatea lot of logs. log::info!("Geyser notif VOTE account:{}", account);
|
2023-09-29 05:49:49 -07:00
|
|
|
let account_pubkey = account.pubkey;
|
2023-08-29 03:16:57 -07:00
|
|
|
//process vote accout notification
|
2023-09-13 11:45:29 -07:00
|
|
|
if let Err(err) = votestore.add_vote(account, current_epoch_state.current_epoch_end_slot()) {
|
2023-09-29 05:49:49 -07:00
|
|
|
log::warn!("Can't add new stake from account data err:{} account:{}", err, account_pubkey);
|
2023-09-08 11:07:43 -07:00
|
|
|
continue;
|
2023-08-29 03:16:57 -07:00
|
|
|
}
|
|
|
|
}
|
2023-09-27 09:52:35 -07:00
|
|
|
solana_sdk::sysvar::stake_history::ID => {
|
|
|
|
log::info!("Geyser notif History account:{}", account);
|
|
|
|
}
|
2023-09-13 11:45:29 -07:00
|
|
|
solana_sdk::system_program::ID => {
|
|
|
|
log::info!("system_program account:{}",account.pubkey);
|
|
|
|
}
|
2023-08-29 03:16:57 -07:00
|
|
|
_ => log::warn!("receive an account notification from a unknown owner:{account:?}"),
|
2023-08-11 00:13:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(UpdateOneof::Slot(slot)) => {
|
2023-09-13 11:45:29 -07:00
|
|
|
log::trace!("Receive slot slot: {slot:?}");
|
|
|
|
//TODO remove log
|
2023-08-31 05:24:16 -07:00
|
|
|
//log::info!("Processing slot: {:?} current slot:{:?}", slot, current_slot);
|
2023-09-13 11:45:29 -07:00
|
|
|
// log_end_epoch(
|
|
|
|
// current_epoch_state.current_slot.confirmed_slot,
|
|
|
|
// current_epoch_state.next_epoch_start_slot,
|
|
|
|
// current_epoch_state.current_epoch.slot_index,
|
|
|
|
// format!(
|
|
|
|
// "Receive slot: {:?} at commitment:{:?}",
|
|
|
|
// slot.slot,
|
|
|
|
// slot.status()
|
|
|
|
// ),
|
|
|
|
// );
|
|
|
|
|
|
|
|
let schedule_event = current_epoch_state.process_new_slot(&slot);
|
2023-09-27 09:52:35 -07:00
|
|
|
if bootstrap_data.done {
|
|
|
|
if let Some(init_event) = schedule_event {
|
|
|
|
crate::leader_schedule::run_leader_schedule_events(
|
|
|
|
init_event,
|
|
|
|
&mut spawned_leader_schedule_task,
|
|
|
|
&mut stakestore,
|
|
|
|
&mut votestore,
|
|
|
|
);
|
|
|
|
}
|
2023-09-05 07:18:34 -07:00
|
|
|
}
|
2023-09-02 08:52:28 -07:00
|
|
|
|
2023-08-11 00:13:31 -07:00
|
|
|
}
|
2023-09-02 08:52:28 -07:00
|
|
|
Some(UpdateOneof::BlockMeta(block_meta)) => {
|
|
|
|
log::info!("Receive Block Meta at slot: {}", block_meta.slot);
|
|
|
|
}
|
|
|
|
Some(UpdateOneof::Block(block)) => {
|
2023-10-04 06:54:50 -07:00
|
|
|
log::trace!("Receive Block at slot: {} hash:{} parent_slot:{}",
|
|
|
|
block.slot,
|
|
|
|
block.blockhash,
|
|
|
|
block.parent_slot,
|
|
|
|
);
|
|
|
|
|
|
|
|
//TODO remove; Detect missing block
|
|
|
|
if let Some(parent_block_slot) = parent_block_slot {
|
|
|
|
if parent_block_slot != block.parent_slot {
|
|
|
|
log::error!("Bad parent slot stored:{} block:{}, miss a block"
|
|
|
|
,parent_block_slot,block.parent_slot
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
parent_block_slot = Some(block.slot);
|
|
|
|
|
2023-09-15 08:47:34 -07:00
|
|
|
//parse to detect stake merge tx.
|
|
|
|
//first in the main thread then in a specific thread.
|
|
|
|
let stake_public_key: Vec<u8> = solana_sdk::stake::program::id().to_bytes().to_vec();
|
2023-09-16 12:55:14 -07:00
|
|
|
for notif_tx in block.transactions {
|
|
|
|
if !notif_tx.is_vote {
|
|
|
|
if let Some(message) = notif_tx.transaction.and_then(|tx| tx.message) {
|
|
|
|
for instruction in message.instructions {
|
|
|
|
//filter stake tx
|
|
|
|
if message.account_keys[instruction.program_id_index as usize] == stake_public_key {
|
2023-09-16 13:46:41 -07:00
|
|
|
let source_bytes: [u8; 64] = notif_tx.signature[..solana_sdk::signature::SIGNATURE_BYTES]
|
|
|
|
.try_into()
|
|
|
|
.unwrap();
|
2023-09-27 09:52:35 -07:00
|
|
|
log::info!("New stake Tx sign:{} at block slot:{:?} current_slot:{} accounts:{:?}"
|
2023-09-17 02:17:29 -07:00
|
|
|
, solana_sdk::signature::Signature::from(source_bytes).to_string()
|
|
|
|
, block.slot
|
|
|
|
, current_epoch_state.current_slot.confirmed_slot
|
2023-09-27 09:52:35 -07:00
|
|
|
, instruction.accounts
|
2023-09-17 02:17:29 -07:00
|
|
|
);
|
2023-09-16 12:55:14 -07:00
|
|
|
let program_index = instruction.program_id_index;
|
|
|
|
crate::stakestore::process_stake_tx_message(
|
2023-09-18 07:13:09 -07:00
|
|
|
&mut stake_verification_sender,
|
2023-09-16 12:55:14 -07:00
|
|
|
&mut stakestore
|
|
|
|
, &message.account_keys
|
|
|
|
, instruction
|
|
|
|
, program_index
|
2023-09-19 03:53:39 -07:00
|
|
|
, block.slot
|
|
|
|
, current_epoch_state.current_epoch_end_slot(),
|
2023-09-18 07:13:09 -07:00
|
|
|
).await;
|
2023-09-16 12:55:14 -07:00
|
|
|
}
|
2023-09-15 08:47:34 -07:00
|
|
|
}
|
2023-09-16 12:55:14 -07:00
|
|
|
}
|
2023-09-15 08:47:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-02 08:52:28 -07:00
|
|
|
}
|
2023-09-01 01:26:06 -07:00
|
|
|
Some(UpdateOneof::Ping(_)) => log::trace!("UpdateOneof::Ping"),
|
2023-08-11 00:13:31 -07:00
|
|
|
bad_msg => {
|
|
|
|
log::info!("Geyser stream unexpected message received:{:?}",bad_msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(error) => {
|
|
|
|
log::error!("Geyser stream receive an error has message: {error:?}, try to reconnect and resynchronize.");
|
2023-08-30 07:06:11 -07:00
|
|
|
//todo reconnect and resynchronize.
|
|
|
|
//break;
|
2023-08-11 00:13:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
2023-09-27 09:52:35 -07:00
|
|
|
log::error!("The geyser stream close try to reconnect and resynchronize.");
|
|
|
|
break;
|
2023-09-15 08:47:34 -07:00
|
|
|
//TODO call same initial code.
|
2023-09-27 09:52:35 -07:00
|
|
|
// let new_confirmed_stream = client
|
|
|
|
// .subscribe_once(
|
|
|
|
// slots.clone(),
|
|
|
|
// accounts.clone(), //accounts
|
|
|
|
// Default::default(), //tx
|
|
|
|
// Default::default(), //entry
|
|
|
|
// blocks.clone(), //full block
|
|
|
|
// Default::default(), //block meta
|
|
|
|
// Some(CommitmentLevel::Confirmed),
|
|
|
|
// vec![],
|
|
|
|
// )
|
|
|
|
// .await?;
|
|
|
|
|
|
|
|
// confirmed_stream = new_confirmed_stream;
|
|
|
|
// log::info!("reconnection done");
|
2023-08-30 09:21:10 -07:00
|
|
|
|
|
|
|
//TODO resynchronize.
|
2023-08-11 00:13:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-27 09:52:35 -07:00
|
|
|
Ok(())
|
2023-08-11 00:13:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub struct AccountPretty {
|
|
|
|
is_startup: bool,
|
|
|
|
slot: u64,
|
|
|
|
pubkey: Pubkey,
|
|
|
|
lamports: u64,
|
|
|
|
owner: Pubkey,
|
|
|
|
executable: bool,
|
|
|
|
rent_epoch: u64,
|
|
|
|
data: Vec<u8>,
|
|
|
|
write_version: u64,
|
|
|
|
txn_signature: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AccountPretty {
|
|
|
|
fn read_stake(&self) -> anyhow::Result<Option<Delegation>> {
|
2023-09-08 11:07:43 -07:00
|
|
|
if self.data.is_empty() {
|
|
|
|
log::warn!("Stake account with empty data. Can't read vote.");
|
|
|
|
bail!("Error: read Stake account with empty data");
|
|
|
|
}
|
2023-08-11 00:13:31 -07:00
|
|
|
crate::stakestore::read_stake_from_account_data(self.data.as_slice())
|
|
|
|
}
|
2023-09-27 09:52:35 -07:00
|
|
|
|
2023-08-29 03:16:57 -07:00
|
|
|
fn read_vote(&self) -> anyhow::Result<VoteState> {
|
|
|
|
if self.data.is_empty() {
|
|
|
|
log::warn!("Vote account with empty data. Can't read vote.");
|
2023-09-08 11:07:43 -07:00
|
|
|
bail!("Error: read Vote account with empty data");
|
2023-08-29 03:16:57 -07:00
|
|
|
}
|
|
|
|
Ok(VoteState::deserialize(&self.data)?)
|
|
|
|
}
|
2023-08-11 00:13:31 -07:00
|
|
|
}
|
|
|
|
|
2023-09-17 02:45:09 -07:00
|
|
|
impl std::fmt::Display for AccountPretty {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"{} at slot:{} lpt:{}",
|
|
|
|
self.pubkey.to_string(),
|
|
|
|
self.slot,
|
|
|
|
self.lamports
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-11 00:13:31 -07:00
|
|
|
fn read_account(
|
|
|
|
geyser_account: SubscribeUpdateAccount,
|
|
|
|
current_slot: u64,
|
|
|
|
) -> Option<AccountPretty> {
|
|
|
|
let Some(inner_account) = geyser_account.account else {
|
2023-09-25 11:15:26 -07:00
|
|
|
log::warn!("Receive a SubscribeUpdateAccount without account.");
|
|
|
|
return None;
|
|
|
|
};
|
2023-08-11 00:13:31 -07:00
|
|
|
|
|
|
|
if geyser_account.slot != current_slot {
|
2023-09-03 05:40:43 -07:00
|
|
|
log::trace!(
|
2023-08-11 00:13:31 -07:00
|
|
|
"Get geyser account on a different slot:{} of the current:{current_slot}",
|
|
|
|
geyser_account.slot
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(AccountPretty {
|
|
|
|
is_startup: geyser_account.is_startup,
|
|
|
|
slot: geyser_account.slot,
|
|
|
|
pubkey: Pubkey::try_from(inner_account.pubkey).expect("valid pubkey"),
|
|
|
|
lamports: inner_account.lamports,
|
|
|
|
owner: Pubkey::try_from(inner_account.owner).expect("valid pubkey"),
|
|
|
|
executable: inner_account.executable,
|
|
|
|
rent_epoch: inner_account.rent_epoch,
|
|
|
|
data: inner_account.data,
|
|
|
|
write_version: inner_account.write_version,
|
|
|
|
txn_signature: bs58::encode(inner_account.txn_signature.unwrap_or_default()).into_string(),
|
|
|
|
})
|
|
|
|
}
|
2023-09-27 09:52:35 -07:00
|
|
|
|
2023-09-28 09:17:19 -07:00
|
|
|
// fn program_account(program_data: &[u8]) -> AccountSharedData {
|
|
|
|
// AccountSharedData::from(Account {
|
|
|
|
// lamports: Rent::default().minimum_balance(program_data.len()).min(1),
|
|
|
|
// data: program_data.to_vec(),
|
|
|
|
// owner: solana_sdk::bpf_loader::id(),
|
|
|
|
// executable: true,
|
|
|
|
// rent_epoch: 0,
|
|
|
|
// })
|
|
|
|
// }
|