Skip to content

Commit

Permalink
refactor: Move RpcConnection to a separate, thinner crate (#1199)
Browse files Browse the repository at this point in the history
The first step towards removing dependency on program crates in SDK,
clients and third-party program.

This change moves `RpcConnection` trait and `SolanaRpcConnection`
implementation away from `forester-utils` and makes sure it doesn't
contain any program crate as dependency.
  • Loading branch information
vadorovsky authored Sep 12, 2024
1 parent e2c2ab3 commit 2ae64ed
Show file tree
Hide file tree
Showing 51 changed files with 178 additions and 105 deletions.
23 changes: 21 additions & 2 deletions Cargo.lock

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

26 changes: 22 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ members = [
"programs/system",
"programs/compressed-token",
"programs/registry",
"client",
"sdk",
"test-utils",
"utils",
Expand All @@ -23,7 +24,7 @@ members = [
"forester-utils",
"forester",
"photon-api",
"sdk"]
]

[profile.release]
overflow-checks = true
Expand All @@ -32,6 +33,8 @@ overflow-checks = true
opt-level = 2

[workspace.dependencies]
# Solana
solana-banks-client = "=1.18.22"
solana-banks-interface = "=1.18.22"
solana-program = "=1.18.22"
solana-sdk = "=1.18.22"
Expand All @@ -41,19 +44,34 @@ solana-cli-output = "=1.18.22"
solana-transaction-status = "=1.18.22"
solana-account-decoder = "=1.18.22"
solana-rpc = "=1.18.22"
spl-token = "=4.0.0"

photon-api = { path = "photon-api" }

# Anchor
anchor-lang = "=0.29.0"
anchor-spl = "=0.29.0"

spl-token = "=4.0.0"
# Anchor compatibility
borsh = "0.10.0"

# Macro helpers
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = ["visit-mut", "full"] }

# Async ecosystem
tokio = { version = "1.39.1", features = ["rt", "macros", "rt-multi-thread"] }
async-trait = "0.1.82"
bb8 = "0.8.5"

# Logging
log = "0.4"

# Error handling
thiserror = "1.0"

# Light Protocol
light-client = { path = "client", version = "0.8.0" }
photon-api = { path = "photon-api" }

[patch.crates-io]
"solana-account-decoder" = { git = "https://github.com/lightprotocol/agave", branch = "v1.18.22-enforce-cpi-tracking" }
Expand Down
26 changes: 26 additions & 0 deletions client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "light-client"
version = "0.8.0"
edition = "2021"
license = "Apache-2.0"
repository = "https://github.com/lightprotocol/light-protocol"
description = "Client library for Light Protocol"

[dependencies]
# Solana
solana-banks-client = { workspace = true }
solana-client = { workspace = true }
solana-program = { workspace = true }
solana-sdk = { workspace = true }
solana-transaction-status = { workspace = true }

# Anchor compatibility
borsh = { workspace = true }

# Async ecosystem
tokio = { workspace = true }
async-trait = { workspace = true }
bb8 = { workspace = true }

log = { workspace = true }
thiserror = { workspace = true }
1 change: 1 addition & 0 deletions client/src/indexer/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub trait Indexer: Sync + Send + Debug + 'static {}
3 changes: 3 additions & 0 deletions client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod rpc;
pub mod rpc_pool;
pub mod transaction_params;
12 changes: 7 additions & 5 deletions forester-utils/src/rpc/errors.rs → client/src/rpc/errors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anchor_lang::solana_program::instruction::InstructionError;
use solana_banks_client::BanksClientError;
use solana_client::client_error::ClientError;
use solana_program_test::BanksClientError;
use solana_program::instruction::InstructionError;
use solana_sdk::transaction::TransactionError;
use std::io;
use thiserror::Error;
Expand All @@ -10,9 +10,6 @@ pub enum RpcError {
#[error("BanksError: {0}")]
BanksError(#[from] BanksClientError),

#[error("ProgramTestError: {0}")]
ProgramTestError(#[from] solana_program_test::ProgramTestError),

#[error("TransactionError: {0}")]
TransactionError(#[from] TransactionError),

Expand All @@ -24,8 +21,13 @@ pub enum RpcError {

#[error("Error: `{0}`")]
CustomError(String),

#[error("Assert Rpc Error: {0}")]
AssertRpcError(String),

/// The chosen warp slot is not in the future, so warp is not performed
#[error("Warp slot not in the future")]
InvalidWarpSlot,
}

pub fn assert_rpc_error<T>(
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::rpc::errors::RpcError;
use crate::transaction_params::TransactionParams;
use anchor_lang::solana_program::clock::Slot;
use anchor_lang::solana_program::instruction::Instruction;
use anchor_lang::AnchorDeserialize;
use async_trait::async_trait;
use borsh::BorshDeserialize;
use solana_program::clock::Slot;
use solana_program::instruction::Instruction;
use solana_sdk::account::{Account, AccountSharedData};
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::epoch_info::EpochInfo;
Expand Down Expand Up @@ -47,7 +47,7 @@ pub trait RpcConnection: Send + Sync + Debug + 'static {
transaction_params: Option<TransactionParams>,
) -> Result<Option<(T, Signature, Slot)>, RpcError>
where
T: AnchorDeserialize + Send + Debug;
T: BorshDeserialize + Send + Debug;

async fn create_and_send_transaction<'a>(
&'a mut self,
Expand All @@ -71,7 +71,7 @@ pub trait RpcConnection: Send + Sync + Debug + 'static {
async fn airdrop_lamports(&mut self, to: &Pubkey, lamports: u64)
-> Result<Signature, RpcError>;

async fn get_anchor_account<T: AnchorDeserialize>(
async fn get_anchor_account<T: BorshDeserialize>(
&mut self,
pubkey: &Pubkey,
) -> Result<Option<T>, RpcError> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
use crate::rpc::errors::RpcError;
use crate::rpc::rpc_connection::RpcConnection;
use crate::transaction_params::TransactionParams;
use anchor_lang::prelude::Pubkey;
use anchor_lang::solana_program::clock::Slot;
use anchor_lang::solana_program::hash::Hash;
use anchor_lang::AnchorDeserialize;
use async_trait::async_trait;
use borsh::BorshDeserialize;
use log::warn;
use solana_client::rpc_client::RpcClient;
use solana_client::rpc_config::{RpcSendTransactionConfig, RpcTransactionConfig};
use solana_program_test::BanksClientError;
use solana_program::clock::Slot;
use solana_program::hash::Hash;
use solana_program::pubkey::Pubkey;
use solana_sdk::account::{Account, AccountSharedData};
use solana_sdk::bs58;
use solana_sdk::clock::UnixTimestamp;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::epoch_info::EpochInfo;
use solana_sdk::instruction::{Instruction, InstructionError};
use solana_sdk::instruction::Instruction;
use solana_sdk::signature::{Keypair, Signature};
use solana_sdk::transaction::{Transaction, TransactionError};
use solana_sdk::transaction::Transaction;
use solana_transaction_status::option_serializer::OptionSerializer;
use solana_transaction_status::{UiInstruction, UiTransactionEncoding};
use std::fmt::{Debug, Display, Formatter};
Expand Down Expand Up @@ -125,7 +124,7 @@ impl SolanaRpcConnection {
}

impl SolanaRpcConnection {
fn parse_inner_instructions<T: AnchorDeserialize>(
fn parse_inner_instructions<T: BorshDeserialize>(
&self,
signature: Signature,
) -> Result<T, RpcError> {
Expand Down Expand Up @@ -271,7 +270,7 @@ impl RpcConnection for SolanaRpcConnection {
transaction_params: Option<TransactionParams>,
) -> Result<Option<(T, Signature, u64)>, RpcError>
where
T: AnchorDeserialize + Send + Debug,
T: BorshDeserialize + Send + Debug,
{
let pre_balance = self.client.get_balance(payer)?;
let latest_blockhash = self.client.get_latest_blockhash()?;
Expand Down Expand Up @@ -327,18 +326,7 @@ impl RpcConnection for SolanaRpcConnection {
- 5000 * deduped_signers.len() as i64
- network_fee;
if post_balance as i64 != expected_post_balance {
println!("transaction_params: {:?}", transaction_params);
println!("pre_balance: {}", pre_balance);
println!("post_balance: {}", post_balance);
println!("expected post_balance: {}", expected_post_balance);
println!(
"diff post_balance: {}",
post_balance as i64 - expected_post_balance
);
println!("network_fee: {}", network_fee);
return Err(RpcError::from(BanksClientError::TransactionError(
TransactionError::InstructionError(0, InstructionError::Custom(11111)),
)));
return Err(RpcError::AssertRpcError(format!("unexpected balance after transaction: expected {expected_post_balance}, got {post_balance}")));
}
}

Expand Down
4 changes: 2 additions & 2 deletions forester/src/rpc_pool.rs → client/src/rpc_pool.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::RpcConnection;
use bb8::{Pool, PooledConnection};
use forester_utils::rpc::RpcError;
use solana_sdk::commitment_config::CommitmentConfig;
use std::time::Duration;
use thiserror::Error;
use tokio::time::sleep;

use crate::rpc::{RpcConnection, RpcError};

#[derive(Error, Debug)]
pub enum PoolError {
#[error("Failed to create RPC client: {0}")]
Expand Down
File renamed without changes.
15 changes: 14 additions & 1 deletion forester-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ repository = "https://github.com/lightprotocol/light-protocol"
description = "Utility library for Light's Forester node implementation"

[dependencies]
# Light Protocol
account-compression = { path = "../programs/account-compression", version = "1.0.0", features = ["cpi"] }
light-compressed-token = { path = "../programs/compressed-token", version = "1.0.0", features = ["cpi"] }
light-hash-set = { path = "../merkle-tree/hash-set", version = "1.0.0" }
Expand All @@ -20,21 +21,33 @@ light-system-program = { path = "../programs/system", version = "1.0.0", feature
light-utils = { path = "../utils", version = "1.0.0" }

photon-api = { workspace = true }
light-client = { workspace = true }

# Anchor
anchor-lang = { workspace = true }
anchor-spl = { workspace = true }

# Solana
spl-token = { workspace = true, features = ["no-entrypoint"] }
solana-program-test = { workspace = true }
solana-sdk = { workspace = true }
solana-client = { workspace = true }
solana-transaction-status = { workspace = true }

# Async ecosystem
tokio = { workspace = true }
async-trait = { workspace = true }

# Error handling
thiserror = "1.0"

# Logging
log = "0.4"

# Big numbers
num-bigint = "0.4.6"
num-traits = "0.2.19"

# HTTP client
reqwest = "0.11.26"
async-trait = "0.1.82"

2 changes: 1 addition & 1 deletion forester-utils/src/address_merkle_tree_config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::rpc::RpcConnection;
use crate::{
get_concurrent_merkle_tree, get_hash_set, get_indexed_merkle_tree,
indexer::{AddressMerkleTreeAccounts, StateMerkleTreeAccounts},
Expand All @@ -8,6 +7,7 @@ use account_compression::{
AddressMerkleTreeAccount, AddressMerkleTreeConfig, AddressQueueConfig, NullifierQueueConfig,
QueueAccount, StateMerkleTreeAccount, StateMerkleTreeConfig,
};
use light_client::rpc::RpcConnection;
use light_hasher::Poseidon;
use num_traits::Zero;
use solana_sdk::pubkey::Pubkey;
Expand Down
2 changes: 1 addition & 1 deletion forester-utils/src/forester_epoch.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::fmt::Display;
// TODO: move into separate forester utils crate
use crate::rpc::{RpcConnection, RpcError};
use anchor_lang::{
prelude::borsh, solana_program::pubkey::Pubkey, AnchorDeserialize, AnchorSerialize,
};
use light_client::rpc::{RpcConnection, RpcError};
use light_registry::{
protocol_config::state::{EpochState, ProtocolConfig},
sdk::{create_register_forester_epoch_pda_instruction, create_report_work_instruction},
Expand Down
2 changes: 1 addition & 1 deletion forester-utils/src/indexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ use num_bigint::BigUint;
use solana_sdk::signature::Keypair;
use std::fmt::Debug;

use crate::rpc::RpcConnection;
use account_compression::initialize_address_merkle_tree::{
Error as AccountCompressionError, Pubkey,
};
use light_client::rpc::RpcConnection;
use light_compressed_token::TokenData;
use light_hash_set::HashSetError;
use light_hasher::Poseidon;
Expand Down
Loading

0 comments on commit 2ae64ed

Please sign in to comment.