add stake verification with RPC
This commit is contained in:
parent
7d884850f3
commit
71706729b8
|
@ -201,6 +201,11 @@ async fn run_loop<F: Interceptor>(mut client: GeyserGrpcClient<F>) -> anyhow::Re
|
||||||
let jh = tokio::spawn(async move { BootstrapEvent::InitBootstrap });
|
let jh = tokio::spawn(async move { BootstrapEvent::InitBootstrap });
|
||||||
spawned_bootstrap_task.push(jh);
|
spawned_bootstrap_task.push(jh);
|
||||||
|
|
||||||
|
//For DEBUG TODO remove:
|
||||||
|
//start stake verification loop
|
||||||
|
let mut stake_verification_sender =
|
||||||
|
crate::stakestore::start_stake_verification_loop(RPC_URL.to_string()).await;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
Some(req) = request_rx.recv() => {
|
Some(req) = request_rx.recv() => {
|
||||||
|
@ -366,11 +371,12 @@ async fn run_loop<F: Interceptor>(mut client: GeyserGrpcClient<F>) -> anyhow::Re
|
||||||
);
|
);
|
||||||
let program_index = instruction.program_id_index;
|
let program_index = instruction.program_id_index;
|
||||||
crate::stakestore::process_stake_tx_message(
|
crate::stakestore::process_stake_tx_message(
|
||||||
|
&mut stake_verification_sender,
|
||||||
&mut stakestore
|
&mut stakestore
|
||||||
, &message.account_keys
|
, &message.account_keys
|
||||||
, instruction
|
, instruction
|
||||||
, program_index
|
, program_index
|
||||||
);
|
).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use solana_sdk::stake::instruction::StakeInstruction;
|
||||||
use solana_sdk::stake::state::Delegation;
|
use solana_sdk::stake::state::Delegation;
|
||||||
use solana_sdk::stake::state::StakeState;
|
use solana_sdk::stake::state::StakeState;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use tokio::sync::mpsc::Sender;
|
||||||
use yellowstone_grpc_proto::solana::storage::confirmed_block::CompiledInstruction;
|
use yellowstone_grpc_proto::solana::storage::confirmed_block::CompiledInstruction;
|
||||||
|
|
||||||
pub type StakeMap = HashMap<Pubkey, StoredStake>;
|
pub type StakeMap = HashMap<Pubkey, StoredStake>;
|
||||||
|
@ -281,7 +282,75 @@ pub fn read_stake_from_account_data(mut data: &[u8]) -> anyhow::Result<Option<De
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_stake_tx_message(
|
pub async fn start_stake_verification_loop(
|
||||||
|
rpc_url: String,
|
||||||
|
) -> Sender<(String, Pubkey, Option<StoredStake>)> {
|
||||||
|
let (request_tx, mut request_rx) =
|
||||||
|
tokio::sync::mpsc::channel::<(String, Pubkey, Option<StoredStake>)>(100);
|
||||||
|
tokio::spawn(async move {
|
||||||
|
while let Some((instruction, stake_pk, stake)) = request_rx.recv().await {
|
||||||
|
tokio::spawn({
|
||||||
|
let rpc_url = rpc_url.clone();
|
||||||
|
async move {
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_millis(5000)).await;
|
||||||
|
//get stake from RPC
|
||||||
|
let rpc_client =
|
||||||
|
solana_client::nonblocking::rpc_client::RpcClient::new_with_commitment(
|
||||||
|
rpc_url,
|
||||||
|
solana_sdk::commitment_config::CommitmentConfig::finalized(),
|
||||||
|
);
|
||||||
|
match rpc_client.get_account(&stake_pk).await {
|
||||||
|
Ok(account) => {
|
||||||
|
let stake_data = crate::stakestore::read_stake_from_account_data(
|
||||||
|
account.data.as_slice(),
|
||||||
|
);
|
||||||
|
log::info!(
|
||||||
|
"VERIFICATION Instruction:{instruction} Account:{} verification current stake:{stake:?} Rpc stake:{stake_data:?}",
|
||||||
|
stake_pk
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(solana_client::client_error::ClientError {
|
||||||
|
kind:
|
||||||
|
solana_client::client_error::ClientErrorKind::RpcError(
|
||||||
|
solana_client::rpc_request::RpcError::ForUser(msg),
|
||||||
|
),
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
log::info!(
|
||||||
|
"VERIFICATION Instruction:{instruction} Account:{} verification RPC not found:{}",
|
||||||
|
stake_pk,
|
||||||
|
msg
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::info!(
|
||||||
|
"VERIFICATION Instruction:{instruction} Account:{} verification RPC error:{err}",
|
||||||
|
stake_pk
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
request_tx
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_verification(
|
||||||
|
stake_sender: &mut Sender<(String, Pubkey, Option<StoredStake>)>,
|
||||||
|
stakestore: &mut StakeStore,
|
||||||
|
instr: &str,
|
||||||
|
stake_pybkey: Pubkey,
|
||||||
|
) {
|
||||||
|
let current_stake = stakestore.stakes.get(&stake_pybkey).cloned();
|
||||||
|
stake_sender
|
||||||
|
.send((instr.to_string(), stake_pybkey, current_stake))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn process_stake_tx_message(
|
||||||
|
stake_sender: &mut Sender<(String, Pubkey, Option<StoredStake>)>,
|
||||||
stakestore: &mut StakeStore,
|
stakestore: &mut StakeStore,
|
||||||
account_keys_vec: &[Vec<u8>],
|
account_keys_vec: &[Vec<u8>],
|
||||||
instruction: CompiledInstruction,
|
instruction: CompiledInstruction,
|
||||||
|
@ -330,6 +399,14 @@ pub fn process_stake_tx_message(
|
||||||
, account_keys[instruction.accounts[0] as usize].to_string()
|
, account_keys[instruction.accounts[0] as usize].to_string()
|
||||||
, account_keys[instruction.accounts[1] as usize].to_string()
|
, account_keys[instruction.accounts[1] as usize].to_string()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"Initialize",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::Authorize(new_authorized, authority_type) => {
|
StakeInstruction::Authorize(new_authorized, authority_type) => {
|
||||||
let value = json!({
|
let value = json!({
|
||||||
|
@ -346,6 +423,14 @@ pub fn process_stake_tx_message(
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
log::info!("StakeInstruction::Authorize value:{value} custodian:{custodian:?}");
|
log::info!("StakeInstruction::Authorize value:{value} custodian:{custodian:?}");
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"Authorize",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::DelegateStake => {
|
StakeInstruction::DelegateStake => {
|
||||||
let info = json!({
|
let info = json!({
|
||||||
|
@ -357,6 +442,14 @@ pub fn process_stake_tx_message(
|
||||||
"stakeAuthority": account_keys[instruction.accounts[5] as usize].to_string(),
|
"stakeAuthority": account_keys[instruction.accounts[5] as usize].to_string(),
|
||||||
});
|
});
|
||||||
log::info!("StakeInstruction::DelegateStake infos:{info}");
|
log::info!("StakeInstruction::DelegateStake infos:{info}");
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"DelegateStake",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::Split(lamports) => {
|
StakeInstruction::Split(lamports) => {
|
||||||
let info = json!({
|
let info = json!({
|
||||||
|
@ -366,6 +459,14 @@ pub fn process_stake_tx_message(
|
||||||
"lamports": lamports,
|
"lamports": lamports,
|
||||||
});
|
});
|
||||||
log::info!("StakeInstruction::Split infos:{info}");
|
log::info!("StakeInstruction::Split infos:{info}");
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"Split",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::Withdraw(lamports) => {
|
StakeInstruction::Withdraw(lamports) => {
|
||||||
let info = json!({
|
let info = json!({
|
||||||
|
@ -379,6 +480,14 @@ pub fn process_stake_tx_message(
|
||||||
let custodian = (instruction.accounts.len() >= 6)
|
let custodian = (instruction.accounts.len() >= 6)
|
||||||
.then(|| json!(account_keys[instruction.accounts[5] as usize].to_string()));
|
.then(|| json!(account_keys[instruction.accounts[5] as usize].to_string()));
|
||||||
log::info!("StakeInstruction::Withdraw custodian:{custodian:?}infos:{info}");
|
log::info!("StakeInstruction::Withdraw custodian:{custodian:?}infos:{info}");
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"Withdraw",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::Deactivate => {
|
StakeInstruction::Deactivate => {
|
||||||
let info = json!({
|
let info = json!({
|
||||||
|
@ -406,6 +515,14 @@ pub fn process_stake_tx_message(
|
||||||
"custodian": account_keys[instruction.accounts[1] as usize].to_string(),
|
"custodian": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
});
|
});
|
||||||
log::info!("StakeInstruction::SetLockup unixTimestamp:{unix_timestamp} epoch:{epoch} custodian:{custodian} infos:{info}");
|
log::info!("StakeInstruction::SetLockup unixTimestamp:{unix_timestamp} epoch:{epoch} custodian:{custodian} infos:{info}");
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"SetLockup",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::AuthorizeWithSeed(args) => {
|
StakeInstruction::AuthorizeWithSeed(args) => {
|
||||||
let info = json!({
|
let info = json!({
|
||||||
|
@ -421,6 +538,14 @@ pub fn process_stake_tx_message(
|
||||||
let custodian = (instruction.accounts.len() >= 4)
|
let custodian = (instruction.accounts.len() >= 4)
|
||||||
.then(|| json!(account_keys[instruction.accounts[3] as usize].to_string()));
|
.then(|| json!(account_keys[instruction.accounts[3] as usize].to_string()));
|
||||||
log::info!("StakeInstruction::AuthorizeWithSeed clockSysvar:{clock_sysvar:?} custodian:{custodian:?} infos:{info}");
|
log::info!("StakeInstruction::AuthorizeWithSeed clockSysvar:{clock_sysvar:?} custodian:{custodian:?} infos:{info}");
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"AuthorizeWithSeed",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::InitializeChecked => {
|
StakeInstruction::InitializeChecked => {
|
||||||
let info = json!({
|
let info = json!({
|
||||||
|
@ -430,6 +555,14 @@ pub fn process_stake_tx_message(
|
||||||
"withdrawer": account_keys[instruction.accounts[3] as usize].to_string(),
|
"withdrawer": account_keys[instruction.accounts[3] as usize].to_string(),
|
||||||
});
|
});
|
||||||
log::info!("StakeInstruction::InitializeChecked infos:{info}");
|
log::info!("StakeInstruction::InitializeChecked infos:{info}");
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"InitializeChecked",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::AuthorizeChecked(authority_type) => {
|
StakeInstruction::AuthorizeChecked(authority_type) => {
|
||||||
let info = json!({
|
let info = json!({
|
||||||
|
@ -442,6 +575,14 @@ pub fn process_stake_tx_message(
|
||||||
let custodian = (instruction.accounts.len() >= 5)
|
let custodian = (instruction.accounts.len() >= 5)
|
||||||
.then(|| json!(account_keys[instruction.accounts[4] as usize].to_string()));
|
.then(|| json!(account_keys[instruction.accounts[4] as usize].to_string()));
|
||||||
log::info!("StakeInstruction::AuthorizeChecked custodian:{custodian:?} infos:{info}");
|
log::info!("StakeInstruction::AuthorizeChecked custodian:{custodian:?} infos:{info}");
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"AuthorizeChecked",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::AuthorizeCheckedWithSeed(args) => {
|
StakeInstruction::AuthorizeCheckedWithSeed(args) => {
|
||||||
let info = json!({
|
let info = json!({
|
||||||
|
@ -458,6 +599,14 @@ pub fn process_stake_tx_message(
|
||||||
log::info!(
|
log::info!(
|
||||||
"StakeInstruction::AuthorizeCheckedWithSeed custodian:{custodian:?} infos:{info}"
|
"StakeInstruction::AuthorizeCheckedWithSeed custodian:{custodian:?} infos:{info}"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"AuthorizeCheckedWithSeed",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::SetLockupChecked(lockup_args) => {
|
StakeInstruction::SetLockupChecked(lockup_args) => {
|
||||||
let unix_timestamp = lockup_args
|
let unix_timestamp = lockup_args
|
||||||
|
@ -475,6 +624,14 @@ pub fn process_stake_tx_message(
|
||||||
"custodian": account_keys[instruction.accounts[1] as usize].to_string(),
|
"custodian": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
});
|
});
|
||||||
log::info!("StakeInstruction::SetLockupChecked unixTimestamp:{unix_timestamp} epoch:{epoch} custodian:{custodian:?} infos:{info}");
|
log::info!("StakeInstruction::SetLockupChecked unixTimestamp:{unix_timestamp} epoch:{epoch} custodian:{custodian:?} infos:{info}");
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"SetLockupChecked",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::GetMinimumDelegation => {
|
StakeInstruction::GetMinimumDelegation => {
|
||||||
log::info!("StakeInstruction::GetMinimumDelegation");
|
log::info!("StakeInstruction::GetMinimumDelegation");
|
||||||
|
@ -486,6 +643,14 @@ pub fn process_stake_tx_message(
|
||||||
"referenceVoteAccount": account_keys[instruction.accounts[2] as usize].to_string(),
|
"referenceVoteAccount": account_keys[instruction.accounts[2] as usize].to_string(),
|
||||||
});
|
});
|
||||||
log::info!("StakeInstruction::DeactivateDelinquent infos:{info}");
|
log::info!("StakeInstruction::DeactivateDelinquent infos:{info}");
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"DeactivateDelinquent",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::Redelegate => {
|
StakeInstruction::Redelegate => {
|
||||||
let info = json!({
|
let info = json!({
|
||||||
|
@ -496,6 +661,14 @@ pub fn process_stake_tx_message(
|
||||||
"stakeAuthority": account_keys[instruction.accounts[4] as usize].to_string(),
|
"stakeAuthority": account_keys[instruction.accounts[4] as usize].to_string(),
|
||||||
});
|
});
|
||||||
log::info!("StakeInstruction::Redelegate infos:{info}");
|
log::info!("StakeInstruction::Redelegate infos:{info}");
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"Redelegate",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
StakeInstruction::Merge => {
|
StakeInstruction::Merge => {
|
||||||
let info = json!({
|
let info = json!({
|
||||||
|
@ -516,6 +689,22 @@ pub fn process_stake_tx_message(
|
||||||
source_pubkey.to_string()
|
source_pubkey.to_string()
|
||||||
);
|
);
|
||||||
stakestore.remove_stake(source_pubkey);
|
stakestore.remove_stake(source_pubkey);
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"Merge Destination",
|
||||||
|
account_keys[instruction.accounts[0] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
send_verification(
|
||||||
|
stake_sender,
|
||||||
|
stakestore,
|
||||||
|
"Merge Source",
|
||||||
|
account_keys[instruction.accounts[1] as usize],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue