From decb7d9ed75c0ab06a2bf32d1c181d78eff3245a Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Wed, 7 Aug 2024 17:21:18 -0400 Subject: [PATCH 01/11] Trying to debug confirmation failures --- sdk/src/utils/transactions.rs | 54 ++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/sdk/src/utils/transactions.rs b/sdk/src/utils/transactions.rs index 236bdd2..9e6a69a 100644 --- a/sdk/src/utils/transactions.rs +++ b/sdk/src/utils/transactions.rs @@ -281,14 +281,32 @@ async fn parallel_confirm_transactions( .chunks(SIG_STATUS_BATCH_SIZE) .map(|sig_batch| async move { match get_signature_statuses_with_retry(client, sig_batch).await { - Ok(sig_batch_response) => sig_batch_response - .value - .iter() - .enumerate() - .map(|(i, sig_status)| (sig_batch[i], sig_status.clone())) - .collect::>(), + Ok(sig_batch_response) => { + let res = sig_batch_response + .value + .iter() + .enumerate() + .map(|(i, sig_status)| (sig_batch[i], sig_status.clone())) + .collect::>(); + let count = res + .iter() + .map(|(_, status)| if status.is_some() { 1 } else { 0 }) + .sum::(); + println!( + "Got {} confirmations for {} transactions", + count, + sig_batch.len() + ); + info!( + "Got {} confirmations for {} transactions", + count, + sig_batch.len() + ); + res + } Err(e) => { - info!("Failed getting signature statuses: {}", e); + info!("Failed getting signature statuses: {:?}", e); + println!("Failed getting signature statuses: {:?}", e); vec![] } } @@ -298,16 +316,38 @@ async fn parallel_confirm_transactions( let results = futures::future::join_all(confirmation_futures).await; let mut confirmed_signatures: HashSet = HashSet::new(); + let mut none_count = 0; + let mut err_count = 0; + let mut unsatisfied_commitement_count = 0; for result_batch in results.iter() { for (sig, result) in result_batch { if let Some(status) = result { if status.satisfies_commitment(client.commitment()) && status.err.is_none() { confirmed_signatures.insert(*sig); } + + if status.err.is_some() { + err_count += 1; + } + + if !status.satisfies_commitment(client.commitment()) { + unsatisfied_commitement_count += 1; + } + } else { + none_count += 1; } } } + println!( + "None count: {} Err count: {} Unsatisfied commitment count: {}", + none_count, err_count, unsatisfied_commitement_count + ); + info!( + "None count: {} Err count: {} Unsatisfied commitment count: {}", + none_count, err_count, unsatisfied_commitement_count + ); + info!( "{} transactions submitted, {} confirmed", num_transactions_submitted, From dc25c083c1baa5d8275d1ca07eb647fadc4768b1 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Wed, 7 Aug 2024 17:46:52 -0400 Subject: [PATCH 02/11] trying stuff --- sdk/src/utils/transactions.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sdk/src/utils/transactions.rs b/sdk/src/utils/transactions.rs index 9e6a69a..ba983b8 100644 --- a/sdk/src/utils/transactions.rs +++ b/sdk/src/utils/transactions.rs @@ -405,9 +405,9 @@ pub async fn parallel_execute_transactions( continue; // Skip transactions that have already been confirmed } - if idx % 50 == 0 { + if idx % 20 == 0 { // Need to avoid spamming the rpc or lots of transactions will get dropped - sleep(Duration::from_secs(3)).await; + sleep(Duration::from_secs(1)).await; } // Future optimization: submit these in parallel batches and refresh blockhash for every batch @@ -431,6 +431,7 @@ pub async fn parallel_execute_transactions( submitted_signatures.insert(tx.signatures[0], idx); } Some(_) => { + info!("Transaction error: {:?}", e); match e.kind { solana_client::client_error::ClientErrorKind::Io(e) => { results[idx] = Err(JitoSendTransactionError::TransactionError(format!( From 7cc8837ad31b614fe9e75bcaf3d16ee7c9b1f6f8 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Wed, 7 Aug 2024 20:01:07 -0400 Subject: [PATCH 03/11] trying stuff? --- sdk/src/utils/transactions.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/src/utils/transactions.rs b/sdk/src/utils/transactions.rs index ba983b8..91d0240 100644 --- a/sdk/src/utils/transactions.rs +++ b/sdk/src/utils/transactions.rs @@ -205,12 +205,12 @@ pub async fn get_signature_statuses_with_retry( signatures: &[Signature], ) -> RpcResult>> { for _ in 1..4 { - if let Ok(result) = client.get_signature_statuses(signatures).await { + if let Ok(result) = client.get_signature_statuses_with_history(signatures).await { return Ok(result); } tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; } - client.get_signature_statuses(signatures).await + client.get_signature_statuses_with_history(signatures).await } async fn find_ix_per_tx( @@ -322,7 +322,7 @@ async fn parallel_confirm_transactions( for result_batch in results.iter() { for (sig, result) in result_batch { if let Some(status) = result { - if status.satisfies_commitment(client.commitment()) && status.err.is_none() { + if status.satisfies_commitment() && status.err.is_none() { confirmed_signatures.insert(*sig); } @@ -330,7 +330,7 @@ async fn parallel_confirm_transactions( err_count += 1; } - if !status.satisfies_commitment(client.commitment()) { + if !status.satisfies_commitment(CommitmentConfig::confirmed()) { unsatisfied_commitement_count += 1; } } else { From 6cfc043084a109a879c9fba39b7df8438c5fe385 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Thu, 8 Aug 2024 15:18:42 -0400 Subject: [PATCH 04/11] temp work --- sdk/src/utils/transactions.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sdk/src/utils/transactions.rs b/sdk/src/utils/transactions.rs index 91d0240..7c58d7b 100644 --- a/sdk/src/utils/transactions.rs +++ b/sdk/src/utils/transactions.rs @@ -4,6 +4,7 @@ use std::vec; use std::{collections::HashMap, sync::Arc, time::Duration}; use log::*; +use solana_client::rpc_config::RpcSendTransactionConfig; use solana_client::rpc_response::{ Response, RpcResult, RpcSimulateTransactionResult, RpcVoteAccountInfo, }; @@ -322,7 +323,7 @@ async fn parallel_confirm_transactions( for result_batch in results.iter() { for (sig, result) in result_batch { if let Some(status) = result { - if status.satisfies_commitment() && status.err.is_none() { + if status.satisfies_commitment(CommitmentConfig::confirmed()) && status.err.is_none() { confirmed_signatures.insert(*sig); } @@ -410,8 +411,14 @@ pub async fn parallel_execute_transactions( sleep(Duration::from_secs(1)).await; } + client.simulate_transaction(transaction) + // Future optimization: submit these in parallel batches and refresh blockhash for every batch - match client.send_transaction(tx).await { + match client.send_transaction_with_config(tx, + RpcSendTransactionConfig { + skip_preflight: true, + ..Default::default() + }).await { Ok(signature) => { debug!("🟨 Submitted: {:?}", signature); println!("🟨 Submitted: {:?}", signature); From cbe82d39ccc07205c36db67fcaed6e200387ae52 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Mon, 12 Aug 2024 18:25:13 -0400 Subject: [PATCH 05/11] Cleanup --- sdk/src/utils/transactions.rs | 66 ++++++----------------------------- 1 file changed, 11 insertions(+), 55 deletions(-) diff --git a/sdk/src/utils/transactions.rs b/sdk/src/utils/transactions.rs index 7c58d7b..7ef5ed2 100644 --- a/sdk/src/utils/transactions.rs +++ b/sdk/src/utils/transactions.rs @@ -282,32 +282,14 @@ async fn parallel_confirm_transactions( .chunks(SIG_STATUS_BATCH_SIZE) .map(|sig_batch| async move { match get_signature_statuses_with_retry(client, sig_batch).await { - Ok(sig_batch_response) => { - let res = sig_batch_response - .value - .iter() - .enumerate() - .map(|(i, sig_status)| (sig_batch[i], sig_status.clone())) - .collect::>(); - let count = res - .iter() - .map(|(_, status)| if status.is_some() { 1 } else { 0 }) - .sum::(); - println!( - "Got {} confirmations for {} transactions", - count, - sig_batch.len() - ); - info!( - "Got {} confirmations for {} transactions", - count, - sig_batch.len() - ); - res - } + Ok(sig_batch_response) => sig_batch_response + .value + .iter() + .enumerate() + .map(|(i, sig_status)| (sig_batch[i], sig_status.clone())) + .collect::>(), Err(e) => { info!("Failed getting signature statuses: {:?}", e); - println!("Failed getting signature statuses: {:?}", e); vec![] } } @@ -317,38 +299,19 @@ async fn parallel_confirm_transactions( let results = futures::future::join_all(confirmation_futures).await; let mut confirmed_signatures: HashSet = HashSet::new(); - let mut none_count = 0; - let mut err_count = 0; - let mut unsatisfied_commitement_count = 0; + for result_batch in results.iter() { for (sig, result) in result_batch { if let Some(status) = result { - if status.satisfies_commitment(CommitmentConfig::confirmed()) && status.err.is_none() { + if status.satisfies_commitment(CommitmentConfig::confirmed()) + && status.err.is_none() + { confirmed_signatures.insert(*sig); } - - if status.err.is_some() { - err_count += 1; - } - - if !status.satisfies_commitment(CommitmentConfig::confirmed()) { - unsatisfied_commitement_count += 1; - } - } else { - none_count += 1; } } } - println!( - "None count: {} Err count: {} Unsatisfied commitment count: {}", - none_count, err_count, unsatisfied_commitement_count - ); - info!( - "None count: {} Err count: {} Unsatisfied commitment count: {}", - none_count, err_count, unsatisfied_commitement_count - ); - info!( "{} transactions submitted, {} confirmed", num_transactions_submitted, @@ -411,14 +374,8 @@ pub async fn parallel_execute_transactions( sleep(Duration::from_secs(1)).await; } - client.simulate_transaction(transaction) - // Future optimization: submit these in parallel batches and refresh blockhash for every batch - match client.send_transaction_with_config(tx, - RpcSendTransactionConfig { - skip_preflight: true, - ..Default::default() - }).await { + match client.send_transaction(tx).await { Ok(signature) => { debug!("🟨 Submitted: {:?}", signature); println!("🟨 Submitted: {:?}", signature); @@ -438,7 +395,6 @@ pub async fn parallel_execute_transactions( submitted_signatures.insert(tx.signatures[0], idx); } Some(_) => { - info!("Transaction error: {:?}", e); match e.kind { solana_client::client_error::ClientErrorKind::Io(e) => { results[idx] = Err(JitoSendTransactionError::TransactionError(format!( From 3c8caf82da1468a555d0d41affab762749712990 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 13 Aug 2024 10:52:01 -0400 Subject: [PATCH 06/11] Lint --- run_tests.sh | 11 ++--------- sdk/src/utils/transactions.rs | 1 - 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/run_tests.sh b/run_tests.sh index 4a54f8e..3f16abc 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -4,13 +4,6 @@ cargo build-sbf --manifest-path programs/steward/Cargo.toml; cargo build-sbf --manifest-path programs/validator-history/Cargo.toml; -# Run all tests except the specified one -SBF_OUT_DIR=$(pwd)/target/deploy RUST_MIN_STACK=8000000 cargo test -- --skip steward::test_state_methods +# Run all tests +SBF_OUT_DIR=$(pwd)/target/deploy RUST_MIN_STACK=5000000 cargo test --package tests --all-features --color auto -# Check if the previous command succeeded -if [ $? -eq 0 ]; then - # Run the specific test in isolation - SBF_OUT_DIR=$(pwd)/target/deploy RUST_MIN_STACK=8000000 cargo test --package tests --test mod steward::test_state_methods -else - echo "Some tests failed, skipping the isolated test run." -fi \ No newline at end of file diff --git a/sdk/src/utils/transactions.rs b/sdk/src/utils/transactions.rs index 7ef5ed2..9abe28f 100644 --- a/sdk/src/utils/transactions.rs +++ b/sdk/src/utils/transactions.rs @@ -4,7 +4,6 @@ use std::vec; use std::{collections::HashMap, sync::Arc, time::Duration}; use log::*; -use solana_client::rpc_config::RpcSendTransactionConfig; use solana_client::rpc_response::{ Response, RpcResult, RpcSimulateTransactionResult, RpcVoteAccountInfo, }; From 6397079e741959cce2c84b91e8ba578044be676e Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 13 Aug 2024 11:30:35 -0400 Subject: [PATCH 07/11] Filter certain error codes --- .../validator-keeper/src/operations/steward.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/keepers/validator-keeper/src/operations/steward.rs b/keepers/validator-keeper/src/operations/steward.rs index 2f2324f..fa6965d 100644 --- a/keepers/validator-keeper/src/operations/steward.rs +++ b/keepers/validator-keeper/src/operations/steward.rs @@ -37,6 +37,9 @@ pub enum StewardErrorCodes { InvalidState = 0xA2, // Don't Raise Flag IndexesDontMatch = 0xA3, // Raise Flag VoteHistoryNotRecentEnough = 0xA4, // Don't Raise Flag + AutoRemoveStakeAccountClosed = 0xA5, // Don't Raise Flag + StakePoolNotUpdated = 0xA6, // Don't Raise Flag + ValidatorsNotRemovedYet = 0xA7, // Don't Raise Flag } pub async fn fire( @@ -81,6 +84,21 @@ pub async fn fire( keeper_flags.set_flag(KeeperFlag::RerunVote); StewardErrorCodes::VoteHistoryNotRecentEnough as i64 } + s if s.contains("AutoRemoveValidatorFromPool") + && s.contains("ConstraintOwner") => + { + StewardErrorCodes::AutoRemoveStakeAccountClosed as i64 + } + s if s.contains("UpdateStakePoolBalance") + && s.contains("0x10") => + { + StewardErrorCodes::StakePoolNotUpdated as i64 + } + s if s.contains("AutoAddValidator") + && s.contains("ValidatorsNeedToBeRemoved") => + { + StewardErrorCodes::ValidatorsNotRemovedYet as i64 + } _ => { StewardErrorCodes::UnknownRpcSimulateTransactionResult as i64 From 5c9bcb53dffae24eba5a48b2deca28ad6bbbdde9 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 13 Aug 2024 12:31:51 -0400 Subject: [PATCH 08/11] README for Keeper --- keepers/validator-keeper/README.md | 152 ++++++++++++++++++++++++++--- 1 file changed, 136 insertions(+), 16 deletions(-) diff --git a/keepers/validator-keeper/README.md b/keepers/validator-keeper/README.md index 879fe43..c25c34d 100644 --- a/keepers/validator-keeper/README.md +++ b/keepers/validator-keeper/README.md @@ -1,53 +1,173 @@ -## Keeper State +# StakeNet Keeper Bot + +## Overview + +This is a service that permissionlessly maintains the StakeNet Validator History and Steward programs. It ensures that Validator History data is kept up to date, and that the Steward program is properly moving through its regular operations to maintain the targeted stake pool. Operations, program addresses, and transaction submission details, can be configured via environment variables. + +## Usage + +Prerequisites: + +- RPC endpoint that can handle getProgramAccounts calls +- Keypair loaded with some SOL at stakenet/credentials/keypair.json +- .env file with configuration below + +### Build and run from source + +In `stakenet/` directory: + +``` +docker compose --env-file .env up -d --build validator-keeper +``` + +### Run from Dockerhub + +This image is available on Dockerhub at: (TODO) + +In `stakenet/` directory: + +``` +docker pull /: +docker run -d \ + --name validator-keeper \ + --env-file .env \ + -v $(pwd)/credentials:/credentials \ + --restart on-failure:5 \ + /: +``` + +### Env File for third party Keepers + +In `stakenet/.env`: + +```bash +# RPC URL for the cluster +JSON_RPC_URL="INCLUDE YOUR RPC URL HERE" + +# Cluster to specify (mainnet, testnet, devnet) +CLUSTER=mainnet + +# Log levels +RUST_LOG="info,solana_gossip=error,solana_metrics=info" + +# Path to keypair used to execute tranasactions +KEYPAIR=./credentials/keypair.json + +# Validator history program ID (Pubkey as base58 string) +VALIDATOR_HISTORY_PROGRAM_ID=HistoryJTGbKQD2mRgLZ3XhqHnN811Qpez8X9kCcGHoa + +# Tip distribution program ID (Pubkey as base58 string) +TIP_DISTRIBUTION_PROGRAM_ID=4R3gSG8BpU4t19KYj8CfnbtRpnT8gtk4dvTHxVRwc2r7 + +# Steward program ID +STEWARD_PROGRAM_ID=Stewardf95sJbmtcZsyagb2dg4Mo8eVQho8gpECvLx8 + +# Steward config account for JitoSOL +STEWARD_CONFIG=jitoVjT9jRUyeXHzvCwzPgHj7yWNRhLcUoXtes4wtjv + +# Priority Fees in microlamports +PRIORITY_FEES=20000 + +# Retry count +TX_RETRY_COUNT=100 + +# Confirmation time after submission +TX_CONFIRMATION_SECONDS=30 + +# Run flags (true/false) +RUN_CLUSTER_HISTORY=true +RUN_COPY_VOTE_ACCOUNTS=true +RUN_MEV_COMMISSION=true +RUN_MEV_EARNED=true +RUN_STEWARD=true +RUN_EMIT_METRICS=false + +# Interval to update Validator History Accounts (in seconds) +VALIDATOR_HISTORY_INTERVAL=300 + +# Interval to run steward (in seconds) +STEWARD_INTERVAL=301 + +# Interval to emit metrics (in seconds) +METRICS_INTERVAL=60 + +# For Oracle Authority Only +RUN_STAKE_UPLOAD=false +RUN_GOSSIP_UPLOAD=false + +# Run with the startup flag set to true +FULL_STARTUP=true + +# Running with no_pack set to true skips packing the instructions and will cost more +NO_PACK=false + +# Pay for new accounts when necessary +PAY_FOR_NEW_ACCOUNTS=false + +# Max time in minutes to wait after any fire cycle +COOL_DOWN_RANGE=0 + +# Metrics upload influx server (optional) +SOLANA_METRICS_CONFIG="" +``` + +## Program Layout + +### Keeper State + The `KeeperState` keeps track of: + - current epoch data - running tally of all operations successes and failures for the given epoch - all accounts fetched from the RPC that are needed downstream Note: All maps are key'd by the `vote_account` -## Program - ### Initialize -Gather all needed arguments, and initialize the global `KeeperState`. + +Gather all needed arguments, and initialize the global `KeeperState`. ### Loop -The forever loop consists of three parts: **Fetch**, **Fire** and **Emit**. There is only ever one **Fetch** and **Emit** section, and there can be several **Fire** sections. + +The forever loop consists of three parts: **Fetch**, **Fire** and **Emit**. There is only ever one **Fetch** and **Emit** section, and there can be several **Fire** sections. The **Fire** sections can run on independent cadences - say we want the Validator History functions to run every 300sec and we want to emit metrics every 60sec. -The **Fetch** section is run _before_ and **Fire** section. -The **Emit** section is *one tick* after any **Fire** section. +The **Fetch** section is run _before_ and **Fire** section. +The **Emit** section is _one tick_ after any **Fire** section. #### Fetch + The **Fetch** section is in charge of three operations: + - Keeping track of the current epoch and resetting the runs and error counts for each operation - Creating any missing accounts needed for the downstream **Fires** to run - Fetching and updating all of the needed accounts needed downstream This is accomplished is by running three functions within the **Fetch** section + - `pre_create_update` - Updates epoch, and fetches all needed accounts that are not dependant on any missing accounts. - `create_missing_accounts` - Creates the missing accounts, which can be determined by the accounts fetched in the previous step -- `post_create_update` - Fetches any last accounts that needed the missing accounts +- `post_create_update` - Fetches any last accounts that needed the missing accounts Since this is run before every **FIRE** section, some accounts will be fetched that are not needed. This may seem wasteful but the simplicity of having a synchronized global is worth the cost. -Notes: -- The **Fetch** section is the only section that will mutate the `KeeperState`. +Notes: + +- The **Fetch** section is the only section that will mutate the `KeeperState`. - If anything in the **Fetch** section fails, no **Fires** will run #### Fire + There are several **Fire** sections running at their own cadence. Before any **Fire** section is run, the **Fetch** section will be called. Each **Fire** is a call to `operations::operation_name::fire` which will fire off the operation and return the new count of runs and errors for that operation to be saved in the `KeeperState` -Notes: -- Each **Fire** is self contained, one should not be dependant on another. -- No **Fire* will fetch any accounts, if there are needs for them, they should be added to the `KeeperState` +Notes: +- Each **Fire** is self contained, one should not be dependant on another. +- No \*_Fire_ will fetch any accounts, if there are needs for them, they should be added to the `KeeperState` #### Emit -This section emits the state of the Keeper one tick after any operation has been called. This is because we want to emit a failure of any **Fetch** operation, which on failure advances the tick. - - +This section emits the state of the Keeper one tick after any operation has been called. This is because we want to emit a failure of any **Fetch** operation, which on failure advances the tick. From cccf83b989ec5eee75fa55225db8f5e51669efc1 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 13 Aug 2024 12:52:34 -0400 Subject: [PATCH 09/11] Fix readme, rename keeper --- Cargo.lock | 64 +++++------ Dockerfile | 4 +- docker-compose.yaml | 4 +- keeper-bot-quick-start.md | 90 ++++++++------- .../Cargo.toml | 2 +- .../README.md | 107 +----------------- .../src/entries/copy_vote_account_entry.rs | 0 .../src/entries/crank_steward.rs | 0 .../src/entries/gossip_entry.rs | 0 .../src/entries/mev_commission_entry.rs | 0 .../src/entries/mod.rs | 0 .../src/entries/stake_history_entry.rs | 0 .../src/lib.rs | 0 .../src/main.rs | 6 +- .../src/operations/cluster_history.rs | 0 .../src/operations/gossip_upload.rs | 0 .../src/operations/keeper_operations.rs | 0 .../src/operations/metrics_emit.rs | 0 .../src/operations/mev_commission.rs | 0 .../src/operations/mev_earned.rs | 0 .../src/operations/mod.rs | 0 .../src/operations/stake_upload.rs | 0 .../src/operations/steward.rs | 0 .../src/operations/vote_account.rs | 0 .../src/state/keeper_config.rs | 0 .../src/state/keeper_state.rs | 0 .../src/state/mod.rs | 0 .../src/state/update_state.rs | 0 utils/steward-cli/Cargo.toml | 2 +- .../src/commands/cranks/steward.rs | 2 +- 30 files changed, 94 insertions(+), 187 deletions(-) rename keepers/{validator-keeper => stakenet-keeper}/Cargo.toml (97%) rename keepers/{validator-keeper => stakenet-keeper}/README.md (55%) rename keepers/{validator-keeper => stakenet-keeper}/src/entries/copy_vote_account_entry.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/entries/crank_steward.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/entries/gossip_entry.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/entries/mev_commission_entry.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/entries/mod.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/entries/stake_history_entry.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/lib.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/main.rs (99%) rename keepers/{validator-keeper => stakenet-keeper}/src/operations/cluster_history.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/operations/gossip_upload.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/operations/keeper_operations.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/operations/metrics_emit.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/operations/mev_commission.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/operations/mev_earned.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/operations/mod.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/operations/stake_upload.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/operations/steward.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/operations/vote_account.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/state/keeper_config.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/state/keeper_state.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/state/mod.rs (100%) rename keepers/{validator-keeper => stakenet-keeper}/src/state/update_state.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 5af13eb..ad0897d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6096,6 +6096,37 @@ dependencies = [ "spl-program-error", ] +[[package]] +name = "stakenet-keeper" +version = "0.1.0" +dependencies = [ + "anchor-lang", + "bytemuck", + "clap 4.4.18", + "dotenv", + "env_logger 0.10.2", + "futures", + "futures-util", + "jito-steward", + "jito-tip-distribution", + "log", + "rand 0.8.5", + "solana-account-decoder", + "solana-clap-utils", + "solana-client", + "solana-gossip", + "solana-metrics", + "solana-net-utils", + "solana-program", + "solana-sdk", + "solana-streamer", + "spl-stake-pool", + "stakenet-sdk", + "thiserror", + "tokio", + "validator-history", +] + [[package]] name = "stakenet-sdk" version = "0.1.0" @@ -6146,11 +6177,11 @@ dependencies = [ "solana-sdk", "spl-pod", "spl-stake-pool", + "stakenet-keeper", "stakenet-sdk", "thiserror", "tokio", "validator-history", - "validator-keeper", ] [[package]] @@ -7071,37 +7102,6 @@ dependencies = [ "solana-program", ] -[[package]] -name = "validator-keeper" -version = "0.1.0" -dependencies = [ - "anchor-lang", - "bytemuck", - "clap 4.4.18", - "dotenv", - "env_logger 0.10.2", - "futures", - "futures-util", - "jito-steward", - "jito-tip-distribution", - "log", - "rand 0.8.5", - "solana-account-decoder", - "solana-clap-utils", - "solana-client", - "solana-gossip", - "solana-metrics", - "solana-net-utils", - "solana-program", - "solana-sdk", - "solana-streamer", - "spl-stake-pool", - "stakenet-sdk", - "thiserror", - "tokio", - "validator-history", -] - [[package]] name = "valuable" version = "0.1.0" diff --git a/Dockerfile b/Dockerfile index 76d0207..31ae0c2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,13 +10,13 @@ COPY . . RUN --mount=type=cache,mode=0777,target=/home/root/app/target \ --mount=type=cache,mode=0777,target=/usr/local/cargo/registry \ - cargo build --release --bin validator-keeper + cargo build --release --bin stakenet-keeper ######### FROM debian:buster as validator-history RUN apt-get update && apt-get install -y ca-certificates -ENV APP="validator-keeper" +ENV APP="stakenet-keeper" COPY --from=builder /usr/src/app/target/release/$APP ./$APP diff --git a/docker-compose.yaml b/docker-compose.yaml index 9ff0e14..197fb45 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,10 +1,10 @@ version: "3" services: - validator-keeper: + stakenet-keeper: build: context: . target: validator-history - container_name: validator-keeper + container_name: stakenet-keeper environment: - RUST_LOG=${RUST_LOG:-info} - SOLANA_METRICS_CONFIG=${SOLANA_METRICS_CONFIG} diff --git a/keeper-bot-quick-start.md b/keeper-bot-quick-start.md index 272344b..6824b56 100644 --- a/keeper-bot-quick-start.md +++ b/keeper-bot-quick-start.md @@ -15,18 +15,17 @@ solana-keygen new -o ./credentials/keypair.json ### ENV -In the root directory create a new folder named `config` and create a `.env` file inside of it +In the root directory create `.env` file ```bash -mkdir config -touch ./config/.env +touch .env ``` -Then copy into the `.env` file the contents below. Everything should be set as-is, however consider replacing the `JSON_RPC_URL` and adjusting the `PRIORITY_FEES` +Then copy into the `.env` file the contents below. Everything should be set as-is, however you will need to include a `JSON_RPC_URL` that can handle getProgramAccounts calls. -```.env +```bash # RPC URL for the cluster -JSON_RPC_URL=https://api.mainnet-beta.solana.com +JSON_RPC_URL="INCLUDE YOUR RPC URL HERE" # Cluster to specify (mainnet, testnet, devnet) CLUSTER=mainnet @@ -34,7 +33,7 @@ CLUSTER=mainnet # Log levels RUST_LOG="info,solana_gossip=error,solana_metrics=info" -# Path to keypair used to pay for account creation and execute transactions +# Path to keypair used to execute tranasactions KEYPAIR=./credentials/keypair.json # Validator history program ID (Pubkey as base58 string) @@ -46,59 +45,56 @@ TIP_DISTRIBUTION_PROGRAM_ID=4R3gSG8BpU4t19KYj8CfnbtRpnT8gtk4dvTHxVRwc2r7 # Steward program ID STEWARD_PROGRAM_ID=Stewardf95sJbmtcZsyagb2dg4Mo8eVQho8gpECvLx8 -# Steward config account +# Steward config account for JitoSOL STEWARD_CONFIG=jitoVjT9jRUyeXHzvCwzPgHj7yWNRhLcUoXtes4wtjv # Priority Fees in microlamports PRIORITY_FEES=20000 +# Retry count +TX_RETRY_COUNT=100 + +# Confirmation time after submission +TX_CONFIRMATION_SECONDS=30 + # Run flags (true/false) RUN_CLUSTER_HISTORY=true RUN_COPY_VOTE_ACCOUNTS=true RUN_MEV_COMMISSION=true RUN_MEV_EARNED=true RUN_STEWARD=true -RUN_EMIT_METRICS=true - -################# DEBUGGING AND ORACLE USE ONLY ################# +RUN_EMIT_METRICS=false # Interval to update Validator History Accounts (in seconds) -# VALIDATOR_HISTORY_INTERVAL=300 +VALIDATOR_HISTORY_INTERVAL=300 # Interval to run steward (in seconds) -# STEWARD_INTERVAL=301 +STEWARD_INTERVAL=301 # Interval to emit metrics (in seconds) -# METRICS_INTERVAL=60 +METRICS_INTERVAL=60 -# For ORACLE_AUTHORITY operator -# RUN_STAKE_UPLOAD=false -# RUN_GOSSIP_UPLOAD=false +# For Oracle Authority Only +RUN_STAKE_UPLOAD=false +RUN_GOSSIP_UPLOAD=false # Run with the startup flag set to true -# FULL_STARTUP=true +FULL_STARTUP=true # Running with no_pack set to true skips packing the instructions and will cost more -# NO_PACK=false +NO_PACK=false # Pay for new accounts when necessary -# PAY_FOR_NEW_ACCOUNTS=false +PAY_FOR_NEW_ACCOUNTS=false # Max time in minutes to wait after any fire cycle -# COOL_DOWN_RANGE=20 +COOL_DOWN_RANGE=20 -# Gossip entrypoint in the form of URL:PORT -# GOSSIP_ENTRYPOINT= - -# Metrics upload config -# For uploading metrics to your private InfluxDB instance -# SOLANA_METRICS_CONFIG= - -# Path to keypair used specifically for submitting permissioned transactions -# ORACLE_AUTHORITY_KEYPAIR= +# Metrics upload influx server (optional) +SOLANA_METRICS_CONFIG="" ``` -## Running Docker +## Running Docker image from source Once the setup is complete use the following commands to run/manage the docker container: @@ -107,39 +103,53 @@ Once the setup is complete use the following commands to run/manage the docker c ### Start Docker ```bash -docker compose --env-file config/.env up -d --build validator-keeper --remove-orphans +docker compose --env-file .env up -d --build stakenet-keeper --remove-orphans ``` -### Stop Docker** +### View Logs ```bash -docker stop validator-keeper; docker rm validator-keeper; +docker logs stakenet-keeper -f ``` -### View Logs +### Stop Docker\*\* + +```bash +docker stop stakenet-keeper; docker rm stakenet-keeper; +``` + +## Run from Dockerhub + +This image is available on Dockerhub at: (TODO) ```bash -docker logs validator-keeper -f +docker pull /: +docker run -d \ + --name stakenet-keeper \ + --env-file .env \ + -v $(pwd)/credentials:/credentials \ + --restart on-failure:5 \ + /: ``` -## Running Raw +## Running as Binary To run the keeper in terminal, build for release and run the program. ### Build for Release ```bash -cargo build --release --bin validator-keeper +cargo build --release --bin stakenet-keeper ``` ### Run Keeper ```bash -RUST_LOG=info cargo run --bin validator-keeper -- +RUST_LOG=info ./target/release/stakenet-keeper ``` To see all available parameters run: ```bash -RUST_LOG=info cargo run --bin validator-keeper -- -h +RUST_LOG=info ./target/release/stakenet-keeper -h ``` diff --git a/keepers/validator-keeper/Cargo.toml b/keepers/stakenet-keeper/Cargo.toml similarity index 97% rename from keepers/validator-keeper/Cargo.toml rename to keepers/stakenet-keeper/Cargo.toml index 927bfd4..a95837a 100644 --- a/keepers/validator-keeper/Cargo.toml +++ b/keepers/stakenet-keeper/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "validator-keeper" +name = "stakenet-keeper" version = "0.1.0" edition = "2021" description = "Script to keep validator history accounts up to date" diff --git a/keepers/validator-keeper/README.md b/keepers/stakenet-keeper/README.md similarity index 55% rename from keepers/validator-keeper/README.md rename to keepers/stakenet-keeper/README.md index c25c34d..7d22d2c 100644 --- a/keepers/validator-keeper/README.md +++ b/keepers/stakenet-keeper/README.md @@ -2,114 +2,11 @@ ## Overview -This is a service that permissionlessly maintains the StakeNet Validator History and Steward programs. It ensures that Validator History data is kept up to date, and that the Steward program is properly moving through its regular operations to maintain the targeted stake pool. Operations, program addresses, and transaction submission details, can be configured via environment variables. +This is a service that permissionlessly maintains the StakeNet Validator History and Steward programs. It ensures that Validator History data is kept up to date, and that the Steward program is properly moving through its regular operations to maintain the targeted stake pool. Operations, program addresses, and transaction submission details, can be configured via arguments or environment variables. ## Usage -Prerequisites: - -- RPC endpoint that can handle getProgramAccounts calls -- Keypair loaded with some SOL at stakenet/credentials/keypair.json -- .env file with configuration below - -### Build and run from source - -In `stakenet/` directory: - -``` -docker compose --env-file .env up -d --build validator-keeper -``` - -### Run from Dockerhub - -This image is available on Dockerhub at: (TODO) - -In `stakenet/` directory: - -``` -docker pull /: -docker run -d \ - --name validator-keeper \ - --env-file .env \ - -v $(pwd)/credentials:/credentials \ - --restart on-failure:5 \ - /: -``` - -### Env File for third party Keepers - -In `stakenet/.env`: - -```bash -# RPC URL for the cluster -JSON_RPC_URL="INCLUDE YOUR RPC URL HERE" - -# Cluster to specify (mainnet, testnet, devnet) -CLUSTER=mainnet - -# Log levels -RUST_LOG="info,solana_gossip=error,solana_metrics=info" - -# Path to keypair used to execute tranasactions -KEYPAIR=./credentials/keypair.json - -# Validator history program ID (Pubkey as base58 string) -VALIDATOR_HISTORY_PROGRAM_ID=HistoryJTGbKQD2mRgLZ3XhqHnN811Qpez8X9kCcGHoa - -# Tip distribution program ID (Pubkey as base58 string) -TIP_DISTRIBUTION_PROGRAM_ID=4R3gSG8BpU4t19KYj8CfnbtRpnT8gtk4dvTHxVRwc2r7 - -# Steward program ID -STEWARD_PROGRAM_ID=Stewardf95sJbmtcZsyagb2dg4Mo8eVQho8gpECvLx8 - -# Steward config account for JitoSOL -STEWARD_CONFIG=jitoVjT9jRUyeXHzvCwzPgHj7yWNRhLcUoXtes4wtjv - -# Priority Fees in microlamports -PRIORITY_FEES=20000 - -# Retry count -TX_RETRY_COUNT=100 - -# Confirmation time after submission -TX_CONFIRMATION_SECONDS=30 - -# Run flags (true/false) -RUN_CLUSTER_HISTORY=true -RUN_COPY_VOTE_ACCOUNTS=true -RUN_MEV_COMMISSION=true -RUN_MEV_EARNED=true -RUN_STEWARD=true -RUN_EMIT_METRICS=false - -# Interval to update Validator History Accounts (in seconds) -VALIDATOR_HISTORY_INTERVAL=300 - -# Interval to run steward (in seconds) -STEWARD_INTERVAL=301 - -# Interval to emit metrics (in seconds) -METRICS_INTERVAL=60 - -# For Oracle Authority Only -RUN_STAKE_UPLOAD=false -RUN_GOSSIP_UPLOAD=false - -# Run with the startup flag set to true -FULL_STARTUP=true - -# Running with no_pack set to true skips packing the instructions and will cost more -NO_PACK=false - -# Pay for new accounts when necessary -PAY_FOR_NEW_ACCOUNTS=false - -# Max time in minutes to wait after any fire cycle -COOL_DOWN_RANGE=0 - -# Metrics upload influx server (optional) -SOLANA_METRICS_CONFIG="" -``` +See [keeper-bot-quick-start.md](../../keeper-bot-quick-start.md) for instructions on how to build and run this service. ## Program Layout diff --git a/keepers/validator-keeper/src/entries/copy_vote_account_entry.rs b/keepers/stakenet-keeper/src/entries/copy_vote_account_entry.rs similarity index 100% rename from keepers/validator-keeper/src/entries/copy_vote_account_entry.rs rename to keepers/stakenet-keeper/src/entries/copy_vote_account_entry.rs diff --git a/keepers/validator-keeper/src/entries/crank_steward.rs b/keepers/stakenet-keeper/src/entries/crank_steward.rs similarity index 100% rename from keepers/validator-keeper/src/entries/crank_steward.rs rename to keepers/stakenet-keeper/src/entries/crank_steward.rs diff --git a/keepers/validator-keeper/src/entries/gossip_entry.rs b/keepers/stakenet-keeper/src/entries/gossip_entry.rs similarity index 100% rename from keepers/validator-keeper/src/entries/gossip_entry.rs rename to keepers/stakenet-keeper/src/entries/gossip_entry.rs diff --git a/keepers/validator-keeper/src/entries/mev_commission_entry.rs b/keepers/stakenet-keeper/src/entries/mev_commission_entry.rs similarity index 100% rename from keepers/validator-keeper/src/entries/mev_commission_entry.rs rename to keepers/stakenet-keeper/src/entries/mev_commission_entry.rs diff --git a/keepers/validator-keeper/src/entries/mod.rs b/keepers/stakenet-keeper/src/entries/mod.rs similarity index 100% rename from keepers/validator-keeper/src/entries/mod.rs rename to keepers/stakenet-keeper/src/entries/mod.rs diff --git a/keepers/validator-keeper/src/entries/stake_history_entry.rs b/keepers/stakenet-keeper/src/entries/stake_history_entry.rs similarity index 100% rename from keepers/validator-keeper/src/entries/stake_history_entry.rs rename to keepers/stakenet-keeper/src/entries/stake_history_entry.rs diff --git a/keepers/validator-keeper/src/lib.rs b/keepers/stakenet-keeper/src/lib.rs similarity index 100% rename from keepers/validator-keeper/src/lib.rs rename to keepers/stakenet-keeper/src/lib.rs diff --git a/keepers/validator-keeper/src/main.rs b/keepers/stakenet-keeper/src/main.rs similarity index 99% rename from keepers/validator-keeper/src/main.rs rename to keepers/stakenet-keeper/src/main.rs index 5bb4a2b..186f2a7 100644 --- a/keepers/validator-keeper/src/main.rs +++ b/keepers/stakenet-keeper/src/main.rs @@ -10,9 +10,7 @@ use rand::Rng; use solana_client::nonblocking::rpc_client::RpcClient; use solana_metrics::set_host_id; use solana_sdk::signature::read_keypair_file; -use std::{sync::Arc, time::Duration}; -use tokio::time::sleep; -use validator_keeper::{ +use stakenet_keeper::{ operations::{ self, keeper_operations::{set_flag, KeeperCreates, KeeperOperations}, @@ -23,6 +21,8 @@ use validator_keeper::{ update_state::{create_missing_accounts, post_create_update, pre_create_update}, }, }; +use std::{sync::Arc, time::Duration}; +use tokio::time::sleep; fn set_run_flags(args: &Args) -> u32 { let mut run_flags = 0; diff --git a/keepers/validator-keeper/src/operations/cluster_history.rs b/keepers/stakenet-keeper/src/operations/cluster_history.rs similarity index 100% rename from keepers/validator-keeper/src/operations/cluster_history.rs rename to keepers/stakenet-keeper/src/operations/cluster_history.rs diff --git a/keepers/validator-keeper/src/operations/gossip_upload.rs b/keepers/stakenet-keeper/src/operations/gossip_upload.rs similarity index 100% rename from keepers/validator-keeper/src/operations/gossip_upload.rs rename to keepers/stakenet-keeper/src/operations/gossip_upload.rs diff --git a/keepers/validator-keeper/src/operations/keeper_operations.rs b/keepers/stakenet-keeper/src/operations/keeper_operations.rs similarity index 100% rename from keepers/validator-keeper/src/operations/keeper_operations.rs rename to keepers/stakenet-keeper/src/operations/keeper_operations.rs diff --git a/keepers/validator-keeper/src/operations/metrics_emit.rs b/keepers/stakenet-keeper/src/operations/metrics_emit.rs similarity index 100% rename from keepers/validator-keeper/src/operations/metrics_emit.rs rename to keepers/stakenet-keeper/src/operations/metrics_emit.rs diff --git a/keepers/validator-keeper/src/operations/mev_commission.rs b/keepers/stakenet-keeper/src/operations/mev_commission.rs similarity index 100% rename from keepers/validator-keeper/src/operations/mev_commission.rs rename to keepers/stakenet-keeper/src/operations/mev_commission.rs diff --git a/keepers/validator-keeper/src/operations/mev_earned.rs b/keepers/stakenet-keeper/src/operations/mev_earned.rs similarity index 100% rename from keepers/validator-keeper/src/operations/mev_earned.rs rename to keepers/stakenet-keeper/src/operations/mev_earned.rs diff --git a/keepers/validator-keeper/src/operations/mod.rs b/keepers/stakenet-keeper/src/operations/mod.rs similarity index 100% rename from keepers/validator-keeper/src/operations/mod.rs rename to keepers/stakenet-keeper/src/operations/mod.rs diff --git a/keepers/validator-keeper/src/operations/stake_upload.rs b/keepers/stakenet-keeper/src/operations/stake_upload.rs similarity index 100% rename from keepers/validator-keeper/src/operations/stake_upload.rs rename to keepers/stakenet-keeper/src/operations/stake_upload.rs diff --git a/keepers/validator-keeper/src/operations/steward.rs b/keepers/stakenet-keeper/src/operations/steward.rs similarity index 100% rename from keepers/validator-keeper/src/operations/steward.rs rename to keepers/stakenet-keeper/src/operations/steward.rs diff --git a/keepers/validator-keeper/src/operations/vote_account.rs b/keepers/stakenet-keeper/src/operations/vote_account.rs similarity index 100% rename from keepers/validator-keeper/src/operations/vote_account.rs rename to keepers/stakenet-keeper/src/operations/vote_account.rs diff --git a/keepers/validator-keeper/src/state/keeper_config.rs b/keepers/stakenet-keeper/src/state/keeper_config.rs similarity index 100% rename from keepers/validator-keeper/src/state/keeper_config.rs rename to keepers/stakenet-keeper/src/state/keeper_config.rs diff --git a/keepers/validator-keeper/src/state/keeper_state.rs b/keepers/stakenet-keeper/src/state/keeper_state.rs similarity index 100% rename from keepers/validator-keeper/src/state/keeper_state.rs rename to keepers/stakenet-keeper/src/state/keeper_state.rs diff --git a/keepers/validator-keeper/src/state/mod.rs b/keepers/stakenet-keeper/src/state/mod.rs similarity index 100% rename from keepers/validator-keeper/src/state/mod.rs rename to keepers/stakenet-keeper/src/state/mod.rs diff --git a/keepers/validator-keeper/src/state/update_state.rs b/keepers/stakenet-keeper/src/state/update_state.rs similarity index 100% rename from keepers/validator-keeper/src/state/update_state.rs rename to keepers/stakenet-keeper/src/state/update_state.rs diff --git a/utils/steward-cli/Cargo.toml b/utils/steward-cli/Cargo.toml index 72f371e..38e8eb1 100644 --- a/utils/steward-cli/Cargo.toml +++ b/utils/steward-cli/Cargo.toml @@ -25,4 +25,4 @@ stakenet-sdk = { path = "../../sdk" } thiserror = "1.0.37" tokio = { version = "1.36.0", features = ["full"] } validator-history = { features = ["no-entrypoint"], path = "../../programs/validator-history" } -validator-keeper = { path = "../../keepers/validator-keeper" } +stakenet-keeper = { path = "../../keepers/stakenet-keeper" } diff --git a/utils/steward-cli/src/commands/cranks/steward.rs b/utils/steward-cli/src/commands/cranks/steward.rs index 61ed514..c08a104 100644 --- a/utils/steward-cli/src/commands/cranks/steward.rs +++ b/utils/steward-cli/src/commands/cranks/steward.rs @@ -4,12 +4,12 @@ use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::{pubkey::Pubkey, signature::read_keypair_file}; +use stakenet_keeper::entries::crank_steward::crank_steward; use stakenet_sdk::utils::accounts::get_all_steward_accounts; use stakenet_sdk::utils::accounts::{ get_all_steward_validator_accounts, get_all_validator_accounts, }; use stakenet_sdk::utils::transactions::get_vote_accounts_with_retry; -use validator_keeper::entries::crank_steward::crank_steward; use crate::commands::command_args::CrankSteward; From e1480fef7070c938d4aa52699411756f69c8479a Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 13 Aug 2024 18:47:44 -0400 Subject: [PATCH 10/11] Dockerhub --- keeper-bot-quick-start.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/keeper-bot-quick-start.md b/keeper-bot-quick-start.md index 6824b56..a9223c8 100644 --- a/keeper-bot-quick-start.md +++ b/keeper-bot-quick-start.md @@ -120,16 +120,16 @@ docker stop stakenet-keeper; docker rm stakenet-keeper; ## Run from Dockerhub -This image is available on Dockerhub at: (TODO) +This image is available on Dockerhub at: https://hub.docker.com/r/jitolabs/stakenet-keeper ```bash -docker pull /: +docker pull jitolabs/stakenet-keeper:latest docker run -d \ --name stakenet-keeper \ --env-file .env \ -v $(pwd)/credentials:/credentials \ --restart on-failure:5 \ - /: + jitolabs/stakenet-keeper:latest ``` ## Running as Binary From 855984424e301789a5abcc8f3f79123726cb304a Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 13 Aug 2024 19:04:47 -0400 Subject: [PATCH 11/11] dependency order --- utils/steward-cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/steward-cli/Cargo.toml b/utils/steward-cli/Cargo.toml index 38e8eb1..d2b419a 100644 --- a/utils/steward-cli/Cargo.toml +++ b/utils/steward-cli/Cargo.toml @@ -21,8 +21,8 @@ solana-program = "1.18" solana-sdk = "1.18" spl-pod = "0.1.0" spl-stake-pool = { features = ["no-entrypoint"], version = "1.0.0" } +stakenet-keeper = { path = "../../keepers/stakenet-keeper" } stakenet-sdk = { path = "../../sdk" } thiserror = "1.0.37" tokio = { version = "1.36.0", features = ["full"] } validator-history = { features = ["no-entrypoint"], path = "../../programs/validator-history" } -stakenet-keeper = { path = "../../keepers/stakenet-keeper" }