From f86dadc74a5b980f85e08322f751acb314b406ff Mon Sep 17 00:00:00 2001 From: dougefresh Date: Fri, 24 Oct 2025 11:17:57 +0000 Subject: [PATCH] feat: Add Send Sync to traits --- .github/workflows/check.yml | 15 +--- .../src/helpers.rs | 5 +- .../helpers/reclaim_event_account_helpers.rs | 4 +- examples/circle-cctp/Cargo.toml | 2 +- examples/circle-cctp/src/command.rs | 19 +++- examples/circle-cctp/src/main.rs | 86 +++++++++---------- 6 files changed, 66 insertions(+), 65 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 507d7ee..50d6a45 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -103,8 +103,7 @@ jobs: # https://doc.rust-lang.org/beta/unstable-book/language-features/doc-cfg.html which allows an # API be documented as only available in some specific platforms. # - - runs-on: ubuntu-latest + runs-on: ${{ vars.RUNNER }} name: doc steps: - uses: actions/checkout@v5 @@ -114,17 +113,11 @@ jobs: with: cache-on-failure: "true" cache-all-crates: "true" - cache-workspace-crates: "true" - workspaces: | - . -> target - # Specifies what to use as the backend providing cache - # Can be set to "github", "buildjet", or "warpbuild" - # default: "github" - cache-bin: "true" - name: Install rust uses: dtolnay/rust-toolchain@nightly - name: Install cargo-docs-rs - uses: dtolnay/install@cargo-docs-rs + run: | + cargo +nightly install cargo-docs-rs - name: cargo docs-rs run: | ./scripts/docsrs.sh @@ -191,4 +184,4 @@ jobs: TEST_PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} RPC_URL: ${{ secrets.RPC_URL }} run: | - cargo run -p circle-cctp -- bridge 0x626189bcDE2392ea088Ea0BD32336994CA9a0DCc + cargo run -p circle-cctp -- burn 0x626189bcDE2392ea088Ea0BD32336994CA9a0DCc diff --git a/encoders/circle-message-transmitter-v2-encoder/src/helpers.rs b/encoders/circle-message-transmitter-v2-encoder/src/helpers.rs index 414338a..da37286 100644 --- a/encoders/circle-message-transmitter-v2-encoder/src/helpers.rs +++ b/encoders/circle-message-transmitter-v2-encoder/src/helpers.rs @@ -1,6 +1,7 @@ use { crate::{accounts::MessageSent, types::ReclaimEventAccountParams}, solana_account::Account, + solana_client::nonblocking::rpc_client::RpcClient, solana_pubkey::Pubkey, solana_rpc_client_api::client_error::Result as ClientResult, std::{ @@ -13,7 +14,7 @@ pub const TOKEN_MINTER_PROGRAM_ID: Pubkey = solana_pubkey::pubkey!("CCTPV2vPZJS2u2BBsUoscuikbYjnpFmbFsvVuJdgUMQe"); #[async_trait::async_trait] -pub trait ReclaimAccountRpcState { +pub trait ReclaimAccountRpcState: Send + Sync { async fn get_reclaim_accounts(&self, owner: &Pubkey) -> ClientResult>; async fn get_reclaim_account_signature(&self, account: &Pubkey) -> ClientResult>; @@ -21,7 +22,7 @@ pub trait ReclaimAccountRpcState { /// The fee account is owned by Circle and is used to pay for CCTP fees. #[async_trait::async_trait] -pub trait FeeRecipientFetcher { +pub trait FeeRecipientFetcher: Send + Sync { async fn get_fee_recipient_token_account( &self, circle_usdc_address: &Pubkey, diff --git a/encoders/circle-message-transmitter-v2-encoder/src/helpers/reclaim_event_account_helpers.rs b/encoders/circle-message-transmitter-v2-encoder/src/helpers/reclaim_event_account_helpers.rs index 0bd8c98..465e73e 100644 --- a/encoders/circle-message-transmitter-v2-encoder/src/helpers/reclaim_event_account_helpers.rs +++ b/encoders/circle-message-transmitter-v2-encoder/src/helpers/reclaim_event_account_helpers.rs @@ -9,7 +9,6 @@ use { rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}, }, solana_pubkey::Pubkey, - solana_rpc_client::nonblocking::rpc_client::RpcClient, }; // https://github.com/circlefin/solana-cctp-contracts/blob/03f7dec786eb9affa68688954f62917edeed2e35/programs/v2/message-transmitter-v2/src/state.rs#L56 @@ -60,11 +59,14 @@ impl + Send + Sync> ReclaimAccountRpcState for T { } } +#[tracing::instrument(level = "info", skip(rpc))] pub async fn find_claimable_accounts( owner: &Pubkey, rpc: &T, ) -> ClientResult { + tracing::debug!("calling RPC for reclaim accounts"); let accounts = rpc.get_reclaim_accounts(owner).await?; + tracing::debug!("found {} accounts", accounts.len()); let mut claimable = ReclaimAccountStatus::new(*owner); let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) diff --git a/examples/circle-cctp/Cargo.toml b/examples/circle-cctp/Cargo.toml index e96e816..52ab52a 100644 --- a/examples/circle-cctp/Cargo.toml +++ b/examples/circle-cctp/Cargo.toml @@ -23,7 +23,7 @@ solana-rpc-client = { workspace = true } solana-rpc-client-api = { workspace = true } solana-signer = { workspace = true } solana-system-interface = { workspace = true } -soly = { git = "https://github.com/CarteraMesh/soly.git", branch = "main" } +soly = { version = "0.1.1-rc.1" } spl-memo = { workspace = true } spl-token = { workspace = true } tokio = { workspace = true, features = ["full"] } diff --git a/examples/circle-cctp/src/command.rs b/examples/circle-cctp/src/command.rs index c68fe86..c0f721a 100644 --- a/examples/circle-cctp/src/command.rs +++ b/examples/circle-cctp/src/command.rs @@ -1,4 +1,7 @@ -use clap::{Args, Parser, Subcommand}; +use { + clap::{Args, Parser, Subcommand}, + std::fmt::Debug, +}; #[derive(Parser)] #[command(name = "circle-cctp")] @@ -8,7 +11,7 @@ pub struct Cli { } #[derive(Args)] -pub struct BridgeArgs { +pub struct BurnArgs { #[arg(long, default_value = "10")] pub amount: u64, #[arg(long, default_value = "6")] @@ -18,9 +21,19 @@ pub struct BridgeArgs { pub destination: String, } +impl Debug for BurnArgs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "[amount={},dest={},chain={}]", + self.amount, self.destination, self.destination_chain + ) + } +} + #[derive(Subcommand)] pub enum Commands { - Bridge(BridgeArgs), + Burn(BurnArgs), Reclaim, Recv { tx_hash: String }, } diff --git a/examples/circle-cctp/src/main.rs b/examples/circle-cctp/src/main.rs index 94d5360..e94e3bd 100644 --- a/examples/circle-cctp/src/main.rs +++ b/examples/circle-cctp/src/main.rs @@ -1,13 +1,11 @@ use { - crate::command::BridgeArgs, + crate::command::BurnArgs, alloy_primitives::Address, anyhow::{Ok, Result}, clap::Parser, nitrogen_circle_message_transmitter_v2_encoder::{ ID as MESSAGE_TRANSMITTER_PROGRAM_ID, helpers::{receive_message_helpers, reclaim_event_account_helpers}, - instructions::reclaim_event_account, - types::ReclaimEventAccountParams, }, nitrogen_circle_token_messenger_minter_v2_encoder::{ ID as TOKEN_MINTER_PROGRAM_ID, @@ -25,8 +23,8 @@ use { BlockHashCacheProvider, LookupTableCacheProvider, SimpleCacheProvider, - SolanaRpcProvider, - TraceNativeProvider, + SolanaRpcProviderNative, + TraceRpcNativeProvider, TransactionBuilder, }, std::{env, time::Duration}, @@ -50,10 +48,7 @@ async fn fetch_attestation( attestation::get_attestation_with_retry(sig, chain).await } -async fn reclaim + Send + Sync>( - rpc: &T, - owner: Keypair, -) -> Result<()> { +async fn reclaim(rpc: &T, owner: Keypair) -> Result<()> { let reclaim_accounts = reclaim_event_account_helpers::find_claimable_accounts(&owner.pubkey(), rpc).await?; info!("reclaim accounts {reclaim_accounts}"); @@ -74,20 +69,9 @@ async fn reclaim + Send + Sync>( tracing::warn!("Skipping account with no signature"); continue; } - let sig = account.signature.unwrap_or_default(); + let sig = account.signature.clone().unwrap(); let (attest, message) = fetch_attestation(sig, None).await?; - let reclaim_account = reclaim_event_account( - ReclaimEventAccountParams::builder() - .attestation(attest) - .destination_message(message) - .build(), - ); - let reclaim_tx = TransactionBuilder::from( - reclaim_account - .accounts(owner.pubkey(), account.address) - .instruction(), - ); - + let reclaim_tx: TransactionBuilder = account.instruction((attest, message)).into(); let reclaim_tx = match (units, fee) { (Some(units), Some(fee)) => { reclaim_tx.prepend_compute_budget_instructions(units, fee)? @@ -155,12 +139,14 @@ fn get_keypair() -> Result { } #[allow(unused_variables)] -async fn evm_sol(args: BridgeArgs, owner: Keypair, rpc: TraceNativeProvider) -> Result<()> { +async fn evm_sol(args: BurnArgs, owner: Keypair, rpc: T) -> Result<()> { info!("TBD sending to sol"); Ok(()) } -async fn sol_evm(args: BridgeArgs, owner: Keypair, rpc: TraceNativeProvider) -> Result<()> { +async fn sol_evm(args: BurnArgs, owner: Keypair, rpc: T) -> Result<()> { + let span = tracing::info_span!("sol_evm", args =? args); + let _g = span.enter(); info!("burning..."); let message_sent_event_account = Keypair::new(); let evm_addr: Address = Address::parse_checksummed(args.destination, None)?; @@ -211,6 +197,30 @@ async fn sol_evm(args: BridgeArgs, owner: Keypair, rpc: TraceNativeProvider) -> Ok(()) } +fn cached_rpc(rpc: RpcClient) -> impl SolanaRpcProviderNative { + let rpc: TraceRpcNativeProvider = rpc.into(); + let hash_cache = BlockHashCacheProvider::new(rpc.clone(), Duration::from_secs(30)); + let lookup_cache = LookupTableCacheProvider::builder() + .inner(rpc.clone()) + .lookup_cache( + soly::Cache::builder() + .time_to_live(Duration::from_secs(86400)) + .build(), + ) + .negative_cache( + soly::Cache::builder() + .time_to_live(Duration::from_secs(600)) + .build(), + ) + .build(); + + SimpleCacheProvider::builder() + .inner(rpc.clone()) + .blockhash_cache(hash_cache.into()) + .lookup_cache(lookup_cache.into()) + .build() +} + #[allow(clippy::expect_fun_call)] #[tokio::main] pub async fn main() -> Result<()> { @@ -228,10 +238,12 @@ pub async fn main() -> Result<()> { let url = env::var("RPC_URL").expect("RPC_URL is not set"); info!("using RPC {url}"); - let rpc: TraceNativeProvider = - RpcClient::new_with_commitment(url, CommitmentConfig::finalized()).into(); + let rpc = cached_rpc(RpcClient::new_with_commitment( + url, + CommitmentConfig::finalized(), + )); match cli.command { - command::Commands::Bridge(args) => { + command::Commands::Burn(args) => { if !args.to_sol { sol_evm(args, owner, rpc).await } else { @@ -239,26 +251,6 @@ pub async fn main() -> Result<()> { } } command::Commands::Reclaim => { - let hash_cache = BlockHashCacheProvider::new(rpc.clone(), Duration::from_secs(30)); - let lookup_cache = LookupTableCacheProvider::builder() - .inner(rpc.clone()) - .lookup_cache( - soly::Cache::builder() - .time_to_live(Duration::from_secs(86400)) - .build(), - ) - .negative_cache( - soly::Cache::builder() - .time_to_live(Duration::from_secs(600)) - .build(), - ) - .build(); - - let rpc = SimpleCacheProvider::builder() - .inner(rpc.clone()) - .blockhash_cache(hash_cache.into()) - .lookup_cache(lookup_cache.into()) - .build(); reclaim(&rpc, owner).await?; Ok(()) }