Skip to content

Commit

Permalink
feat: TipRouter CLI separate stages (#87)
Browse files Browse the repository at this point in the history
### Change notes
* New top-level environment variable/CLI arg
* SAVE_PATH: renaming of `META_MERKLE_TREE_DIR`. Path where all
generated operator files are stored
* Separates each stage of the process into more coherent functions. 
* `run` CLI command loops through each stage, saving the outputs to
_save-path_ CLI argument. The output from each stage is held in memory
to reduce the processing.
        * New Environment Variables/CLI Args for `run`
* STARTING_STAGE: Ability to start the operator from a specific stage
before it continues
* one of: `load-bank-from-snapshot, create-stake-meta,
create-merkle-tree-collection, create-meta-merkle-tree, cast-vote,
wait-for-next-epoch`
* SAVE_STAGES: true/false - whether to save the state of intermediate
stages in files. Needed for CLAIM_TIPS and SET_MERKLE_ROOT
* SAVE_SNAPSHOTS: true/false - whether to save the bank loaded in the
target as a full snapshot (~100GB).
* Create CLI commands for each stage
* _snapshot-slot_ - Create and store a full snapshot for a given slot
* _create-stake-meta_ - For a given epoch and slot, load the bank and
create the `StakeMetaCollection` file which contains validator vote
accounts and their staking delegations.
* _create-merkle-tree-collection_ - For a given epoch, load the
`StakeMetaCollection` from disk at _save-path_, generate and save the
`GeneratedMerkleTreeCollection`.
* _create-meta-merkle-tree_ - For a given epoch, load the
`GeneratedMerkleTreeCollection` from disk at _save-path_, generate and
save the`MetaMerkleTree`.
* _submit-epoch_ - For a given epoch, load the MetaMerkle file and cast
a vote to the NCN's ballot box. Optionally set the merkle root on the
Tip Distribution account if the NCN has consensus for the epoch.
* _claim-tips_ - For a given epoch, generate and execute Tip
Distribution Claim instructions for any unclaimed tips.
* TipRouter saved files
    * generated files are now saved under _save-path_
* Files _<= current_epoch - num_monitored_epochs_ are purged for
anything
* NOTE: file names have change to a _{epoch}_file_name.json_ format. All
previous files will not be removed. Operators should manually delete old
files.

---------

Co-authored-by: Evan Batsell <[email protected]>
  • Loading branch information
tomjohn1028 and ebatsell authored Mar 11, 2025
1 parent 7bf9c11 commit d27f552
Show file tree
Hide file tree
Showing 17 changed files with 1,153 additions and 695 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ jobs:
name: jito_tip_router_program.so
path: integration_tests/tests/fixtures/
- uses: taiki-e/install-action@nextest
- run: cargo nextest run --all-features -E 'not test(ledger_utils::tests::test_get_bank_from_ledger_success) and not test(test_meta_merkle_creation_from_ledger)'
- run: cargo nextest run --all-features -E 'not test(ledger_utils::tests)'
env:
SBF_OUT_DIR: ${{ github.workspace }}/integration_tests/tests/fixtures

Expand Down
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion format.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ cargo fmt --all

print_executing "cargo nextest run --all-features"
cargo build-sbf --sbf-out-dir integration_tests/tests/fixtures
SBF_OUT_DIR=integration_tests/tests/fixtures cargo nextest run --all-features -E 'not test(ledger_utils::tests::test_get_bank_from_ledger_success) and not test(test_meta_merkle_creation_from_ledger)'
SBF_OUT_DIR=integration_tests/tests/fixtures cargo nextest run --all-features -E 'not test(ledger_utils::tests::test_get_bank_from_ledger_success)'

# Code coverage only runs with flag
if [[ "$*" == *"--code-coverage"* ]]; then
Expand Down
32 changes: 31 additions & 1 deletion meta_merkle_tree/src/generated_merkle_tree.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use std::{fs::File, io::BufReader, path::PathBuf};
use std::{
fs::File,
io::{BufReader, Write},
path::PathBuf,
};

use jito_tip_distribution_sdk::{
jito_tip_distribution::ID as TIP_DISTRIBUTION_ID, CLAIM_STATUS_SEED,
Expand Down Expand Up @@ -119,6 +123,14 @@ impl GeneratedMerkleTreeCollection {

Ok(tree)
}

/// Write a GeneratedMerkleTreeCollection to a filepath
pub fn write_to_file(&self, path: &PathBuf) -> Result<(), MerkleRootGeneratorError> {
let serialized = serde_json::to_string_pretty(&self)?;
let mut file = File::create(path)?;
file.write_all(serialized.as_bytes())?;
Ok(())
}
}

#[derive(Clone, Eq, Debug, Hash, PartialEq, Deserialize, Serialize)]
Expand Down Expand Up @@ -339,6 +351,24 @@ pub struct StakeMetaCollection {
pub slot: Slot,
}

impl StakeMetaCollection {
/// Load a serialized merkle tree from file path
pub fn new_from_file(path: &PathBuf) -> Result<Self, MerkleRootGeneratorError> {
let file = File::open(path)?;
let reader = BufReader::new(file);
let tree: Self = serde_json::from_reader(reader)?;

Ok(tree)
}

/// Write a merkle tree to a filepath
pub fn write_to_file(&self, path: &PathBuf) {
let serialized = serde_json::to_string_pretty(&self).unwrap();
let mut file = File::create(path).unwrap();
file.write_all(serialized.as_bytes()).unwrap();
}
}

#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq)]
pub struct StakeMeta {
#[serde(with = "pubkey_string_conversion")]
Expand Down
11 changes: 6 additions & 5 deletions meta_merkle_tree/src/meta_merkle_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,11 @@ impl MetaMerkleTree {
}

/// Write a merkle tree to a filepath
pub fn write_to_file(&self, path: &PathBuf) {
let serialized = serde_json::to_string_pretty(&self).unwrap();
let mut file = File::create(path).unwrap();
file.write_all(serialized.as_bytes()).unwrap();
pub fn write_to_file(&self, path: &PathBuf) -> Result<()> {
let serialized = serde_json::to_string_pretty(&self)?;
let mut file = File::create(path)?;
file.write_all(serialized.as_bytes())?;
Ok(())
}

pub fn get_node(&self, tip_distribution_account: &Pubkey) -> TreeNode {
Expand Down Expand Up @@ -241,7 +242,7 @@ mod tests {
let path = PathBuf::from("merkle_tree.json");

// serialize merkle distributor to file
merkle_distributor_info.write_to_file(&path);
merkle_distributor_info.write_to_file(&path).unwrap();
// now test we can successfully read from file
let merkle_distributor_read: MetaMerkleTree = MetaMerkleTree::new_from_file(&path).unwrap();

Expand Down
1 change: 0 additions & 1 deletion tip-router-operator-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ hex = "0.4"
im = "15.1"
itertools = "0.11"
jito-bytemuck = { workspace = true }
jito-restaking-program = { workspace = true }
jito-tip-distribution-sdk = { workspace = true }
jito-tip-payment-sdk = { workspace = true }
jito-tip-router-client = { workspace = true }
Expand Down
Loading

0 comments on commit d27f552

Please sign in to comment.