From 4dc952e9f6f5a24034cb8742e13794071ee1cd9d Mon Sep 17 00:00:00 2001 From: Dodecahedr0x Date: Fri, 5 Jun 2026 14:49:57 +0200 Subject: [PATCH 1/7] feat: schedule automatic undelegation --- Cargo.lock | 2 + magicblock-api/Cargo.toml | 1 + magicblock-api/src/magic_validator.rs | 35 ++- magicblock-chainlink/Cargo.toml | 1 + magicblock-chainlink/src/chainlink/errors.rs | 5 + .../src/chainlink/fetch_cloner/mod.rs | 70 ++++- .../src/chainlink/fetch_cloner/tests.rs | 216 ++++++++++++++- magicblock-chainlink/src/chainlink/mod.rs | 7 +- .../tests/10_aml_undelegation.rs | 252 ++++++++++++++++++ .../tests/utils/test_context.rs | 14 +- .../src/committor_processor.rs | 89 ++++++- magicblock-committor-service/src/service.rs | 38 +++ .../src/service_ext.rs | 9 + .../src/stubs/changeset_committor_stub.rs | 41 ++- test-integration/Cargo.lock | 1 + 15 files changed, 766 insertions(+), 15 deletions(-) create mode 100644 magicblock-chainlink/tests/10_aml_undelegation.rs diff --git a/Cargo.lock b/Cargo.lock index 62ec469e9..1a8e0dd97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3770,6 +3770,7 @@ version = "0.12.0" dependencies = [ "agave-feature-set", "anyhow", + "async-trait", "borsh", "fd-lock", "magic-domain-program", @@ -3875,6 +3876,7 @@ dependencies = [ "solana-transaction-error 3.2.0", "spl-token-2022-interface", "spl-token-interface", + "tempfile", "thiserror 2.0.18", "tokio", "tokio-stream", diff --git a/magicblock-api/Cargo.toml b/magicblock-api/Cargo.toml index cdef84a27..d33762012 100644 --- a/magicblock-api/Cargo.toml +++ b/magicblock-api/Cargo.toml @@ -9,6 +9,7 @@ edition.workspace = true [dependencies] anyhow = { workspace = true } +async-trait = { workspace = true } borsh = "1.5.3" fd-lock = { workspace = true } tracing = { workspace = true } diff --git a/magicblock-api/src/magic_validator.rs b/magicblock-api/src/magic_validator.rs index 7515f2431..996f0646f 100644 --- a/magicblock-api/src/magic_validator.rs +++ b/magicblock-api/src/magic_validator.rs @@ -19,8 +19,10 @@ use magicblock_aperture::{ state::{NodeContext, SharedState}, }; use magicblock_chainlink::{ - config::ChainlinkConfig, remote_account_provider::Endpoints, ProdChainlink, - ProdInnerChainlink, + config::ChainlinkConfig, + fetch_cloner::{UndelegationScheduleRequest, UndelegationScheduler}, + remote_account_provider::Endpoints, + ProdChainlink, ProdInnerChainlink, }; use magicblock_committor_service::{ config::ChainConfig, BaseIntentCommittor, CommittorService, @@ -99,6 +101,29 @@ use crate::{ type InnerChainlinkImpl = ProdInnerChainlink; type ChainlinkImpl = ProdChainlink; +/// Bridges chainlink's [`UndelegationScheduler`] to the committor service so a +/// delegated clone rejected by AML is undelegated on the base layer. +struct CommittorUndelegationScheduler(Arc); + +#[async_trait::async_trait] +impl UndelegationScheduler for CommittorUndelegationScheduler { + async fn schedule_undelegation( + &self, + request: UndelegationScheduleRequest, + ) -> magicblock_chainlink::errors::ChainlinkResult<()> { + let pubkey = request.pubkey; + self.0 + .schedule_undelegation(pubkey, request.account) + .await + .map_err(|err| format!("committor response channel closed: {err}")) + .and_then(|result| result.map_err(|err| err.to_string())) + .map_err(|message| { + magicblock_chainlink::errors::ChainlinkError::FailedToScheduleUndelegationAfterAmlRejection( + pubkey, message, + ) + }) + } +} // ----------------- // MagicValidator @@ -238,6 +263,7 @@ impl MagicValidator { &ledger.latest_block().clone(), &accountsdb, shared_chain_slot.clone(), + committor_service.clone(), ) .await?, ); @@ -495,6 +521,7 @@ impl MagicValidator { latest_block: &LatestBlock, accountsdb: &Arc, chain_slot: Option>, + committor_service: Option>, ) -> ApiResult { if Self::replication_mode_uses_disabled_chainlink( &config.validator.replication_mode, @@ -550,6 +577,10 @@ impl MagicValidator { &config.chainlink, config.storage.as_path(), chain_slot.unwrap_or_default(), + committor_service.map(|committor_service| { + Arc::new(CommittorUndelegationScheduler(committor_service)) + as Arc + }), ) .await?; diff --git a/magicblock-chainlink/Cargo.toml b/magicblock-chainlink/Cargo.toml index 29f664fcf..ce757d365 100644 --- a/magicblock-chainlink/Cargo.toml +++ b/magicblock-chainlink/Cargo.toml @@ -58,6 +58,7 @@ url = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } magicblock-chainlink = { path = ".", features = ["dev-context"] } +tempfile = { workspace = true } [features] default = [] diff --git a/magicblock-chainlink/src/chainlink/errors.rs b/magicblock-chainlink/src/chainlink/errors.rs index 6370d9037..145bdfebf 100644 --- a/magicblock-chainlink/src/chainlink/errors.rs +++ b/magicblock-chainlink/src/chainlink/errors.rs @@ -67,6 +67,11 @@ pub enum ChainlinkError { #[error("Failed to perform Range risk check: {0}")] RangeRisk(#[from] RiskError), + #[error( + "Failed to schedule undelegation for {0} after AML rejection: {1}" + )] + FailedToScheduleUndelegationAfterAmlRejection(Pubkey, String), + #[error("Chainlink is disabled for non-primary mode")] DisabledForNonPrimaryMode, } diff --git a/magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs b/magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs index fe323029f..b0a336c53 100644 --- a/magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs +++ b/magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs @@ -8,6 +8,7 @@ use std::{ time::Duration, }; +use async_trait::async_trait; use dlp_api::{ pda::delegation_record_pda_from_delegated_account, state::DelegationRecord, }; @@ -85,6 +86,23 @@ use crate::{ }, }; +#[derive(Clone)] +pub struct UndelegationScheduleRequest { + pub pubkey: Pubkey, + pub account: AccountSharedData, +} + +/// Schedules an undelegation when a delegated clone is rejected by AML before +/// it enters the local bank. Implemented outside chainlink (e.g. by the API +/// layer bridging to the committor service) to keep chainlink decoupled. +#[async_trait] +pub trait UndelegationScheduler: Send + Sync { + async fn schedule_undelegation( + &self, + request: UndelegationScheduleRequest, + ) -> ChainlinkResult<()>; +} + pub struct FetchCloner where T: ChainRpcClient, @@ -138,6 +156,10 @@ where /// Risk checker for post-delegation action addresses. risk_service: Option>, + + /// Schedules undelegation when post-delegation action AML checks reject + /// a delegated clone before it enters the local bank. + undelegation_scheduler: Option>, } /// Negative-cache capacity for known-empty eATAs. @@ -177,6 +199,7 @@ where .pending_operation_timeout_ms .clone(), risk_service: self.risk_service.clone(), + undelegation_scheduler: self.undelegation_scheduler.clone(), } } } @@ -198,6 +221,7 @@ where subscription_updates_rx: mpsc::Receiver, allowed_programs: Option>, risk_service: Option>, + undelegation_scheduler: Option>, ) -> Arc { let validator_pubkey = validator_keypair.pubkey(); let blacklisted_accounts = blacklisted_accounts(&validator_pubkey); @@ -225,6 +249,7 @@ where FETCH_CLONE_OPERATION_TIMEOUT.as_millis() as u64, )), risk_service, + undelegation_scheduler, }); let accounts_bank_for_eviction = accounts_bank.clone(); @@ -510,16 +535,49 @@ where )); } - self.ensure_delegation_action_dependencies( - request.pubkey, - request.account.remote_slot(), - &request.delegation_actions, - ) - .await?; + if let Err(err) = self + .ensure_delegation_action_dependencies( + request.pubkey, + request.account.remote_slot(), + &request.delegation_actions, + ) + .await + { + if matches!( + err, + ChainlinkError::RangeRisk( + magicblock_aml::RiskError::HighRiskAddresses(_) + ) + ) { + self.schedule_undelegation_after_aml_rejection(&request) + .await?; + } + return Err(err); + } Ok(self.clone_account_with_ownership(request).await?) } + async fn schedule_undelegation_after_aml_rejection( + &self, + request: &AccountCloneRequest, + ) -> ChainlinkResult<()> { + let Some(scheduler) = self.undelegation_scheduler.as_ref() else { + warn!( + pubkey = %request.pubkey, + "AML rejected post-delegation actions but undelegation scheduler is unavailable" + ); + return Ok(()); + }; + + scheduler + .schedule_undelegation(UndelegationScheduleRequest { + pubkey: request.pubkey, + account: request.account.clone(), + }) + .await + } + fn normalize_unresolved_dlp_clone_request( &self, request: &mut AccountCloneRequest, diff --git a/magicblock-chainlink/src/chainlink/fetch_cloner/tests.rs b/magicblock-chainlink/src/chainlink/fetch_cloner/tests.rs index 434614157..7ed5027e6 100644 --- a/magicblock-chainlink/src/chainlink/fetch_cloner/tests.rs +++ b/magicblock-chainlink/src/chainlink/fetch_cloner/tests.rs @@ -1,6 +1,13 @@ -use std::{collections::HashMap, sync::Arc, time::Duration}; +use std::{ + collections::HashMap, + io::{Read, Write}, + net::TcpListener, + sync::{Arc, Mutex}, + time::Duration, +}; use dlp_api::state::DelegationRecord; +use magicblock_config::config::RiskConfig; use solana_account::{ Account, AccountSharedData, ReadableAccount, WritableAccount, }; @@ -203,6 +210,111 @@ where } } +#[derive(Default)] +struct RecordingUndelegationScheduler { + requests: Mutex>, +} + +impl RecordingUndelegationScheduler { + fn requests(&self) -> Vec { + self.requests.lock().unwrap().clone() + } +} + +#[async_trait::async_trait] +impl UndelegationScheduler for RecordingUndelegationScheduler { + async fn schedule_undelegation( + &self, + request: UndelegationScheduleRequest, + ) -> ChainlinkResult<()> { + self.requests.lock().unwrap().push(request); + Ok(()) + } +} + +struct MockRiskServer { + base_url: String, + worker: tokio::task::JoinHandle<()>, +} + +impl MockRiskServer { + async fn start( + address_scores: Vec<(String, u64)>, + expected_calls: usize, + ) -> Self { + let listener = + TcpListener::bind("127.0.0.1:0").expect("bind mock risk server"); + let addr = listener.local_addr().expect("mock risk server address"); + let score_by_address: HashMap = + address_scores.into_iter().collect(); + + let worker = tokio::task::spawn_blocking(move || { + for _ in 0..expected_calls { + let (mut stream, _) = + listener.accept().expect("accept mock risk request"); + stream + .set_read_timeout(Some(Duration::from_secs(2))) + .expect("set mock risk read timeout"); + + let mut buffer = [0u8; 4096]; + let read = stream.read(&mut buffer).expect("read request"); + let request = String::from_utf8_lossy(&buffer[..read]); + let address = extract_query_value(&request, "address") + .expect("missing address query"); + assert!(request.starts_with("GET /risk/address?")); + assert!(request.contains("network=solana")); + + let score = score_by_address + .get(&address) + .expect("unexpected risk address"); + let body = format!(r#"{{"riskScore":{score}}}"#); + let response = format!( + "HTTP/1.1 200 OK\r\ncontent-type: application/json\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{}", + body.len(), + body + ); + stream + .write_all(response.as_bytes()) + .expect("write mock risk response"); + } + }); + + Self { + base_url: format!("http://{addr}"), + worker, + } + } + + async fn join(self) { + self.worker.await.expect("mock risk server panicked"); + } +} + +fn extract_query_value(request: &str, key: &str) -> Option { + let query = request + .lines() + .next()? + .split_whitespace() + .nth(1)? + .split('?') + .nth(1)?; + query.split('&').find_map(|part| { + let (k, v) = part.split_once('=')?; + (k == key).then(|| v.to_string()) + }) +} + +fn make_risk_config(base_url: String) -> RiskConfig { + RiskConfig { + enabled: true, + base_url, + api_key: Some("test-api-key".to_string()), + cache_ttl: Duration::from_secs(60), + request_timeout: Duration::from_secs(2), + risk_score_threshold: 7, + } +} + fn insert_plain_ata_in_bank( accounts_bank: &Arc, ata_pubkey: Pubkey, @@ -292,6 +404,7 @@ fn init_fetch_cloner( subscription_rx, None, None, + None, ); (fetch_cloner, subscription_tx, cloner) } @@ -2434,6 +2547,7 @@ async fn test_allowed_programs_filters_programs() { subscription_rx, allowed_programs, None, + None, ); // Fetch and clone both programs @@ -2506,6 +2620,7 @@ async fn test_allowed_programs_none_allows_all() { subscription_rx, None, // No restriction None, + None, ); // Fetch and clone both programs @@ -2577,6 +2692,7 @@ async fn test_allowed_programs_empty_allows_all() { subscription_rx, allowed_programs, None, + None, ); // Fetch and clone both programs @@ -4278,6 +4394,98 @@ async fn test_post_delegation_actions_reject_non_delegated_clone_target() { ); } +#[tokio::test] +async fn test_post_delegation_action_aml_rejection_schedules_undelegation() { + init_logger(); + let validator_keypair = Keypair::new(); + const CURRENT_SLOT: u64 = 100; + + let FetcherTestCtx { + accounts_bank, + remote_account_provider, + .. + } = setup( + std::iter::empty::<(Pubkey, Account)>(), + CURRENT_SLOT, + validator_keypair.insecure_clone(), + ) + .await; + + let high_risk_signer = random_pubkey(); + let server = + MockRiskServer::start(vec![(high_risk_signer.to_string(), 9)], 1).await; + let temp_ledger = tempfile::tempdir().expect("temp ledger"); + let risk_service = RiskService::try_from_config( + &make_risk_config(server.base_url.clone()), + temp_ledger.path(), + ) + .expect("risk config should be valid") + .expect("risk service should be enabled"); + let risk_service = Arc::new(risk_service); + + let scheduler = Arc::new(RecordingUndelegationScheduler::default()); + let cloner = Arc::new(ClonerStub::new(accounts_bank.clone())); + let (_subscription_tx, subscription_rx) = mpsc::channel(100); + let fetch_cloner = FetchCloner::new( + &remote_account_provider, + &accounts_bank, + &cloner, + validator_keypair.insecure_clone(), + subscription_rx, + None, + Some(risk_service), + Some(scheduler.clone() as Arc), + ); + + let target_pubkey = random_pubkey(); + let mut target_account = AccountSharedData::from(Account { + lamports: 1_000_000, + data: vec![1, 2, 3, 4], + owner: system_program::id(), + executable: false, + rent_epoch: 0, + }); + target_account.set_remote_slot(CURRENT_SLOT); + target_account.set_delegated(true); + + let actions = DelegationActions::from(vec![Instruction::new_with_bytes( + system_program::id(), + &[1], + vec![AccountMeta::new_readonly(high_risk_signer, true)], + )]); + + let err = fetch_cloner + .clone_account_with_post_delegation_action_invariants( + AccountCloneRequest { + pubkey: target_pubkey, + account: target_account.clone(), + commit_frequency_ms: None, + delegation_actions: actions, + delegated_to_other: None, + }, + ) + .await + .expect_err("high-risk signer should reject the clone"); + + assert!(matches!( + err, + ChainlinkError::RangeRisk( + magicblock_aml::RiskError::HighRiskAddresses(_) + ) + )); + assert!( + cloner.clone_requests().is_empty(), + "AML-rejected action target must not be cloned" + ); + + let scheduled = scheduler.requests(); + assert_eq!(scheduled.len(), 1); + assert_eq!(scheduled[0].pubkey, target_pubkey); + assert_eq!(scheduled[0].account, target_account); + + server.join().await; +} + #[tokio::test] async fn test_dlp_owned_clone_without_actions_clears_stale_delegated_flag() { init_logger(); @@ -5275,6 +5483,7 @@ async fn test_fetch_subscription_race_duplicate_clone() { subscription_rx, None, None, + None, ); // Send subscription update (this will become the owner). @@ -5396,6 +5605,7 @@ async fn test_delegated_account_fetch_subscription_race() { subscription_rx, None, None, + None, ); // Send subscription update. @@ -5503,6 +5713,7 @@ async fn test_clone_ownership_failure_propagates_to_waiters() { subscription_rx, None, None, + None, ); // Send subscription update (becomes owner, will fail). @@ -6373,6 +6584,7 @@ async fn test_owned_operation_owner_timeout_cleans_up_pending() { subscription_rx, None, None, + None, ); fetch_cloner.set_pending_operation_timeout(TEST_PENDING_REQUEST_TIMEOUT); @@ -6478,6 +6690,7 @@ async fn test_cancel_pending_terminates_owner_and_all_waiters() { subscription_rx, None, None, + None, ); let owner_task = { @@ -6599,6 +6812,7 @@ async fn test_cancel_all_pending_on_shutdown() { subscription_rx, None, None, + None, ); let mut tasks = Vec::new(); diff --git a/magicblock-chainlink/src/chainlink/mod.rs b/magicblock-chainlink/src/chainlink/mod.rs index 37dd5084b..293bdc9dc 100644 --- a/magicblock-chainlink/src/chainlink/mod.rs +++ b/magicblock-chainlink/src/chainlink/mod.rs @@ -5,7 +5,7 @@ use std::{ use dlp_api::pda::ephemeral_balance_pda_from_payer; use errors::{ChainlinkError, ChainlinkResult}; -use fetch_cloner::FetchCloner; +use fetch_cloner::{FetchCloner, UndelegationScheduler}; use magicblock_accounts_db::{traits::AccountsBank, AccountsDb}; use magicblock_aml::RiskService; use magicblock_config::config::ChainLinkConfig; @@ -220,7 +220,8 @@ impl accounts_bank, cloner, config, - chainlink_config + chainlink_config, + undelegation_scheduler ))] pub async fn try_new_from_endpoints( endpoints: &Endpoints, @@ -232,6 +233,7 @@ impl chainlink_config: &ChainLinkConfig, ledger_path: &Path, chain_slot: Arc, + undelegation_scheduler: Option>, ) -> ChainlinkResult< InnerChainlink< ChainRpcClientImpl, @@ -266,6 +268,7 @@ impl rx, chainlink_config.allowed_programs.clone(), risk_service, + undelegation_scheduler, ); Some(fetch_cloner) } else { diff --git a/magicblock-chainlink/tests/10_aml_undelegation.rs b/magicblock-chainlink/tests/10_aml_undelegation.rs new file mode 100644 index 000000000..ece558da4 --- /dev/null +++ b/magicblock-chainlink/tests/10_aml_undelegation.rs @@ -0,0 +1,252 @@ +use std::{ + collections::HashMap, + io::{Read, Write}, + net::TcpListener, + sync::{Arc, Mutex}, + time::Duration, +}; + +use dlp_api::{ + args::{ + EncryptedBuffer, MaybeEncryptedAccountMeta, MaybeEncryptedInstruction, + MaybeEncryptedIxData, PostDelegationActions, + }, + pda::delegation_record_pda_from_delegated_account, + state::DelegationRecord, +}; +use magicblock_aml::RiskService; +use magicblock_chainlink::{ + chainlink::errors::ChainlinkResult, + fetch_cloner::{UndelegationScheduleRequest, UndelegationScheduler}, + testing::init_logger, +}; +use magicblock_config::config::RiskConfig; +use solana_account::{Account, ReadableAccount}; +use solana_pubkey::Pubkey; +use solana_sdk_ids::system_program; +use tokio::task::JoinHandle; +use utils::test_context::TestContext; + +mod utils; + +#[derive(Default)] +struct RecordingUndelegationScheduler { + requests: Mutex>, +} + +impl RecordingUndelegationScheduler { + fn requests(&self) -> Vec { + self.requests.lock().unwrap().clone() + } +} + +#[async_trait::async_trait] +impl UndelegationScheduler for RecordingUndelegationScheduler { + async fn schedule_undelegation( + &self, + request: UndelegationScheduleRequest, + ) -> ChainlinkResult<()> { + self.requests.lock().unwrap().push(request); + Ok(()) + } +} + +struct MockRiskServer { + base_url: String, + worker: JoinHandle<()>, +} + +impl MockRiskServer { + async fn start( + address_scores: Vec<(String, u64)>, + expected_calls: usize, + ) -> Self { + let listener = + TcpListener::bind("127.0.0.1:0").expect("bind mock risk server"); + let addr = listener.local_addr().expect("mock risk server address"); + let score_by_address: HashMap = + address_scores.into_iter().collect(); + + let worker = tokio::task::spawn_blocking(move || { + for _ in 0..expected_calls { + let (mut stream, _) = + listener.accept().expect("accept mock risk request"); + stream + .set_read_timeout(Some(Duration::from_secs(2))) + .expect("set mock risk read timeout"); + + let mut buffer = [0u8; 4096]; + let read = stream.read(&mut buffer).expect("read request"); + let request = String::from_utf8_lossy(&buffer[..read]); + let address = extract_query_value(&request, "address") + .expect("missing address query"); + assert!(request.starts_with("GET /risk/address?")); + assert!(request.contains("network=solana")); + + let score = score_by_address + .get(&address) + .expect("unexpected risk address"); + let body = format!(r#"{{"riskScore":{score}}}"#); + let response = format!( + "HTTP/1.1 200 OK\r\ncontent-type: application/json\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{}", + body.len(), + body + ); + stream + .write_all(response.as_bytes()) + .expect("write mock risk response"); + } + }); + + Self { + base_url: format!("http://{addr}"), + worker, + } + } + + async fn join(self) { + self.worker.await.expect("mock risk server panicked"); + } +} + +fn extract_query_value(request: &str, key: &str) -> Option { + let query = request + .lines() + .next()? + .split_whitespace() + .nth(1)? + .split('?') + .nth(1)?; + query.split('&').find_map(|part| { + let (k, v) = part.split_once('=')?; + (k == key).then(|| v.to_string()) + }) +} + +fn risk_config(base_url: String) -> RiskConfig { + RiskConfig { + enabled: true, + base_url, + api_key: Some("test-api-key".to_string()), + cache_ttl: Duration::from_secs(60), + request_timeout: Duration::from_secs(2), + risk_score_threshold: 7, + } +} + +fn add_delegation_record_with_signer_action( + ctx: &TestContext, + delegated_pubkey: Pubkey, + owner: Pubkey, + signer: Pubkey, +) { + let record = DelegationRecord { + authority: ctx.validator_pubkey, + owner, + delegation_slot: 1, + lamports: 1_000, + commit_frequency_ms: 2_000, + }; + let mut data = vec![0; DelegationRecord::size_with_discriminator()]; + record.to_bytes_with_discriminator(&mut data).unwrap(); + + let actions = PostDelegationActions { + inserted_signers: 0, + inserted_non_signers: 0, + signers: vec![*signer.as_array(), *system_program::id().as_array()], + non_signers: vec![], + instructions: vec![MaybeEncryptedInstruction { + program_id: 1, + accounts: vec![MaybeEncryptedAccountMeta::ClearText( + dlp_api::compact::AccountMeta::new_readonly(0, true), + )], + data: MaybeEncryptedIxData { + prefix: vec![1], + suffix: EncryptedBuffer::default(), + }, + }], + }; + data.extend_from_slice(&borsh::to_vec(&actions).unwrap()); + + ctx.rpc_client.add_account( + delegation_record_pda_from_delegated_account(&delegated_pubkey), + Account { + owner: dlp_api::id(), + data, + ..Default::default() + }, + ); +} + +#[tokio::test] +async fn post_delegation_aml_rejection_schedules_undelegation() { + init_logger(); + + let high_risk_signer = Pubkey::new_unique(); + let server = + MockRiskServer::start(vec![(high_risk_signer.to_string(), 9)], 1).await; + let temp_ledger = tempfile::tempdir().expect("temp ledger"); + let risk_service = RiskService::try_from_config( + &risk_config(server.base_url.clone()), + temp_ledger.path(), + ) + .expect("risk config should be valid") + .expect("risk service should be enabled"); + let risk_service = Arc::new(risk_service); + let scheduler = Arc::new(RecordingUndelegationScheduler::default()); + + let slot = 100; + let ctx = TestContext::init_with_services( + slot, + Some(risk_service), + Some(scheduler.clone() as Arc), + ) + .await; + + let delegated_pubkey = Pubkey::new_unique(); + let owner = system_program::id(); + ctx.rpc_client.add_account( + delegated_pubkey, + Account { + lamports: 1_000_000, + data: vec![1, 2, 3, 4], + owner: dlp_api::id(), + executable: false, + rent_epoch: 0, + }, + ); + add_delegation_record_with_signer_action( + &ctx, + delegated_pubkey, + owner, + high_risk_signer, + ); + + let err = ctx + .ensure_account(&delegated_pubkey) + .await + .expect_err("high-risk signer should reject the clone"); + + assert!( + matches!( + &err, + magicblock_chainlink::errors::ChainlinkError::PendingRequestOwnerFailed( + pubkey, + message, + ) if *pubkey == delegated_pubkey && message.contains("high risk") + ), + "unexpected error: {err:?}" + ); + assert!( + ctx.cloner.clone_requests().is_empty(), + "AML-rejected action target must not be cloned" + ); + + let scheduled = scheduler.requests(); + assert_eq!(scheduled.len(), 1); + assert_eq!(scheduled[0].pubkey, delegated_pubkey); + assert!(scheduled[0].account.delegated()); + assert_eq!(scheduled[0].account.owner(), &owner); + + server.join().await; +} diff --git a/magicblock-chainlink/tests/utils/test_context.rs b/magicblock-chainlink/tests/utils/test_context.rs index c78854c7f..bfcf4ddeb 100644 --- a/magicblock-chainlink/tests/utils/test_context.rs +++ b/magicblock-chainlink/tests/utils/test_context.rs @@ -5,10 +5,11 @@ use std::{ time::{Duration, Instant}, }; +use magicblock_aml::RiskService; use magicblock_chainlink::{ accounts_bank::mock::AccountsBankStub, errors::ChainlinkResult, - fetch_cloner::{FetchAndCloneResult, FetchCloner}, + fetch_cloner::{FetchAndCloneResult, FetchCloner, UndelegationScheduler}, remote_account_provider::{ chain_pubsub_client::{mock::ChainPubsubClientMock, ChainPubsubClient}, config::RemoteAccountProviderConfig, @@ -55,6 +56,14 @@ pub struct TestContext { impl TestContext { pub async fn init(slot: Slot) -> Self { + Self::init_with_services(slot, None, None).await + } + + pub async fn init_with_services( + slot: Slot, + risk_service: Option>, + undelegation_scheduler: Option>, + ) -> Self { let (rpc_client, pubsub_client) = { let rpc_client = ChainRpcClientMockBuilder::new().slot(slot).build(); @@ -102,7 +111,8 @@ impl TestContext { validator_keypair.insecure_clone(), rx, None, - None, + risk_service, + undelegation_scheduler, )), Some(provider), ) diff --git a/magicblock-committor-service/src/committor_processor.rs b/magicblock-committor-service/src/committor_processor.rs index 5061eb4b0..2649dd746 100644 --- a/magicblock-committor-service/src/committor_processor.rs +++ b/magicblock-committor-service/src/committor_processor.rs @@ -14,7 +14,7 @@ use magicblock_program::magic_scheduled_base_intent::{ }; use magicblock_rpc_client::MagicblockRpcClient; use magicblock_table_mania::{GarbageCollectorConfig, TableMania}; -use solana_account::Account; +use solana_account::{Account, AccountSharedData}; use solana_keypair::Keypair; use solana_pubkey::Pubkey; use solana_rpc_client::nonblocking::rpc_client::RpcClient; @@ -229,6 +229,18 @@ impl CommittorProcessor { Ok(()) } + #[instrument(skip(self, account))] + pub async fn schedule_undelegation( + &self, + pubkey: Pubkey, + account: AccountSharedData, + ) -> CommittorServiceResult<()> { + self.schedule_intent_bundle(vec![undelegation_intent_bundle( + pubkey, account, + )]) + .await + } + #[instrument(skip(self, intent_bundles))] pub async fn schedule_recovered_intent_bundles( &self, @@ -263,6 +275,69 @@ impl CommittorProcessor { } } +pub(crate) fn undelegation_intent_bundle( + pubkey: Pubkey, + account: AccountSharedData, +) -> ScheduledIntentBundle { + let committed_account = CommittedAccount::from((pubkey, account)); + let remote_slot = committed_account.remote_slot; + let intent_bundle = MagicIntentBundle { + commit_and_undelegate: Some(CommitAndUndelegate { + commit_action: CommitType::Standalone(vec![committed_account]), + undelegate_action: UndelegateType::Standalone, + }), + ..Default::default() + }; + + ScheduledIntentBundle { + id: intent_id(), + slot: remote_slot, + blockhash: Default::default(), + sent_transaction: Default::default(), + payer: Default::default(), + intent_bundle, + } +} + +fn intent_id() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_nanos() + .try_into() + .unwrap_or(u64::MAX) +} + +/// Shared assertion that `bundle` is a standalone commit-and-undelegate for a +/// single `(pubkey, owner, slot)` account. Used by the builder and stub tests. +#[cfg(test)] +pub(crate) fn assert_undelegation_bundle( + bundle: &ScheduledIntentBundle, + pubkey: Pubkey, + owner: Pubkey, + slot: u64, +) { + assert_eq!(bundle.slot, slot); + assert!(bundle.intent_bundle.commit.is_none()); + let commit_and_undelegate = bundle + .intent_bundle + .commit_and_undelegate + .as_ref() + .expect("commit-and-undelegate intent should be present"); + assert!(matches!( + commit_and_undelegate.undelegate_action, + UndelegateType::Standalone + )); + let CommitType::Standalone(accounts) = &commit_and_undelegate.commit_action + else { + panic!("commit action should be standalone"); + }; + assert_eq!(accounts.len(), 1); + assert_eq!(accounts[0].pubkey, pubkey); + assert_eq!(accounts[0].remote_slot, slot); + assert_eq!(accounts[0].account.owner, owner); +} + fn pending_rows_to_scheduled_intent_bundles( rows: Vec, payer: Pubkey, @@ -448,6 +523,18 @@ mod tests { row } + #[test] + fn undelegation_intent_bundle_builds_commit_and_undelegate() { + let pubkey = Pubkey::new_unique(); + let owner = Pubkey::new_unique(); + let mut account = AccountSharedData::new(1_000, 4, &owner); + account.set_remote_slot(42); + + let bundle = undelegation_intent_bundle(pubkey, account); + + assert_undelegation_bundle(&bundle, pubkey, owner, 42); + } + #[test] fn pending_rows_reconstruct_commit_finalize_bundle() { let payer = Pubkey::new_unique(); diff --git a/magicblock-committor-service/src/service.rs b/magicblock-committor-service/src/service.rs index b1415b8bc..21959db12 100644 --- a/magicblock-committor-service/src/service.rs +++ b/magicblock-committor-service/src/service.rs @@ -7,6 +7,7 @@ use std::{ use magicblock_core::traits::ActionsCallbackScheduler; use magicblock_program::magic_scheduled_base_intent::ScheduledIntentBundle; +use solana_account::AccountSharedData; use solana_keypair::Keypair; use solana_pubkey::Pubkey; use solana_signature::Signature; @@ -64,6 +65,11 @@ pub enum CommittorMessage { intent_bundles: Vec, respond_to: oneshot::Sender>, }, + ScheduleUndelegation { + pubkey: Pubkey, + account: AccountSharedData, + respond_to: oneshot::Sender>, + }, GetPendingIntentBundles { respond_to: oneshot::Sender>>, @@ -207,6 +213,17 @@ impl CommittorActor { error!(message_type = "ScheduleBaseIntents", error = ?e, "Failed to send response"); } } + ScheduleUndelegation { + pubkey, + account, + respond_to, + } => { + let result = + self.processor.schedule_undelegation(pubkey, account).await; + if let Err(e) = respond_to.send(result) { + error!(message_type = "ScheduleUndelegation", error = ?e, "Failed to send response"); + } + } GetPendingIntentBundles { respond_to } => { let pending_intents = self.processor.pending_intent_bundles().await; @@ -502,6 +519,20 @@ impl BaseIntentCommittor for CommittorService { rx } + fn schedule_undelegation( + &self, + pubkey: Pubkey, + account: AccountSharedData, + ) -> oneshot::Receiver> { + let (tx, rx) = oneshot::channel(); + self.try_send(CommittorMessage::ScheduleUndelegation { + pubkey, + account, + respond_to: tx, + }); + rx + } + fn get_commit_statuses( &self, message_id: u64, @@ -591,6 +622,13 @@ pub trait BaseIntentCommittor: Send + Sync + 'static { intent_bundles: Vec, ) -> oneshot::Receiver>; + /// Schedules commit-and-undelegate for a single delegated account. + fn schedule_undelegation( + &self, + pubkey: Pubkey, + account: AccountSharedData, + ) -> oneshot::Receiver>; + /// Subscribes for results of BaseIntent execution fn subscribe_for_results( &self, diff --git a/magicblock-committor-service/src/service_ext.rs b/magicblock-committor-service/src/service_ext.rs index 024d0423e..ea067da81 100644 --- a/magicblock-committor-service/src/service_ext.rs +++ b/magicblock-committor-service/src/service_ext.rs @@ -8,6 +8,7 @@ use std::{ use async_trait::async_trait; use futures_util::future::join_all; use magicblock_program::magic_scheduled_base_intent::ScheduledIntentBundle; +use solana_account::AccountSharedData; use solana_pubkey::Pubkey; use solana_signature::Signature; use solana_transaction_status_client_types::EncodedConfirmedTransactionWithStatusMeta; @@ -175,6 +176,14 @@ impl BaseIntentCommittor for CommittorServiceExt { self.inner.schedule_intent_bundles(intent_bundles) } + fn schedule_undelegation( + &self, + pubkey: Pubkey, + account: AccountSharedData, + ) -> oneshot::Receiver> { + self.inner.schedule_undelegation(pubkey, account) + } + fn subscribe_for_results( &self, ) -> oneshot::Receiver> diff --git a/magicblock-committor-service/src/stubs/changeset_committor_stub.rs b/magicblock-committor-service/src/stubs/changeset_committor_stub.rs index 0b417db47..2c63c7920 100644 --- a/magicblock-committor-service/src/stubs/changeset_committor_stub.rs +++ b/magicblock-committor-service/src/stubs/changeset_committor_stub.rs @@ -8,7 +8,7 @@ use async_trait::async_trait; use magicblock_program::magic_scheduled_base_intent::{ CommitType, ScheduledIntentBundle, UndelegateType, }; -use solana_account::Account; +use solana_account::{Account, AccountSharedData}; use solana_pubkey::Pubkey; use solana_signature::Signature; use solana_transaction_status_client_types::{ @@ -19,6 +19,7 @@ use tokio::sync::{broadcast, oneshot}; use tokio_util::sync::{CancellationToken, WaitForCancellationFutureOwned}; use crate::{ + committor_processor::undelegation_intent_bundle, error::CommittorServiceResult, intent_execution_manager::BroadcastedIntentExecutionResult, intent_executor::ExecutionOutput, @@ -100,6 +101,16 @@ impl BaseIntentCommittor for ChangesetCommittorStub { receiver } + fn schedule_undelegation( + &self, + pubkey: Pubkey, + account: AccountSharedData, + ) -> oneshot::Receiver> { + self.schedule_intent_bundles(vec![undelegation_intent_bundle( + pubkey, account, + )]) + } + fn subscribe_for_results( &self, ) -> oneshot::Receiver> @@ -297,3 +308,31 @@ fn now() -> u64 { .expect("Time went backwards") .as_secs() } + +#[cfg(test)] +mod tests { + use super::*; + use crate::committor_processor::assert_undelegation_bundle; + + #[tokio::test] + async fn schedule_undelegation_exposes_commit_and_undelegate_api() { + let committor = ChangesetCommittorStub::default(); + let pubkey = Pubkey::new_unique(); + let owner = Pubkey::new_unique(); + let mut account = AccountSharedData::new(1_000, 4, &owner); + account.set_remote_slot(42); + + committor + .schedule_undelegation(pubkey, account.clone()) + .await + .expect("committor response channel should be open") + .expect("undelegation should be scheduled"); + + assert_eq!(committor.len(), 1); + assert_eq!(committor.committed(&pubkey), Some(account.into())); + + let changesets = committor.committed_changesets.lock().unwrap(); + let intent = changesets.values().next().expect("scheduled intent"); + assert_undelegation_bundle(intent, pubkey, owner, 42); + } +} diff --git a/test-integration/Cargo.lock b/test-integration/Cargo.lock index d98545855..90bbfda5f 100644 --- a/test-integration/Cargo.lock +++ b/test-integration/Cargo.lock @@ -4318,6 +4318,7 @@ version = "0.12.0" dependencies = [ "agave-feature-set", "anyhow", + "async-trait", "borsh", "fd-lock", "magic-domain-program", From b817deb396b84561124f56e22c377c12922512ad Mon Sep 17 00:00:00 2001 From: Dodecahedr0x Date: Fri, 5 Jun 2026 15:22:11 +0200 Subject: [PATCH 2/7] fix: update lockfile --- test-integration/Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-integration/Cargo.lock b/test-integration/Cargo.lock index 90bbfda5f..07d2b22ac 100644 --- a/test-integration/Cargo.lock +++ b/test-integration/Cargo.lock @@ -4237,7 +4237,7 @@ dependencies = [ "flate2", "lmdb-rkv", "magicblock-config", - "magicblock-magic-program-api 0.11.4", + "magicblock-magic-program-api 0.12.0", "memmap2 0.9.9", "parking_lot", "reflink-copy", From 54e090539c9e3867e68eb419fa8fd7af46943944 Mon Sep 17 00:00:00 2001 From: Dodecahedr0x Date: Fri, 5 Jun 2026 15:24:55 +0200 Subject: [PATCH 3/7] style: lint --- test-integration/test-chainlink/src/ixtest_context.rs | 1 + test-integration/test-chainlink/src/test_context.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/test-integration/test-chainlink/src/ixtest_context.rs b/test-integration/test-chainlink/src/ixtest_context.rs index 76744f288..4f6c41b61 100644 --- a/test-integration/test-chainlink/src/ixtest_context.rs +++ b/test-integration/test-chainlink/src/ixtest_context.rs @@ -130,6 +130,7 @@ impl IxtestContext { rx, None, None, + None, )), Some(provider), ) diff --git a/test-integration/test-chainlink/src/test_context.rs b/test-integration/test-chainlink/src/test_context.rs index cd6485f94..4966a8d43 100644 --- a/test-integration/test-chainlink/src/test_context.rs +++ b/test-integration/test-chainlink/src/test_context.rs @@ -104,6 +104,7 @@ impl TestContext { rx, None, None, + None, )), Some(provider), ) From 5074224151971650df1c3579c0e062207702466a Mon Sep 17 00:00:00 2001 From: Dodecahedr0x Date: Mon, 8 Jun 2026 18:11:25 +0200 Subject: [PATCH 4/7] feat: schedule undelegation with clone --- Cargo.lock | 2 - magicblock-account-cloner/src/lib.rs | 28 ++- magicblock-api/Cargo.toml | 1 - magicblock-api/src/magic_validator.rs | 35 +-- magicblock-chainlink/Cargo.toml | 1 - magicblock-chainlink/src/chainlink/errors.rs | 5 - .../chainlink/fetch_cloner/ata_projection.rs | 2 + .../src/chainlink/fetch_cloner/mod.rs | 66 +----- .../src/chainlink/fetch_cloner/pipeline.rs | 2 + .../src/chainlink/fetch_cloner/tests.rs | 222 +----------------- magicblock-chainlink/src/chainlink/mod.rs | 5 +- magicblock-chainlink/src/cloner/errors.rs | 3 + magicblock-chainlink/src/cloner/mod.rs | 3 + .../tests/utils/test_context.rs | 6 +- .../src/committor_processor.rs | 89 +------ magicblock-committor-service/src/service.rs | 38 --- .../src/service_ext.rs | 9 - .../src/stubs/changeset_committor_stub.rs | 41 +--- .../magicblock/src/utils/instruction_utils.rs | 4 +- test-integration/Cargo.lock | 4 +- test-integration/Cargo.toml | 15 +- test-integration/test-chainlink/Cargo.toml | 8 +- .../test-chainlink/src/ixtest_context.rs | 2 +- .../test-chainlink/src/test_context.rs | 11 +- .../tests/ix_aml_undelegation.rs | 104 ++++---- 25 files changed, 127 insertions(+), 579 deletions(-) rename magicblock-chainlink/tests/10_aml_undelegation.rs => test-integration/test-chainlink/tests/ix_aml_undelegation.rs (72%) diff --git a/Cargo.lock b/Cargo.lock index 1a8e0dd97..62ec469e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3770,7 +3770,6 @@ version = "0.12.0" dependencies = [ "agave-feature-set", "anyhow", - "async-trait", "borsh", "fd-lock", "magic-domain-program", @@ -3876,7 +3875,6 @@ dependencies = [ "solana-transaction-error 3.2.0", "spl-token-2022-interface", "spl-token-interface", - "tempfile", "thiserror 2.0.18", "tokio", "tokio-stream", diff --git a/magicblock-account-cloner/src/lib.rs b/magicblock-account-cloner/src/lib.rs index a2dab89a8..1018ccdb2 100644 --- a/magicblock-account-cloner/src/lib.rs +++ b/magicblock-account-cloner/src/lib.rs @@ -214,6 +214,13 @@ impl ChainlinkCloner { InstructionUtils::set_program_authority_instruction(program, authority) } + fn schedule_undelegation_ix(pubkey: Pubkey) -> Instruction { + InstructionUtils::schedule_commit_and_undelegate_instruction( + &validator_authority_id(), + vec![pubkey], + ) + } + // ----------------- // Clone Fields Helper // ----------------- @@ -255,7 +262,9 @@ impl ChainlinkCloner { // To re-enable, uncomment the following and use `ixs` instead of `[clone_ix]`: // let ixs = self.maybe_add_crank_commits_ix(request, clone_ix); let mut ixs = vec![clone_ix]; - if !actions.is_empty() { + if request.needs_undelegation { + ixs.push(Self::schedule_undelegation_ix(request.pubkey)); + } else if !actions.is_empty() { ixs.push(Self::post_delegation_action_ix(request.pubkey, actions)); } @@ -321,7 +330,8 @@ impl ChainlinkCloner { let end = (offset + MAX_INLINE_DATA_SIZE).min(data.len()); let chunk = data[offset..end].to_vec(); let is_last = end == data.len(); - let final_without_actions = is_last && actions.is_empty(); + let final_without_actions = + is_last && actions.is_empty() && !request.needs_undelegation; let continue_ix = Self::clone_continue_ix( request.pubkey, @@ -334,7 +344,7 @@ impl ChainlinkCloner { offset = end; } - if !actions.is_empty() { + if request.needs_undelegation || !actions.is_empty() { let continue_ix = Self::clone_continue_ix( request.pubkey, data.len() as u32, @@ -342,11 +352,12 @@ impl ChainlinkCloner { true, actions.clone(), ); - let action_ix = - Self::post_delegation_action_ix(request.pubkey, actions); - txs.push( - self.create_signed_tx(&[continue_ix, action_ix], blockhash), - ); + let ix = if request.needs_undelegation { + Self::schedule_undelegation_ix(request.pubkey) + } else { + Self::post_delegation_action_ix(request.pubkey, actions) + }; + txs.push(self.create_signed_tx(&[continue_ix, ix], blockhash)); } txs @@ -740,6 +751,7 @@ mod tests { commit_frequency_ms: None, delegation_actions: DelegationActions::from(actions), delegated_to_other: None, + needs_undelegation: false, } } diff --git a/magicblock-api/Cargo.toml b/magicblock-api/Cargo.toml index d33762012..cdef84a27 100644 --- a/magicblock-api/Cargo.toml +++ b/magicblock-api/Cargo.toml @@ -9,7 +9,6 @@ edition.workspace = true [dependencies] anyhow = { workspace = true } -async-trait = { workspace = true } borsh = "1.5.3" fd-lock = { workspace = true } tracing = { workspace = true } diff --git a/magicblock-api/src/magic_validator.rs b/magicblock-api/src/magic_validator.rs index 996f0646f..7515f2431 100644 --- a/magicblock-api/src/magic_validator.rs +++ b/magicblock-api/src/magic_validator.rs @@ -19,10 +19,8 @@ use magicblock_aperture::{ state::{NodeContext, SharedState}, }; use magicblock_chainlink::{ - config::ChainlinkConfig, - fetch_cloner::{UndelegationScheduleRequest, UndelegationScheduler}, - remote_account_provider::Endpoints, - ProdChainlink, ProdInnerChainlink, + config::ChainlinkConfig, remote_account_provider::Endpoints, ProdChainlink, + ProdInnerChainlink, }; use magicblock_committor_service::{ config::ChainConfig, BaseIntentCommittor, CommittorService, @@ -101,29 +99,6 @@ use crate::{ type InnerChainlinkImpl = ProdInnerChainlink; type ChainlinkImpl = ProdChainlink; -/// Bridges chainlink's [`UndelegationScheduler`] to the committor service so a -/// delegated clone rejected by AML is undelegated on the base layer. -struct CommittorUndelegationScheduler(Arc); - -#[async_trait::async_trait] -impl UndelegationScheduler for CommittorUndelegationScheduler { - async fn schedule_undelegation( - &self, - request: UndelegationScheduleRequest, - ) -> magicblock_chainlink::errors::ChainlinkResult<()> { - let pubkey = request.pubkey; - self.0 - .schedule_undelegation(pubkey, request.account) - .await - .map_err(|err| format!("committor response channel closed: {err}")) - .and_then(|result| result.map_err(|err| err.to_string())) - .map_err(|message| { - magicblock_chainlink::errors::ChainlinkError::FailedToScheduleUndelegationAfterAmlRejection( - pubkey, message, - ) - }) - } -} // ----------------- // MagicValidator @@ -263,7 +238,6 @@ impl MagicValidator { &ledger.latest_block().clone(), &accountsdb, shared_chain_slot.clone(), - committor_service.clone(), ) .await?, ); @@ -521,7 +495,6 @@ impl MagicValidator { latest_block: &LatestBlock, accountsdb: &Arc, chain_slot: Option>, - committor_service: Option>, ) -> ApiResult { if Self::replication_mode_uses_disabled_chainlink( &config.validator.replication_mode, @@ -577,10 +550,6 @@ impl MagicValidator { &config.chainlink, config.storage.as_path(), chain_slot.unwrap_or_default(), - committor_service.map(|committor_service| { - Arc::new(CommittorUndelegationScheduler(committor_service)) - as Arc - }), ) .await?; diff --git a/magicblock-chainlink/Cargo.toml b/magicblock-chainlink/Cargo.toml index ce757d365..29f664fcf 100644 --- a/magicblock-chainlink/Cargo.toml +++ b/magicblock-chainlink/Cargo.toml @@ -58,7 +58,6 @@ url = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } magicblock-chainlink = { path = ".", features = ["dev-context"] } -tempfile = { workspace = true } [features] default = [] diff --git a/magicblock-chainlink/src/chainlink/errors.rs b/magicblock-chainlink/src/chainlink/errors.rs index 145bdfebf..6370d9037 100644 --- a/magicblock-chainlink/src/chainlink/errors.rs +++ b/magicblock-chainlink/src/chainlink/errors.rs @@ -67,11 +67,6 @@ pub enum ChainlinkError { #[error("Failed to perform Range risk check: {0}")] RangeRisk(#[from] RiskError), - #[error( - "Failed to schedule undelegation for {0} after AML rejection: {1}" - )] - FailedToScheduleUndelegationAfterAmlRejection(Pubkey, String), - #[error("Chainlink is disabled for non-primary mode")] DisabledForNonPrimaryMode, } diff --git a/magicblock-chainlink/src/chainlink/fetch_cloner/ata_projection.rs b/magicblock-chainlink/src/chainlink/fetch_cloner/ata_projection.rs index 743cb6cde..f65e16a77 100644 --- a/magicblock-chainlink/src/chainlink/fetch_cloner/ata_projection.rs +++ b/magicblock-chainlink/src/chainlink/fetch_cloner/ata_projection.rs @@ -217,6 +217,7 @@ where commit_frequency_ms: None, delegation_actions: delegation_actions.clone(), delegated_to_other: None, + needs_undelegation: false, }) } @@ -593,6 +594,7 @@ where commit_frequency_ms, delegation_actions: actions.unwrap_or_default(), delegated_to_other, + needs_undelegation: false, }); } diff --git a/magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs b/magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs index b0a336c53..f1c90290e 100644 --- a/magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs +++ b/magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs @@ -8,7 +8,6 @@ use std::{ time::Duration, }; -use async_trait::async_trait; use dlp_api::{ pda::delegation_record_pda_from_delegated_account, state::DelegationRecord, }; @@ -86,23 +85,6 @@ use crate::{ }, }; -#[derive(Clone)] -pub struct UndelegationScheduleRequest { - pub pubkey: Pubkey, - pub account: AccountSharedData, -} - -/// Schedules an undelegation when a delegated clone is rejected by AML before -/// it enters the local bank. Implemented outside chainlink (e.g. by the API -/// layer bridging to the committor service) to keep chainlink decoupled. -#[async_trait] -pub trait UndelegationScheduler: Send + Sync { - async fn schedule_undelegation( - &self, - request: UndelegationScheduleRequest, - ) -> ChainlinkResult<()>; -} - pub struct FetchCloner where T: ChainRpcClient, @@ -156,10 +138,6 @@ where /// Risk checker for post-delegation action addresses. risk_service: Option>, - - /// Schedules undelegation when post-delegation action AML checks reject - /// a delegated clone before it enters the local bank. - undelegation_scheduler: Option>, } /// Negative-cache capacity for known-empty eATAs. @@ -199,7 +177,6 @@ where .pending_operation_timeout_ms .clone(), risk_service: self.risk_service.clone(), - undelegation_scheduler: self.undelegation_scheduler.clone(), } } } @@ -221,7 +198,6 @@ where subscription_updates_rx: mpsc::Receiver, allowed_programs: Option>, risk_service: Option>, - undelegation_scheduler: Option>, ) -> Arc { let validator_pubkey = validator_keypair.pubkey(); let blacklisted_accounts = blacklisted_accounts(&validator_pubkey); @@ -249,7 +225,6 @@ where FETCH_CLONE_OPERATION_TIMEOUT.as_millis() as u64, )), risk_service, - undelegation_scheduler, }); let accounts_bank_for_eviction = accounts_bank.clone(); @@ -535,7 +510,7 @@ where )); } - if let Err(err) = self + match self .ensure_delegation_action_dependencies( request.pubkey, request.account.remote_slot(), @@ -543,41 +518,20 @@ where ) .await { - if matches!( - err, - ChainlinkError::RangeRisk( - magicblock_aml::RiskError::HighRiskAddresses(_) - ) - ) { - self.schedule_undelegation_after_aml_rejection(&request) - .await?; + Ok(()) => {} + Err(ChainlinkError::RangeRisk( + magicblock_aml::RiskError::HighRiskAddresses(_), + )) => { + request.needs_undelegation = true; + } + Err(err) => { + return Err(err); } - return Err(err); } Ok(self.clone_account_with_ownership(request).await?) } - async fn schedule_undelegation_after_aml_rejection( - &self, - request: &AccountCloneRequest, - ) -> ChainlinkResult<()> { - let Some(scheduler) = self.undelegation_scheduler.as_ref() else { - warn!( - pubkey = %request.pubkey, - "AML rejected post-delegation actions but undelegation scheduler is unavailable" - ); - return Ok(()); - }; - - scheduler - .schedule_undelegation(UndelegationScheduleRequest { - pubkey: request.pubkey, - account: request.account.clone(), - }) - .await - } - fn normalize_unresolved_dlp_clone_request( &self, request: &mut AccountCloneRequest, @@ -898,6 +852,7 @@ where commit_frequency_ms, delegation_actions: raw_delegation_actions, delegated_to_other, + needs_undelegation: false, }, ) .await @@ -2607,6 +2562,7 @@ where commit_frequency_ms: None, delegation_actions: DelegationActions::default(), delegated_to_other: None, + needs_undelegation: false, }) .await?; Ok(()) diff --git a/magicblock-chainlink/src/chainlink/fetch_cloner/pipeline.rs b/magicblock-chainlink/src/chainlink/fetch_cloner/pipeline.rs index cfd563ac2..a704d360d 100644 --- a/magicblock-chainlink/src/chainlink/fetch_cloner/pipeline.rs +++ b/magicblock-chainlink/src/chainlink/fetch_cloner/pipeline.rs @@ -134,6 +134,7 @@ fn classify_single_account( commit_frequency_ms: None, delegation_actions: DelegationActions::default(), delegated_to_other: None, + needs_undelegation: false, }); } } @@ -378,6 +379,7 @@ where commit_frequency_ms, delegation_actions, delegated_to_other, + needs_undelegation: false, }); if cleanup_delegated_subscription { if cleanup_undelegation_tracking { diff --git a/magicblock-chainlink/src/chainlink/fetch_cloner/tests.rs b/magicblock-chainlink/src/chainlink/fetch_cloner/tests.rs index 7ed5027e6..d0c7f3d91 100644 --- a/magicblock-chainlink/src/chainlink/fetch_cloner/tests.rs +++ b/magicblock-chainlink/src/chainlink/fetch_cloner/tests.rs @@ -1,13 +1,6 @@ -use std::{ - collections::HashMap, - io::{Read, Write}, - net::TcpListener, - sync::{Arc, Mutex}, - time::Duration, -}; +use std::{collections::HashMap, sync::Arc, time::Duration}; use dlp_api::state::DelegationRecord; -use magicblock_config::config::RiskConfig; use solana_account::{ Account, AccountSharedData, ReadableAccount, WritableAccount, }; @@ -210,111 +203,6 @@ where } } -#[derive(Default)] -struct RecordingUndelegationScheduler { - requests: Mutex>, -} - -impl RecordingUndelegationScheduler { - fn requests(&self) -> Vec { - self.requests.lock().unwrap().clone() - } -} - -#[async_trait::async_trait] -impl UndelegationScheduler for RecordingUndelegationScheduler { - async fn schedule_undelegation( - &self, - request: UndelegationScheduleRequest, - ) -> ChainlinkResult<()> { - self.requests.lock().unwrap().push(request); - Ok(()) - } -} - -struct MockRiskServer { - base_url: String, - worker: tokio::task::JoinHandle<()>, -} - -impl MockRiskServer { - async fn start( - address_scores: Vec<(String, u64)>, - expected_calls: usize, - ) -> Self { - let listener = - TcpListener::bind("127.0.0.1:0").expect("bind mock risk server"); - let addr = listener.local_addr().expect("mock risk server address"); - let score_by_address: HashMap = - address_scores.into_iter().collect(); - - let worker = tokio::task::spawn_blocking(move || { - for _ in 0..expected_calls { - let (mut stream, _) = - listener.accept().expect("accept mock risk request"); - stream - .set_read_timeout(Some(Duration::from_secs(2))) - .expect("set mock risk read timeout"); - - let mut buffer = [0u8; 4096]; - let read = stream.read(&mut buffer).expect("read request"); - let request = String::from_utf8_lossy(&buffer[..read]); - let address = extract_query_value(&request, "address") - .expect("missing address query"); - assert!(request.starts_with("GET /risk/address?")); - assert!(request.contains("network=solana")); - - let score = score_by_address - .get(&address) - .expect("unexpected risk address"); - let body = format!(r#"{{"riskScore":{score}}}"#); - let response = format!( - "HTTP/1.1 200 OK\r\ncontent-type: application/json\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{}", - body.len(), - body - ); - stream - .write_all(response.as_bytes()) - .expect("write mock risk response"); - } - }); - - Self { - base_url: format!("http://{addr}"), - worker, - } - } - - async fn join(self) { - self.worker.await.expect("mock risk server panicked"); - } -} - -fn extract_query_value(request: &str, key: &str) -> Option { - let query = request - .lines() - .next()? - .split_whitespace() - .nth(1)? - .split('?') - .nth(1)?; - query.split('&').find_map(|part| { - let (k, v) = part.split_once('=')?; - (k == key).then(|| v.to_string()) - }) -} - -fn make_risk_config(base_url: String) -> RiskConfig { - RiskConfig { - enabled: true, - base_url, - api_key: Some("test-api-key".to_string()), - cache_ttl: Duration::from_secs(60), - request_timeout: Duration::from_secs(2), - risk_score_threshold: 7, - } -} - fn insert_plain_ata_in_bank( accounts_bank: &Arc, ata_pubkey: Pubkey, @@ -404,7 +292,6 @@ fn init_fetch_cloner( subscription_rx, None, None, - None, ); (fetch_cloner, subscription_tx, cloner) } @@ -2547,7 +2434,6 @@ async fn test_allowed_programs_filters_programs() { subscription_rx, allowed_programs, None, - None, ); // Fetch and clone both programs @@ -2620,7 +2506,6 @@ async fn test_allowed_programs_none_allows_all() { subscription_rx, None, // No restriction None, - None, ); // Fetch and clone both programs @@ -2692,7 +2577,6 @@ async fn test_allowed_programs_empty_allows_all() { subscription_rx, allowed_programs, None, - None, ); // Fetch and clone both programs @@ -4380,6 +4264,7 @@ async fn test_post_delegation_actions_reject_non_delegated_clone_target() { commit_frequency_ms: None, delegation_actions: actions, delegated_to_other: None, + needs_undelegation: false, }, ) .await @@ -4394,98 +4279,6 @@ async fn test_post_delegation_actions_reject_non_delegated_clone_target() { ); } -#[tokio::test] -async fn test_post_delegation_action_aml_rejection_schedules_undelegation() { - init_logger(); - let validator_keypair = Keypair::new(); - const CURRENT_SLOT: u64 = 100; - - let FetcherTestCtx { - accounts_bank, - remote_account_provider, - .. - } = setup( - std::iter::empty::<(Pubkey, Account)>(), - CURRENT_SLOT, - validator_keypair.insecure_clone(), - ) - .await; - - let high_risk_signer = random_pubkey(); - let server = - MockRiskServer::start(vec![(high_risk_signer.to_string(), 9)], 1).await; - let temp_ledger = tempfile::tempdir().expect("temp ledger"); - let risk_service = RiskService::try_from_config( - &make_risk_config(server.base_url.clone()), - temp_ledger.path(), - ) - .expect("risk config should be valid") - .expect("risk service should be enabled"); - let risk_service = Arc::new(risk_service); - - let scheduler = Arc::new(RecordingUndelegationScheduler::default()); - let cloner = Arc::new(ClonerStub::new(accounts_bank.clone())); - let (_subscription_tx, subscription_rx) = mpsc::channel(100); - let fetch_cloner = FetchCloner::new( - &remote_account_provider, - &accounts_bank, - &cloner, - validator_keypair.insecure_clone(), - subscription_rx, - None, - Some(risk_service), - Some(scheduler.clone() as Arc), - ); - - let target_pubkey = random_pubkey(); - let mut target_account = AccountSharedData::from(Account { - lamports: 1_000_000, - data: vec![1, 2, 3, 4], - owner: system_program::id(), - executable: false, - rent_epoch: 0, - }); - target_account.set_remote_slot(CURRENT_SLOT); - target_account.set_delegated(true); - - let actions = DelegationActions::from(vec![Instruction::new_with_bytes( - system_program::id(), - &[1], - vec![AccountMeta::new_readonly(high_risk_signer, true)], - )]); - - let err = fetch_cloner - .clone_account_with_post_delegation_action_invariants( - AccountCloneRequest { - pubkey: target_pubkey, - account: target_account.clone(), - commit_frequency_ms: None, - delegation_actions: actions, - delegated_to_other: None, - }, - ) - .await - .expect_err("high-risk signer should reject the clone"); - - assert!(matches!( - err, - ChainlinkError::RangeRisk( - magicblock_aml::RiskError::HighRiskAddresses(_) - ) - )); - assert!( - cloner.clone_requests().is_empty(), - "AML-rejected action target must not be cloned" - ); - - let scheduled = scheduler.requests(); - assert_eq!(scheduled.len(), 1); - assert_eq!(scheduled[0].pubkey, target_pubkey); - assert_eq!(scheduled[0].account, target_account); - - server.join().await; -} - #[tokio::test] async fn test_dlp_owned_clone_without_actions_clears_stale_delegated_flag() { init_logger(); @@ -4523,6 +4316,7 @@ async fn test_dlp_owned_clone_without_actions_clears_stale_delegated_flag() { commit_frequency_ms: None, delegation_actions: DelegationActions::default(), delegated_to_other: None, + needs_undelegation: false, }, ) .await @@ -4574,6 +4368,7 @@ async fn test_dlp_owned_magic_fee_vault_without_actions_remains_delegated() { commit_frequency_ms: None, delegation_actions: DelegationActions::default(), delegated_to_other: None, + needs_undelegation: false, }, ) .await @@ -4661,6 +4456,7 @@ async fn test_post_delegation_actions_refresh_writable_dependency_before_target( commit_frequency_ms: None, delegation_actions: actions, delegated_to_other: None, + needs_undelegation: false, }, ) .await @@ -4736,6 +4532,7 @@ async fn test_post_delegation_actions_execute_once_across_remote_slots() { commit_frequency_ms: None, delegation_actions: actions.clone(), delegated_to_other: None, + needs_undelegation: false, }, ) .await @@ -4806,6 +4603,7 @@ async fn test_delegated_clone_does_not_override_active_local_target() { commit_frequency_ms: None, delegation_actions: DelegationActions::default(), delegated_to_other: None, + needs_undelegation: false, }, ) .await @@ -5483,7 +5281,6 @@ async fn test_fetch_subscription_race_duplicate_clone() { subscription_rx, None, None, - None, ); // Send subscription update (this will become the owner). @@ -5605,7 +5402,6 @@ async fn test_delegated_account_fetch_subscription_race() { subscription_rx, None, None, - None, ); // Send subscription update. @@ -5713,7 +5509,6 @@ async fn test_clone_ownership_failure_propagates_to_waiters() { subscription_rx, None, None, - None, ); // Send subscription update (becomes owner, will fail). @@ -6584,7 +6379,6 @@ async fn test_owned_operation_owner_timeout_cleans_up_pending() { subscription_rx, None, None, - None, ); fetch_cloner.set_pending_operation_timeout(TEST_PENDING_REQUEST_TIMEOUT); @@ -6690,7 +6484,6 @@ async fn test_cancel_pending_terminates_owner_and_all_waiters() { subscription_rx, None, None, - None, ); let owner_task = { @@ -6812,7 +6605,6 @@ async fn test_cancel_all_pending_on_shutdown() { subscription_rx, None, None, - None, ); let mut tasks = Vec::new(); diff --git a/magicblock-chainlink/src/chainlink/mod.rs b/magicblock-chainlink/src/chainlink/mod.rs index 293bdc9dc..549b0a2a9 100644 --- a/magicblock-chainlink/src/chainlink/mod.rs +++ b/magicblock-chainlink/src/chainlink/mod.rs @@ -5,7 +5,7 @@ use std::{ use dlp_api::pda::ephemeral_balance_pda_from_payer; use errors::{ChainlinkError, ChainlinkResult}; -use fetch_cloner::{FetchCloner, UndelegationScheduler}; +use fetch_cloner::FetchCloner; use magicblock_accounts_db::{traits::AccountsBank, AccountsDb}; use magicblock_aml::RiskService; use magicblock_config::config::ChainLinkConfig; @@ -221,7 +221,6 @@ impl cloner, config, chainlink_config, - undelegation_scheduler ))] pub async fn try_new_from_endpoints( endpoints: &Endpoints, @@ -233,7 +232,6 @@ impl chainlink_config: &ChainLinkConfig, ledger_path: &Path, chain_slot: Arc, - undelegation_scheduler: Option>, ) -> ChainlinkResult< InnerChainlink< ChainRpcClientImpl, @@ -268,7 +266,6 @@ impl rx, chainlink_config.allowed_programs.clone(), risk_service, - undelegation_scheduler, ); Some(fetch_cloner) } else { diff --git a/magicblock-chainlink/src/cloner/errors.rs b/magicblock-chainlink/src/cloner/errors.rs index 8959755bd..d3bcd79f5 100644 --- a/magicblock-chainlink/src/cloner/errors.rs +++ b/magicblock-chainlink/src/cloner/errors.rs @@ -40,4 +40,7 @@ pub enum ClonerError { #[error("Failed to evict account {0} : {1:?}")] FailedToEvictAccount(Pubkey, Box), + + #[error("Failed to schedule undelegation {0} : {1:?}")] + FailedToScheduleUndelegation(Pubkey, Box), } diff --git a/magicblock-chainlink/src/cloner/mod.rs b/magicblock-chainlink/src/cloner/mod.rs index 9e7fa74a5..0aed61a74 100644 --- a/magicblock-chainlink/src/cloner/mod.rs +++ b/magicblock-chainlink/src/cloner/mod.rs @@ -59,6 +59,9 @@ pub struct AccountCloneRequest { /// this contains that validator's pubkey. None if account is not /// delegated to another validator. pub delegated_to_other: Option, + /// Account that need to be undelegated (e.g. due to AML risk) after cloning. + /// Is only true if there are actions with risky signers. + pub needs_undelegation: bool, } #[async_trait] diff --git a/magicblock-chainlink/tests/utils/test_context.rs b/magicblock-chainlink/tests/utils/test_context.rs index bfcf4ddeb..95d2afbf4 100644 --- a/magicblock-chainlink/tests/utils/test_context.rs +++ b/magicblock-chainlink/tests/utils/test_context.rs @@ -9,7 +9,7 @@ use magicblock_aml::RiskService; use magicblock_chainlink::{ accounts_bank::mock::AccountsBankStub, errors::ChainlinkResult, - fetch_cloner::{FetchAndCloneResult, FetchCloner, UndelegationScheduler}, + fetch_cloner::{FetchAndCloneResult, FetchCloner}, remote_account_provider::{ chain_pubsub_client::{mock::ChainPubsubClientMock, ChainPubsubClient}, config::RemoteAccountProviderConfig, @@ -56,13 +56,12 @@ pub struct TestContext { impl TestContext { pub async fn init(slot: Slot) -> Self { - Self::init_with_services(slot, None, None).await + Self::init_with_services(slot, None).await } pub async fn init_with_services( slot: Slot, risk_service: Option>, - undelegation_scheduler: Option>, ) -> Self { let (rpc_client, pubsub_client) = { let rpc_client = @@ -112,7 +111,6 @@ impl TestContext { rx, None, risk_service, - undelegation_scheduler, )), Some(provider), ) diff --git a/magicblock-committor-service/src/committor_processor.rs b/magicblock-committor-service/src/committor_processor.rs index 2649dd746..5061eb4b0 100644 --- a/magicblock-committor-service/src/committor_processor.rs +++ b/magicblock-committor-service/src/committor_processor.rs @@ -14,7 +14,7 @@ use magicblock_program::magic_scheduled_base_intent::{ }; use magicblock_rpc_client::MagicblockRpcClient; use magicblock_table_mania::{GarbageCollectorConfig, TableMania}; -use solana_account::{Account, AccountSharedData}; +use solana_account::Account; use solana_keypair::Keypair; use solana_pubkey::Pubkey; use solana_rpc_client::nonblocking::rpc_client::RpcClient; @@ -229,18 +229,6 @@ impl CommittorProcessor { Ok(()) } - #[instrument(skip(self, account))] - pub async fn schedule_undelegation( - &self, - pubkey: Pubkey, - account: AccountSharedData, - ) -> CommittorServiceResult<()> { - self.schedule_intent_bundle(vec![undelegation_intent_bundle( - pubkey, account, - )]) - .await - } - #[instrument(skip(self, intent_bundles))] pub async fn schedule_recovered_intent_bundles( &self, @@ -275,69 +263,6 @@ impl CommittorProcessor { } } -pub(crate) fn undelegation_intent_bundle( - pubkey: Pubkey, - account: AccountSharedData, -) -> ScheduledIntentBundle { - let committed_account = CommittedAccount::from((pubkey, account)); - let remote_slot = committed_account.remote_slot; - let intent_bundle = MagicIntentBundle { - commit_and_undelegate: Some(CommitAndUndelegate { - commit_action: CommitType::Standalone(vec![committed_account]), - undelegate_action: UndelegateType::Standalone, - }), - ..Default::default() - }; - - ScheduledIntentBundle { - id: intent_id(), - slot: remote_slot, - blockhash: Default::default(), - sent_transaction: Default::default(), - payer: Default::default(), - intent_bundle, - } -} - -fn intent_id() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_nanos() - .try_into() - .unwrap_or(u64::MAX) -} - -/// Shared assertion that `bundle` is a standalone commit-and-undelegate for a -/// single `(pubkey, owner, slot)` account. Used by the builder and stub tests. -#[cfg(test)] -pub(crate) fn assert_undelegation_bundle( - bundle: &ScheduledIntentBundle, - pubkey: Pubkey, - owner: Pubkey, - slot: u64, -) { - assert_eq!(bundle.slot, slot); - assert!(bundle.intent_bundle.commit.is_none()); - let commit_and_undelegate = bundle - .intent_bundle - .commit_and_undelegate - .as_ref() - .expect("commit-and-undelegate intent should be present"); - assert!(matches!( - commit_and_undelegate.undelegate_action, - UndelegateType::Standalone - )); - let CommitType::Standalone(accounts) = &commit_and_undelegate.commit_action - else { - panic!("commit action should be standalone"); - }; - assert_eq!(accounts.len(), 1); - assert_eq!(accounts[0].pubkey, pubkey); - assert_eq!(accounts[0].remote_slot, slot); - assert_eq!(accounts[0].account.owner, owner); -} - fn pending_rows_to_scheduled_intent_bundles( rows: Vec, payer: Pubkey, @@ -523,18 +448,6 @@ mod tests { row } - #[test] - fn undelegation_intent_bundle_builds_commit_and_undelegate() { - let pubkey = Pubkey::new_unique(); - let owner = Pubkey::new_unique(); - let mut account = AccountSharedData::new(1_000, 4, &owner); - account.set_remote_slot(42); - - let bundle = undelegation_intent_bundle(pubkey, account); - - assert_undelegation_bundle(&bundle, pubkey, owner, 42); - } - #[test] fn pending_rows_reconstruct_commit_finalize_bundle() { let payer = Pubkey::new_unique(); diff --git a/magicblock-committor-service/src/service.rs b/magicblock-committor-service/src/service.rs index 21959db12..b1415b8bc 100644 --- a/magicblock-committor-service/src/service.rs +++ b/magicblock-committor-service/src/service.rs @@ -7,7 +7,6 @@ use std::{ use magicblock_core::traits::ActionsCallbackScheduler; use magicblock_program::magic_scheduled_base_intent::ScheduledIntentBundle; -use solana_account::AccountSharedData; use solana_keypair::Keypair; use solana_pubkey::Pubkey; use solana_signature::Signature; @@ -65,11 +64,6 @@ pub enum CommittorMessage { intent_bundles: Vec, respond_to: oneshot::Sender>, }, - ScheduleUndelegation { - pubkey: Pubkey, - account: AccountSharedData, - respond_to: oneshot::Sender>, - }, GetPendingIntentBundles { respond_to: oneshot::Sender>>, @@ -213,17 +207,6 @@ impl CommittorActor { error!(message_type = "ScheduleBaseIntents", error = ?e, "Failed to send response"); } } - ScheduleUndelegation { - pubkey, - account, - respond_to, - } => { - let result = - self.processor.schedule_undelegation(pubkey, account).await; - if let Err(e) = respond_to.send(result) { - error!(message_type = "ScheduleUndelegation", error = ?e, "Failed to send response"); - } - } GetPendingIntentBundles { respond_to } => { let pending_intents = self.processor.pending_intent_bundles().await; @@ -519,20 +502,6 @@ impl BaseIntentCommittor for CommittorService { rx } - fn schedule_undelegation( - &self, - pubkey: Pubkey, - account: AccountSharedData, - ) -> oneshot::Receiver> { - let (tx, rx) = oneshot::channel(); - self.try_send(CommittorMessage::ScheduleUndelegation { - pubkey, - account, - respond_to: tx, - }); - rx - } - fn get_commit_statuses( &self, message_id: u64, @@ -622,13 +591,6 @@ pub trait BaseIntentCommittor: Send + Sync + 'static { intent_bundles: Vec, ) -> oneshot::Receiver>; - /// Schedules commit-and-undelegate for a single delegated account. - fn schedule_undelegation( - &self, - pubkey: Pubkey, - account: AccountSharedData, - ) -> oneshot::Receiver>; - /// Subscribes for results of BaseIntent execution fn subscribe_for_results( &self, diff --git a/magicblock-committor-service/src/service_ext.rs b/magicblock-committor-service/src/service_ext.rs index ea067da81..024d0423e 100644 --- a/magicblock-committor-service/src/service_ext.rs +++ b/magicblock-committor-service/src/service_ext.rs @@ -8,7 +8,6 @@ use std::{ use async_trait::async_trait; use futures_util::future::join_all; use magicblock_program::magic_scheduled_base_intent::ScheduledIntentBundle; -use solana_account::AccountSharedData; use solana_pubkey::Pubkey; use solana_signature::Signature; use solana_transaction_status_client_types::EncodedConfirmedTransactionWithStatusMeta; @@ -176,14 +175,6 @@ impl BaseIntentCommittor for CommittorServiceExt { self.inner.schedule_intent_bundles(intent_bundles) } - fn schedule_undelegation( - &self, - pubkey: Pubkey, - account: AccountSharedData, - ) -> oneshot::Receiver> { - self.inner.schedule_undelegation(pubkey, account) - } - fn subscribe_for_results( &self, ) -> oneshot::Receiver> diff --git a/magicblock-committor-service/src/stubs/changeset_committor_stub.rs b/magicblock-committor-service/src/stubs/changeset_committor_stub.rs index 2c63c7920..0b417db47 100644 --- a/magicblock-committor-service/src/stubs/changeset_committor_stub.rs +++ b/magicblock-committor-service/src/stubs/changeset_committor_stub.rs @@ -8,7 +8,7 @@ use async_trait::async_trait; use magicblock_program::magic_scheduled_base_intent::{ CommitType, ScheduledIntentBundle, UndelegateType, }; -use solana_account::{Account, AccountSharedData}; +use solana_account::Account; use solana_pubkey::Pubkey; use solana_signature::Signature; use solana_transaction_status_client_types::{ @@ -19,7 +19,6 @@ use tokio::sync::{broadcast, oneshot}; use tokio_util::sync::{CancellationToken, WaitForCancellationFutureOwned}; use crate::{ - committor_processor::undelegation_intent_bundle, error::CommittorServiceResult, intent_execution_manager::BroadcastedIntentExecutionResult, intent_executor::ExecutionOutput, @@ -101,16 +100,6 @@ impl BaseIntentCommittor for ChangesetCommittorStub { receiver } - fn schedule_undelegation( - &self, - pubkey: Pubkey, - account: AccountSharedData, - ) -> oneshot::Receiver> { - self.schedule_intent_bundles(vec![undelegation_intent_bundle( - pubkey, account, - )]) - } - fn subscribe_for_results( &self, ) -> oneshot::Receiver> @@ -308,31 +297,3 @@ fn now() -> u64 { .expect("Time went backwards") .as_secs() } - -#[cfg(test)] -mod tests { - use super::*; - use crate::committor_processor::assert_undelegation_bundle; - - #[tokio::test] - async fn schedule_undelegation_exposes_commit_and_undelegate_api() { - let committor = ChangesetCommittorStub::default(); - let pubkey = Pubkey::new_unique(); - let owner = Pubkey::new_unique(); - let mut account = AccountSharedData::new(1_000, 4, &owner); - account.set_remote_slot(42); - - committor - .schedule_undelegation(pubkey, account.clone()) - .await - .expect("committor response channel should be open") - .expect("undelegation should be scheduled"); - - assert_eq!(committor.len(), 1); - assert_eq!(committor.committed(&pubkey), Some(account.into())); - - let changesets = committor.committed_changesets.lock().unwrap(); - let intent = changesets.values().next().expect("scheduled intent"); - assert_undelegation_bundle(intent, pubkey, owner, 42); - } -} diff --git a/programs/magicblock/src/utils/instruction_utils.rs b/programs/magicblock/src/utils/instruction_utils.rs index bd289fe99..dc97a460a 100644 --- a/programs/magicblock/src/utils/instruction_utils.rs +++ b/programs/magicblock/src/utils/instruction_utils.rs @@ -59,7 +59,6 @@ impl InstructionUtils { // ----------------- // Schedule Commit and Undelegate // ----------------- - #[cfg(test)] pub fn schedule_commit_and_undelegate( payer: &Keypair, pubkeys: Vec, @@ -72,8 +71,7 @@ impl InstructionUtils { Self::into_transaction(payer, ix, recent_blockhash) } - #[cfg(test)] - pub(crate) fn schedule_commit_and_undelegate_instruction( + pub fn schedule_commit_and_undelegate_instruction( payer: &Pubkey, pdas: Vec, ) -> Instruction { diff --git a/test-integration/Cargo.lock b/test-integration/Cargo.lock index 07d2b22ac..47ca9baa6 100644 --- a/test-integration/Cargo.lock +++ b/test-integration/Cargo.lock @@ -4318,7 +4318,6 @@ version = "0.12.0" dependencies = [ "agave-feature-set", "anyhow", - "async-trait", "borsh", "fd-lock", "magic-domain-program", @@ -11137,8 +11136,10 @@ name = "test-chainlink" version = "0.0.0" dependencies = [ "bincode", + "borsh", "futures", "integration-test-tools", + "magicblock-aml", "magicblock-chainlink", "magicblock-config", "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", @@ -11156,6 +11157,7 @@ dependencies = [ "solana-sdk-ids", "solana-system-interface 3.2.0", "spl-token-interface", + "tempfile", "tokio", "tracing", ] diff --git a/test-integration/Cargo.toml b/test-integration/Cargo.toml index b97350f47..10de745e0 100644 --- a/test-integration/Cargo.toml +++ b/test-integration/Cargo.toml @@ -19,7 +19,7 @@ members = [ "test-schedule-intent", "test-table-mania", "test-task-scheduler", - "test-tools" + "test-tools", ] resolver = "2" @@ -38,18 +38,23 @@ color-backtrace = { version = "0.7" } ctrlc = "3.4.7" ephemeral-rollups-sdk = { git = "https://github.com/magicblock-labs/ephemeral-rollups-sdk.git", rev = "ccfc9f924dc40", default-features = false, features = [ "disable-realloc", - "modular-sdk" + "modular-sdk", ] } futures = "0.3.31" integration-test-tools = { path = "test-tools" } isocountry = "0.3.2" lazy_static = "1.4.0" magic-domain-program = { git = "https://github.com/magicblock-labs/magic-domain-program.git", rev = "335a22", default-features = false } -magicblock-accounts-db = { path = "../magicblock-accounts-db", features = ["dev-tools"] } +magicblock-accounts-db = { path = "../magicblock-accounts-db", features = [ + "dev-tools", +] } +magicblock-aml = { path = "../magicblock-aml" } magicblock-api = { path = "../magicblock-api" } -magicblock-chainlink = { path = "../magicblock-chainlink", features = ["dev-context"] } +magicblock-chainlink = { path = "../magicblock-chainlink", features = [ + "dev-context", +] } magicblock-committor-program = { path = "../magicblock-committor-program", features = [ - "no-entrypoint" + "no-entrypoint", ] } magicblock-committor-service = { path = "../magicblock-committor-service" } magicblock-config = { path = "../magicblock-config" } diff --git a/test-integration/test-chainlink/Cargo.toml b/test-integration/test-chainlink/Cargo.toml index 8ab33f014..25498cb97 100644 --- a/test-integration/test-chainlink/Cargo.toml +++ b/test-integration/test-chainlink/Cargo.toml @@ -5,8 +5,10 @@ edition.workspace = true [dependencies] bincode = { workspace = true } +borsh = { workspace = true } futures = { workspace = true } tracing = { workspace = true } +magicblock-aml = { workspace = true } magicblock-chainlink = { workspace = true } magicblock-config = { workspace = true } magicblock-delegation-program-api = { workspace = true } @@ -15,7 +17,10 @@ program-flexi-counter = { workspace = true, features = ["no-entrypoint"] } solana-account = { workspace = true } solana-loader-v2-interface = { workspace = true, features = ["serde"] } solana-loader-v3-interface = { workspace = true, features = ["serde"] } -solana-loader-v4-interface = { workspace = true, features = ["bincode", "serde"] } +solana-loader-v4-interface = { workspace = true, features = [ + "bincode", + "serde", +] } solana-commitment-config = { workspace = true } solana-pubkey = { workspace = true } solana-rpc-client = { workspace = true } @@ -25,4 +30,5 @@ solana-sdk-ids = { workspace = true } solana-system-interface = { workspace = true } spl-token = { workspace = true } integration-test-tools = { workspace = true } +tempfile = { workspace = true } tokio = { workspace = true, features = ["full"] } diff --git a/test-integration/test-chainlink/src/ixtest_context.rs b/test-integration/test-chainlink/src/ixtest_context.rs index 4f6c41b61..8fff08e53 100644 --- a/test-integration/test-chainlink/src/ixtest_context.rs +++ b/test-integration/test-chainlink/src/ixtest_context.rs @@ -103,6 +103,7 @@ impl IxtestContext { commit_frequency_ms: None, delegation_actions: DelegationActions::default(), delegated_to_other: None, + needs_undelegation: false, }) .await .unwrap(); @@ -130,7 +131,6 @@ impl IxtestContext { rx, None, None, - None, )), Some(provider), ) diff --git a/test-integration/test-chainlink/src/test_context.rs b/test-integration/test-chainlink/src/test_context.rs index 4966a8d43..976b83f2e 100644 --- a/test-integration/test-chainlink/src/test_context.rs +++ b/test-integration/test-chainlink/src/test_context.rs @@ -4,6 +4,7 @@ use std::{ time::{Duration, Instant}, }; +use magicblock_aml::RiskService; use magicblock_chainlink::{ accounts_bank::mock::AccountsBankStub, errors::ChainlinkResult, @@ -54,6 +55,13 @@ pub struct TestContext { impl TestContext { pub async fn init(slot: Slot) -> Self { + Self::init_with_risk_service(slot, None).await + } + + pub async fn init_with_risk_service( + slot: Slot, + risk_service: Option>, + ) -> Self { let (rpc_client, pubsub_client) = { let rpc_client = ChainRpcClientMockBuilder::new().slot(slot).build(); @@ -103,8 +111,7 @@ impl TestContext { validator_keypair.insecure_clone(), rx, None, - None, - None, + risk_service, )), Some(provider), ) diff --git a/magicblock-chainlink/tests/10_aml_undelegation.rs b/test-integration/test-chainlink/tests/ix_aml_undelegation.rs similarity index 72% rename from magicblock-chainlink/tests/10_aml_undelegation.rs rename to test-integration/test-chainlink/tests/ix_aml_undelegation.rs index ece558da4..55916d66c 100644 --- a/magicblock-chainlink/tests/10_aml_undelegation.rs +++ b/test-integration/test-chainlink/tests/ix_aml_undelegation.rs @@ -2,7 +2,7 @@ use std::{ collections::HashMap, io::{Read, Write}, net::TcpListener, - sync::{Arc, Mutex}, + sync::Arc, time::Duration, }; @@ -15,41 +15,13 @@ use dlp_api::{ state::DelegationRecord, }; use magicblock_aml::RiskService; -use magicblock_chainlink::{ - chainlink::errors::ChainlinkResult, - fetch_cloner::{UndelegationScheduleRequest, UndelegationScheduler}, - testing::init_logger, -}; +use magicblock_chainlink::testing::init_logger; use magicblock_config::config::RiskConfig; -use solana_account::{Account, ReadableAccount}; +use solana_account::Account; use solana_pubkey::Pubkey; use solana_sdk_ids::system_program; +use test_chainlink::test_context::TestContext; use tokio::task::JoinHandle; -use utils::test_context::TestContext; - -mod utils; - -#[derive(Default)] -struct RecordingUndelegationScheduler { - requests: Mutex>, -} - -impl RecordingUndelegationScheduler { - fn requests(&self) -> Vec { - self.requests.lock().unwrap().clone() - } -} - -#[async_trait::async_trait] -impl UndelegationScheduler for RecordingUndelegationScheduler { - async fn schedule_undelegation( - &self, - request: UndelegationScheduleRequest, - ) -> ChainlinkResult<()> { - self.requests.lock().unwrap().push(request); - Ok(()) - } -} struct MockRiskServer { base_url: String, @@ -178,13 +150,15 @@ fn add_delegation_record_with_signer_action( ); } -#[tokio::test] -async fn post_delegation_aml_rejection_schedules_undelegation() { +async fn setup( + risk_score: u64, +) -> (TestContext, MockRiskServer, Pubkey, tempfile::TempDir) { init_logger(); - let high_risk_signer = Pubkey::new_unique(); + let signer = Pubkey::new_unique(); let server = - MockRiskServer::start(vec![(high_risk_signer.to_string(), 9)], 1).await; + MockRiskServer::start(vec![(signer.to_string(), risk_score)], 1).await; + // Keep alive for the test: RiskService writes risk-cache.db under this path. let temp_ledger = tempfile::tempdir().expect("temp ledger"); let risk_service = RiskService::try_from_config( &risk_config(server.base_url.clone()), @@ -193,15 +167,10 @@ async fn post_delegation_aml_rejection_schedules_undelegation() { .expect("risk config should be valid") .expect("risk service should be enabled"); let risk_service = Arc::new(risk_service); - let scheduler = Arc::new(RecordingUndelegationScheduler::default()); let slot = 100; - let ctx = TestContext::init_with_services( - slot, - Some(risk_service), - Some(scheduler.clone() as Arc), - ) - .await; + let ctx = + TestContext::init_with_risk_service(slot, Some(risk_service)).await; let delegated_pubkey = Pubkey::new_unique(); let owner = system_program::id(); @@ -219,34 +188,43 @@ async fn post_delegation_aml_rejection_schedules_undelegation() { &ctx, delegated_pubkey, owner, - high_risk_signer, + signer, ); - let err = ctx - .ensure_account(&delegated_pubkey) + (ctx, server, delegated_pubkey, temp_ledger) +} + +#[tokio::test] +async fn post_delegation_aml_rejection_schedules_undelegation_with_high_risk_signer( +) { + let (ctx, server, delegated_pubkey, _temp_ledger) = setup(9).await; + + ctx.ensure_account(&delegated_pubkey) .await - .expect_err("high-risk signer should reject the clone"); + .expect("high-risk signer should still be cloned"); + let req = ctx.cloner.clone_requests().first().cloned().unwrap(); assert!( - matches!( - &err, - magicblock_chainlink::errors::ChainlinkError::PendingRequestOwnerFailed( - pubkey, - message, - ) if *pubkey == delegated_pubkey && message.contains("high risk") - ), - "unexpected error: {err:?}" + req.needs_undelegation, + "AML-rejected action must schedule undelegation" ); + + server.join().await; +} + +#[tokio::test] +async fn post_delegation_aml_accepts_low_risk_signer() { + let (ctx, server, delegated_pubkey, _temp_ledger) = setup(1).await; + + ctx.ensure_account(&delegated_pubkey) + .await + .expect("low-risk signer should be cloned"); + + let req = ctx.cloner.clone_requests().first().cloned().unwrap(); assert!( - ctx.cloner.clone_requests().is_empty(), - "AML-rejected action target must not be cloned" + !req.needs_undelegation, + "AML-accepted action must not schedule undelegation" ); - let scheduled = scheduler.requests(); - assert_eq!(scheduled.len(), 1); - assert_eq!(scheduled[0].pubkey, delegated_pubkey); - assert!(scheduled[0].account.delegated()); - assert_eq!(scheduled[0].account.owner(), &owner); - server.join().await; } From 9876d6356cc3fe51484c9f9e9efd67b41c0f08e5 Mon Sep 17 00:00:00 2001 From: Dodecahedr0x Date: Mon, 15 Jun 2026 18:11:44 +0200 Subject: [PATCH 5/7] refactor: cloned undelegation --- magicblock-account-cloner/src/lib.rs | 19 +- .../src/instruction.rs | 10 + .../process_post_delegation_actions.rs | 99 +- .../magicblock/src/magicblock_processor.rs | 12 +- .../src/schedule_transactions/mod.rs | 2 + .../process_schedule_cloned_undelegation.rs | 215 ++ .../magicblock/src/utils/instruction_utils.rs | 20 + programs/magicblock/src/utils/mod.rs | 1 + programs/magicblock/src/utils/validation.rs | 96 + test-integration/Cargo.lock | 2228 ++++++++++++----- test-integration/Cargo.toml | 4 +- test-integration/Makefile | 11 + test-integration/configs/aml.devnet.toml | 65 + test-integration/test-aml/Cargo.toml | 29 + test-integration/test-aml/src/lib.rs | 341 +++ test-integration/test-aml/tests/range_mock.rs | 282 +++ test-integration/test-runner/Cargo.toml | 1 + test-integration/test-runner/bin/run_tests.rs | 53 + 18 files changed, 2719 insertions(+), 769 deletions(-) create mode 100644 programs/magicblock/src/schedule_transactions/process_schedule_cloned_undelegation.rs create mode 100644 programs/magicblock/src/utils/validation.rs create mode 100644 test-integration/configs/aml.devnet.toml create mode 100644 test-integration/test-aml/Cargo.toml create mode 100644 test-integration/test-aml/src/lib.rs create mode 100644 test-integration/test-aml/tests/range_mock.rs diff --git a/magicblock-account-cloner/src/lib.rs b/magicblock-account-cloner/src/lib.rs index 1018ccdb2..bdb99f9f6 100644 --- a/magicblock-account-cloner/src/lib.rs +++ b/magicblock-account-cloner/src/lib.rs @@ -215,9 +215,8 @@ impl ChainlinkCloner { } fn schedule_undelegation_ix(pubkey: Pubkey) -> Instruction { - InstructionUtils::schedule_commit_and_undelegate_instruction( - &validator_authority_id(), - vec![pubkey], + InstructionUtils::schedule_cloned_account_undelegation_instruction( + pubkey, ) } @@ -247,11 +246,16 @@ impl ChainlinkCloner { let fields = Self::clone_fields(request); let actions: Vec = request.delegation_actions.clone().into(); + let clone_actions = if request.needs_undelegation { + Vec::new() + } else { + actions.clone() + }; let clone_ix = Self::clone_ix( request.pubkey, request.account.data().to_vec(), fields, - actions.clone(), + clone_actions, ); // TODO(#625): Re-enable frequency commits when proper limits are in place: @@ -323,6 +327,11 @@ impl ChainlinkCloner { let actions: Vec = request.delegation_actions.clone().into(); + let clone_actions = if request.needs_undelegation { + Vec::new() + } else { + actions.clone() + }; // Continue txs for remaining chunks let mut offset = MAX_INLINE_DATA_SIZE; @@ -350,7 +359,7 @@ impl ChainlinkCloner { data.len() as u32, Vec::new(), true, - actions.clone(), + clone_actions, ); let ix = if request.needs_undelegation { Self::schedule_undelegation_ix(request.pubkey) diff --git a/magicblock-magic-program-api/src/instruction.rs b/magicblock-magic-program-api/src/instruction.rs index 343eeeede..161f79568 100644 --- a/magicblock-magic-program-api/src/instruction.rs +++ b/magicblock-magic-program-api/src/instruction.rs @@ -373,4 +373,14 @@ pub enum PostDelegationActionExecutorInstruction { cloned_account_pubkey: Pubkey, actions: Vec, }, + + /// Schedules undelegation immediately after a matching delegated clone + /// instruction in the same transaction. + /// + /// # Account references + /// - **0.** `[SIGNER]` Validator authority + /// - **1.** `[]` Delegated clone target + /// - **2.** `[]` Instructions sysvar + /// - **3.** `[WRITE]` Magic Context account + ScheduleUndelegation { cloned_account_pubkey: Pubkey }, } diff --git a/programs/magicblock/src/clone_account/process_post_delegation_actions.rs b/programs/magicblock/src/clone_account/process_post_delegation_actions.rs index 276909039..899b8c221 100644 --- a/programs/magicblock/src/clone_account/process_post_delegation_actions.rs +++ b/programs/magicblock/src/clone_account/process_post_delegation_actions.rs @@ -10,10 +10,13 @@ use solana_program_runtime::invoke_context::InvokeContext; use solana_pubkey::Pubkey; use super::{ - execute_post_delegation_actions, load_instructions_sysvar_data, - remove_pending_clone, validate_and_get_index, validate_authority, + execute_post_delegation_actions, remove_pending_clone, + validate_and_get_index, validate_authority, +}; +use crate::{ + errors::MagicBlockProgramError, + utils::validation::validate_last_after_clone, }; -use crate::{errors::MagicBlockProgramError, utils::instruction_sysvar}; pub(crate) fn process_execute_post_delegation_actions( signers: HashSet, @@ -23,55 +26,10 @@ pub(crate) fn process_execute_post_delegation_actions( ) -> Result<(), InstructionError> { validate_authority(&signers, invoke_context)?; validate_program_account(invoke_context)?; - - let mut sysvar_data = load_instructions_sysvar_data(invoke_context)?; - let current_index = - instruction_sysvar::load_current_index(&mut sysvar_data)?; - validate_current_top_level_instruction( + let previous_instruction = validate_last_after_clone( invoke_context, - &mut sysvar_data, - current_index, + "Post-delegation action executor", )?; - if current_index == 0 { - ic_msg!( - invoke_context, - "Post-delegation action executor has no previous clone instruction" - ); - return Err( - MagicBlockProgramError::PostDelegationActionExecutorMissing.into(), - ); - } - - // The executor mutates process-global pending-clone state for final chunked - // clones, so it must be the last top-level instruction in the transaction. - if instruction_sysvar::load_instruction_at( - &mut sysvar_data, - current_index.saturating_add(1), - ) - .is_ok() - { - ic_msg!( - invoke_context, - "Post-delegation action executor must be the last instruction" - ); - return Err( - MagicBlockProgramError::PostDelegationActionExecutorMismatch.into(), - ); - } - - let previous_instruction = instruction_sysvar::load_instruction_at( - &mut sysvar_data, - current_index - 1, - )?; - if previous_instruction.program_id != crate::ID { - ic_msg!( - invoke_context, - "Post-delegation action executor previous instruction is not Magic" - ); - return Err( - MagicBlockProgramError::PostDelegationActionExecutorMismatch.into(), - ); - } let previous_magic_instruction: MagicBlockInstruction = bincode::deserialize(&previous_instruction.data) @@ -159,44 +117,3 @@ fn validate_program_account( } Ok(()) } - -fn validate_current_top_level_instruction( - invoke_context: &mut InvokeContext, - sysvar_data: &mut [u8], - current_index: usize, -) -> Result<(), InstructionError> { - if invoke_context - .transaction_context - .get_instruction_stack_height() - != 1 - { - ic_msg!( - invoke_context, - "Post-delegation action executor must be top-level" - ); - return Err( - MagicBlockProgramError::PostDelegationActionExecutorNotTopLevel - .into(), - ); - } - - let current_instruction = - instruction_sysvar::load_instruction_at(sysvar_data, current_index)?; - let current_ix_ctx = invoke_context - .transaction_context - .get_current_instruction_context()?; - if current_instruction.program_id - != POST_DELEGATION_ACTION_EXECUTOR_PROGRAM_ID - || current_instruction.data != current_ix_ctx.get_instruction_data() - { - ic_msg!( - invoke_context, - "Post-delegation action executor must be top-level" - ); - return Err( - MagicBlockProgramError::PostDelegationActionExecutorNotTopLevel - .into(), - ); - } - Ok(()) -} diff --git a/programs/magicblock/src/magicblock_processor.rs b/programs/magicblock/src/magicblock_processor.rs index 2bd91df52..43245c4da 100644 --- a/programs/magicblock/src/magicblock_processor.rs +++ b/programs/magicblock/src/magicblock_processor.rs @@ -26,8 +26,9 @@ use crate::{ }, schedule_transactions::{ process_accept_scheduled_commits, process_add_action_callback, - process_execute_callback, process_schedule_commit, - process_schedule_intent_bundle, ProcessScheduleCommitOptions, + process_execute_callback, process_schedule_cloned_account_undelegation, + process_schedule_commit, process_schedule_intent_bundle, + ProcessScheduleCommitOptions, }, }; @@ -301,6 +302,13 @@ declare_process_instruction!( cloned_account_pubkey, actions, ), + PostDelegationActionExecutorInstruction::ScheduleUndelegation { + cloned_account_pubkey, + } => process_schedule_cloned_account_undelegation( + signers, + invoke_context, + cloned_account_pubkey, + ), } } ); diff --git a/programs/magicblock/src/schedule_transactions/mod.rs b/programs/magicblock/src/schedule_transactions/mod.rs index 574446361..e178df054 100644 --- a/programs/magicblock/src/schedule_transactions/mod.rs +++ b/programs/magicblock/src/schedule_transactions/mod.rs @@ -1,6 +1,7 @@ mod process_accept_scheduled_commits; mod process_add_action_callback; mod process_execute_callback; +mod process_schedule_cloned_undelegation; mod process_schedule_commit; #[cfg(test)] mod process_schedule_commit_tests; @@ -17,6 +18,7 @@ use magicblock_magic_program_api::{ pub(crate) use process_accept_scheduled_commits::*; pub(crate) use process_add_action_callback::process_add_action_callback; pub(crate) use process_execute_callback::*; +pub(crate) use process_schedule_cloned_undelegation::process_schedule_cloned_account_undelegation; pub(crate) use process_schedule_commit::*; pub(crate) use process_schedule_intent_bundle::process_schedule_intent_bundle; pub use process_scheduled_commit_sent::{ diff --git a/programs/magicblock/src/schedule_transactions/process_schedule_cloned_undelegation.rs b/programs/magicblock/src/schedule_transactions/process_schedule_cloned_undelegation.rs new file mode 100644 index 000000000..7d3fc9cbb --- /dev/null +++ b/programs/magicblock/src/schedule_transactions/process_schedule_cloned_undelegation.rs @@ -0,0 +1,215 @@ +use std::collections::HashSet; + +use magicblock_core::intent::CommittedAccount; +use magicblock_magic_program_api::{ + instruction::MagicBlockInstruction, MAGIC_CONTEXT_PUBKEY, +}; +use solana_account::{ReadableAccount, WritableAccount}; +use solana_instruction::error::InstructionError; +use solana_log_collector::ic_msg; +use solana_program_runtime::invoke_context::InvokeContext; +use solana_pubkey::Pubkey; + +use crate::{ + magic_scheduled_base_intent::{ + CommitAndUndelegate, CommitType, MagicBaseIntent, + ScheduledIntentBundle, UndelegateType, + }, + schedule_transactions::get_clock, + utils::{ + accounts::{ + get_instruction_account_with_idx, get_instruction_pubkey_with_idx, + }, + instruction_utils::InstructionUtils, + validation::validate_last_after_clone, + }, + validator::validator_authority_id, + MagicContext, +}; + +const PAYER_IDX: u16 = 0; +const CLONED_ACCOUNT_IDX: u16 = 1; +const INSTRUCTIONS_SYSVAR_IDX: u16 = 2; +const MAGIC_CONTEXT_ACCOUNT_IDX: u16 = 3; + +pub(crate) fn process_schedule_cloned_account_undelegation( + signers: HashSet, + invoke_context: &mut InvokeContext, + cloned_account_pubkey: Pubkey, +) -> Result<(), InstructionError> { + validate_authority(&signers, invoke_context)?; + validate_previous_clone(invoke_context, cloned_account_pubkey)?; + let clock = get_clock(invoke_context)?; + let blockhash = invoke_context.environment_config.blockhash; + + let transaction_context = &*invoke_context.transaction_context; + let cloned_account_pubkey_at_idx = get_instruction_pubkey_with_idx( + transaction_context, + CLONED_ACCOUNT_IDX, + )?; + if cloned_account_pubkey_at_idx != &cloned_account_pubkey { + ic_msg!( + invoke_context, + "ScheduleClonedAccountUndelegation ERR: cloned account mismatch, expected {}, got {}", + cloned_account_pubkey, + cloned_account_pubkey_at_idx + ); + return Err(InstructionError::InvalidArgument); + } + + check_instructions_sysvar(invoke_context)?; + check_magic_context(invoke_context)?; + + let cloned_account = get_instruction_account_with_idx( + transaction_context, + CLONED_ACCOUNT_IDX, + )?; + let account = cloned_account.to_account_shared_data()?; + if !account.delegated() || account.confined() || account.ephemeral() { + ic_msg!( + invoke_context, + "ScheduleClonedAccountUndelegation ERR: account {} must be delegated, non-confined, and non-ephemeral", + cloned_account_pubkey + ); + return Err(InstructionError::InvalidAccountData); + } + + let committed = CommittedAccount::from_account_shared( + cloned_account_pubkey, + &account, + None, + ); + + let context_acc = get_instruction_account_with_idx( + transaction_context, + MAGIC_CONTEXT_ACCOUNT_IDX, + )?; + let mut context = MagicContext::deserialize(context_acc.borrow()?.data()) + .map_err(|err| { + ic_msg!( + invoke_context, + "Failed to deserialize MagicContext: {}", + err + ); + InstructionError::GenericError + })?; + + let intent_id = context.next_intent_id(); + let sent_transaction = + InstructionUtils::scheduled_commit_sent(intent_id, blockhash); + + let base_intent = + MagicBaseIntent::CommitAndUndelegate(CommitAndUndelegate { + commit_action: CommitType::Standalone(vec![committed]), + undelegate_action: UndelegateType::Standalone, + }) + .into(); + + let scheduled = ScheduledIntentBundle { + id: intent_id, + slot: clock.slot, + blockhash, + sent_transaction, + payer: validator_authority_id(), + intent_bundle: base_intent, + }; + context.add_scheduled_action(scheduled); + context.write_to(context_acc.borrow_mut()?.data_as_mut_slice())?; + + ic_msg!( + invoke_context, + "ScheduleClonedAccountUndelegation: scheduled undelegation for {} with ID {}", + cloned_account_pubkey, + intent_id + ); + Ok(()) +} + +fn validate_authority( + signers: &HashSet, + invoke_context: &InvokeContext, +) -> Result<(), InstructionError> { + let payer_pubkey = get_instruction_pubkey_with_idx( + invoke_context.transaction_context, + PAYER_IDX, + )?; + if payer_pubkey != &validator_authority_id() + || !signers.contains(payer_pubkey) + { + ic_msg!( + invoke_context, + "ScheduleClonedAccountUndelegation ERR: validator authority {} not in signers", + payer_pubkey + ); + return Err(InstructionError::MissingRequiredSignature); + } + Ok(()) +} + +fn validate_previous_clone( + invoke_context: &mut InvokeContext, + cloned_account_pubkey: Pubkey, +) -> Result<(), InstructionError> { + let previous_instruction = validate_last_after_clone( + invoke_context, + "ScheduleClonedAccountUndelegation", + )?; + + let previous_magic_instruction: MagicBlockInstruction = + bincode::deserialize(&previous_instruction.data) + .map_err(|_| InstructionError::InvalidInstructionData)?; + match previous_magic_instruction { + MagicBlockInstruction::CloneAccount { pubkey, fields, .. } + if pubkey == cloned_account_pubkey && fields.delegated => + { + Ok(()) + } + MagicBlockInstruction::CloneAccountContinue { + pubkey, + is_last: true, + .. + } if pubkey == cloned_account_pubkey => Ok(()), + _ => { + ic_msg!( + invoke_context, + "ScheduleClonedAccountUndelegation previous instruction mismatch" + ); + Err(InstructionError::InvalidInstructionData) + } + } +} + +fn check_instructions_sysvar( + invoke_context: &InvokeContext, +) -> Result<(), InstructionError> { + let provided = get_instruction_pubkey_with_idx( + invoke_context.transaction_context, + INSTRUCTIONS_SYSVAR_IDX, + )?; + if provided != &solana_sdk_ids::sysvar::instructions::id() { + ic_msg!( + invoke_context, + "ScheduleClonedAccountUndelegation ERR: instructions sysvar missing" + ); + return Err(InstructionError::UnsupportedSysvar); + } + Ok(()) +} + +fn check_magic_context( + invoke_context: &InvokeContext, +) -> Result<(), InstructionError> { + let provided = get_instruction_pubkey_with_idx( + invoke_context.transaction_context, + MAGIC_CONTEXT_ACCOUNT_IDX, + )?; + if provided != &MAGIC_CONTEXT_PUBKEY { + ic_msg!( + invoke_context, + "ScheduleClonedAccountUndelegation ERR: invalid magic context {}", + provided + ); + return Err(InstructionError::MissingAccount); + } + Ok(()) +} diff --git a/programs/magicblock/src/utils/instruction_utils.rs b/programs/magicblock/src/utils/instruction_utils.rs index dc97a460a..0a577e8f0 100644 --- a/programs/magicblock/src/utils/instruction_utils.rs +++ b/programs/magicblock/src/utils/instruction_utils.rs @@ -490,6 +490,26 @@ impl InstructionUtils { ) } + pub fn schedule_cloned_account_undelegation_instruction( + cloned_account_pubkey: Pubkey, + ) -> Instruction { + Instruction::new_with_bincode( + POST_DELEGATION_ACTION_EXECUTOR_PROGRAM_ID, + &PostDelegationActionExecutorInstruction::ScheduleUndelegation { + cloned_account_pubkey, + }, + vec![ + AccountMeta::new_readonly(validator_authority_id(), true), + AccountMeta::new_readonly(cloned_account_pubkey, false), + AccountMeta::new_readonly( + solana_sdk_ids::sysvar::instructions::id(), + false, + ), + AccountMeta::new(MAGIC_CONTEXT_PUBKEY, false), + ], + ) + } + pub fn cleanup_partial_clone_instruction(pubkey: Pubkey) -> Instruction { Instruction::new_with_bincode( crate::id(), diff --git a/programs/magicblock/src/utils/mod.rs b/programs/magicblock/src/utils/mod.rs index 02611fd40..dac959432 100644 --- a/programs/magicblock/src/utils/mod.rs +++ b/programs/magicblock/src/utils/mod.rs @@ -5,6 +5,7 @@ pub mod accounts; pub(crate) mod instruction_context_frames; pub(crate) mod instruction_sysvar; pub mod instruction_utils; +pub(crate) mod validation; // NOTE: there is no low level SDK currently that exposes the program address // we hardcode it here to avoid either having to pull in the delegation program diff --git a/programs/magicblock/src/utils/validation.rs b/programs/magicblock/src/utils/validation.rs new file mode 100644 index 000000000..218d0bf7e --- /dev/null +++ b/programs/magicblock/src/utils/validation.rs @@ -0,0 +1,96 @@ +use magicblock_magic_program_api::POST_DELEGATION_ACTION_EXECUTOR_PROGRAM_ID; +use solana_instruction::Instruction; +use solana_log_collector::ic_msg; +use solana_program_runtime::invoke_context::InvokeContext; +use solana_transaction::InstructionError; + +use crate::{ + clone_account::load_instructions_sysvar_data, + errors::MagicBlockProgramError, utils::instruction_sysvar, +}; + +pub fn validate_current_top_level_instruction( + invoke_context: &mut InvokeContext, + sysvar_data: &mut [u8], + current_index: usize, + context: &str, +) -> Result<(), InstructionError> { + if invoke_context + .transaction_context + .get_instruction_stack_height() + != 1 + { + ic_msg!(invoke_context, "{} must be top-level", context); + return Err(InstructionError::InvalidInstructionData); + } + + let current_instruction = + instruction_sysvar::load_instruction_at(sysvar_data, current_index)?; + let current_ix_ctx = invoke_context + .transaction_context + .get_current_instruction_context()?; + if current_instruction.program_id + != POST_DELEGATION_ACTION_EXECUTOR_PROGRAM_ID + || current_instruction.data != current_ix_ctx.get_instruction_data() + { + ic_msg!(invoke_context, "{} must be top-level", context); + return Err(InstructionError::InvalidInstructionData); + } + Ok(()) +} + +pub fn validate_last_after_clone( + invoke_context: &mut InvokeContext, + context: &str, +) -> Result { + let mut sysvar_data = load_instructions_sysvar_data(invoke_context)?; + let current_index = + instruction_sysvar::load_current_index(&mut sysvar_data)?; + validate_current_top_level_instruction( + invoke_context, + &mut sysvar_data, + current_index, + context, + )?; + if current_index == 0 { + ic_msg!( + invoke_context, + "{} has no previous clone instruction", + context + ); + return Err( + MagicBlockProgramError::PostDelegationActionExecutorMissing.into(), + ); + } + + // The executor mutates process-global pending-clone state for final chunked + // clones, so it must be the last top-level instruction in the transaction. + if instruction_sysvar::load_instruction_at( + &mut sysvar_data, + current_index.saturating_add(1), + ) + .is_ok() + { + ic_msg!(invoke_context, "{} must be the last instruction", context); + return Err( + MagicBlockProgramError::PostDelegationActionExecutorMismatch.into(), + ); + } + + let previous_instruction = instruction_sysvar::load_instruction_at( + &mut sysvar_data, + current_index - 1, + )?; + if previous_instruction.program_id != crate::ID { + ic_msg!( + invoke_context, + "{} previous instruction is not Magic", + context + ); + return Err( + MagicBlockProgramError::PostDelegationActionExecutorMismatch.into(), + ); + } + + Ok(previous_instruction) +} diff --git a/test-integration/Cargo.lock b/test-integration/Cargo.lock index 47ca9baa6..f7f959b59 100644 --- a/test-integration/Cargo.lock +++ b/test-integration/Cargo.lock @@ -76,7 +76,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6200f3b8cfbe5992fde00d443f60e62a79d2d8f6a658af1ffb7c4f0baa3c7028" dependencies = [ "ahash 0.8.12", - "solana-epoch-schedule", + "solana-epoch-schedule 3.1.0", "solana-hash 3.1.0", "solana-pubkey 3.0.0", "solana-sha256-hasher 3.1.0", @@ -104,7 +104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d93caf9e6dd35ba4193fe778c1e52ee69433ba53b9eaeebc00c7bcd4d699081" dependencies = [ "log", - "solana-clock", + "solana-clock 3.0.1", "solana-hash 3.1.0", "solana-signature", "solana-transaction", @@ -151,10 +151,10 @@ dependencies = [ "openssl", "sha3", "solana-ed25519-program", - "solana-message", + "solana-message 3.1.0", "solana-precompile-error", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-secp256k1-program", "solana-secp256r1-program", ] @@ -167,7 +167,7 @@ checksum = "2c3998a6ec388df954d8f78eeaf73ff487b50a8bdaebd48c8573af22c7b6db72" dependencies = [ "agave-feature-set", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", ] [[package]] @@ -186,7 +186,7 @@ dependencies = [ "regex", "semver", "solana-accounts-db", - "solana-clock", + "solana-clock 3.0.1", "solana-genesis-config", "solana-hash 3.1.0", "solana-lattice-hash", @@ -209,36 +209,36 @@ dependencies = [ "bincode", "libsecp256k1", "num-traits", - "solana-account", - "solana-account-info", - "solana-big-mod-exp", - "solana-blake3-hasher", + "solana-account 3.4.0", + "solana-account-info 3.1.1", + "solana-big-mod-exp 3.0.0", + "solana-blake3-hasher 3.1.0", "solana-bn254", - "solana-clock", - "solana-cpi", + "solana-clock 3.0.1", + "solana-cpi 3.1.0", "solana-curve25519", "solana-hash 3.1.0", - "solana-instruction", - "solana-keccak-hasher", - "solana-loader-v3-interface", + "solana-instruction 3.4.0", + "solana-keccak-hasher 3.1.0", + "solana-loader-v3-interface 6.1.1", "solana-poseidon", - "solana-program-entrypoint", + "solana-program-entrypoint 3.1.1", "solana-program-runtime", "solana-pubkey 3.0.0", "solana-sbpf", - "solana-sdk-ids", - "solana-secp256k1-recover", + "solana-sdk-ids 3.1.0", + "solana-secp256k1-recover 3.1.1", "solana-sha256-hasher 3.1.0", - "solana-stable-layout", - "solana-stake-interface", + "solana-stable-layout 3.0.1", + "solana-stake-interface 2.0.2", "solana-svm-callback", "solana-svm-feature-set", "solana-svm-log-collector", "solana-svm-measure", "solana-svm-timings", "solana-svm-type-overrides", - "solana-sysvar", - "solana-sysvar-id", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", "solana-transaction-context", "thiserror 2.0.18", ] @@ -250,11 +250,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9b36ce7792c4e48140ee2f9ef4eaa289fab1c383a0670588a6c7c755947608c" dependencies = [ "solana-hash 3.1.0", - "solana-message", + "solana-message 3.1.0", "solana-packet", "solana-pubkey 3.0.0", - "solana-sdk-ids", - "solana-short-vec", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.2.0", "solana-signature", "solana-svm-transaction", "solana-transaction-context", @@ -269,7 +269,7 @@ dependencies = [ "agave-logger", "serde", "solana-bls-signatures", - "solana-clock", + "solana-clock 3.0.1", "solana-hash 3.1.0", ] @@ -1200,16 +1200,39 @@ dependencies = [ "subtle", ] +[[package]] +name = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive 0.10.4", + "hashbrown 0.12.3", +] + [[package]] name = "borsh" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" dependencies = [ - "borsh-derive", + "borsh-derive 1.6.0", "cfg_aliases", ] +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + [[package]] name = "borsh-derive" version = "1.6.0" @@ -1217,12 +1240,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" dependencies = [ "once_cell", - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.117", ] +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "brotli" version = "8.0.2" @@ -1579,6 +1624,26 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + [[package]] name = "const-crypto" version = "0.3.0" @@ -2289,35 +2354,44 @@ dependencies = [ [[package]] name = "ephemeral-rollups-sdk" -version = "0.11.0" -source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=ccfc9f924dc40#ccfc9f924dc403e6ec93780e575fa655af1bebb5" +version = "0.15.3" +source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=cd3be977f402f3438ee920c959f7f7a5e02101f8#cd3be977f402f3438ee920c959f7f7a5e02101f8" dependencies = [ "base64ct", "bincode", - "borsh", + "bytemuck", "ephemeral-rollups-sdk-attribute-action", "ephemeral-rollups-sdk-attribute-commit", "ephemeral-rollups-sdk-attribute-delegate", "ephemeral-rollups-sdk-attribute-ephemeral", "ephemeral-rollups-sdk-attribute-ephemeral-accounts", + "ephemeral-vrf-sdk", + "ephemeral-vrf-sdk-vrf-macro", + "five8 0.2.1", "getrandom 0.2.16", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?branch=snawaz%2Fupgrade)", - "magicblock-magic-program-api 0.9.0", - "solana-account", - "solana-account-info", - "solana-cpi", - "solana-instruction", - "solana-program-error", - "solana-program-memory", + "magicblock-delegation-program-api 3.0.0", + "magicblock-magic-program-api 0.10.1", + "solana-account 3.4.0", + "solana-account-info 2.3.0", + "solana-account-info 3.1.1", + "solana-address 2.6.0", + "solana-cpi 3.1.0", + "solana-instruction 3.4.0", + "solana-program 2.3.0", + "solana-program 3.0.0", + "solana-program-error 2.2.2", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", "solana-pubkey 3.0.0", - "solana-system-interface 3.2.0", - "solana-sysvar", + "solana-system-interface 2.0.0", + "solana-sysvar 3.1.1", + "spl-associated-token-account-interface 1.0.0", ] [[package]] name = "ephemeral-rollups-sdk-attribute-action" -version = "0.11.0" -source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=ccfc9f924dc40#ccfc9f924dc403e6ec93780e575fa655af1bebb5" +version = "0.15.3" +source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=cd3be977f402f3438ee920c959f7f7a5e02101f8#cd3be977f402f3438ee920c959f7f7a5e02101f8" dependencies = [ "quote", "syn 1.0.109", @@ -2325,17 +2399,18 @@ dependencies = [ [[package]] name = "ephemeral-rollups-sdk-attribute-commit" -version = "0.11.0" -source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=ccfc9f924dc40#ccfc9f924dc403e6ec93780e575fa655af1bebb5" +version = "0.15.3" +source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=cd3be977f402f3438ee920c959f7f7a5e02101f8#cd3be977f402f3438ee920c959f7f7a5e02101f8" dependencies = [ + "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "ephemeral-rollups-sdk-attribute-delegate" -version = "0.11.0" -source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=ccfc9f924dc40#ccfc9f924dc403e6ec93780e575fa655af1bebb5" +version = "0.15.3" +source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=cd3be977f402f3438ee920c959f7f7a5e02101f8#cd3be977f402f3438ee920c959f7f7a5e02101f8" dependencies = [ "proc-macro2", "quote", @@ -2344,8 +2419,8 @@ dependencies = [ [[package]] name = "ephemeral-rollups-sdk-attribute-ephemeral" -version = "0.11.0" -source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=ccfc9f924dc40#ccfc9f924dc403e6ec93780e575fa655af1bebb5" +version = "0.15.3" +source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=cd3be977f402f3438ee920c959f7f7a5e02101f8#cd3be977f402f3438ee920c959f7f7a5e02101f8" dependencies = [ "proc-macro2", "quote", @@ -2354,8 +2429,31 @@ dependencies = [ [[package]] name = "ephemeral-rollups-sdk-attribute-ephemeral-accounts" -version = "0.11.0" -source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=ccfc9f924dc40#ccfc9f924dc403e6ec93780e575fa655af1bebb5" +version = "0.15.3" +source = "git+https://github.com/magicblock-labs/ephemeral-rollups-sdk.git?rev=cd3be977f402f3438ee920c959f7f7a5e02101f8#cd3be977f402f3438ee920c959f7f7a5e02101f8" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ephemeral-vrf-sdk" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77f3741c733907c10e0d0b32f9aa485c20a73e0b1e7e673a0ac38185fb2a6c11" +dependencies = [ + "borsh 1.6.0", + "ephemeral-vrf-sdk-vrf-macro", + "solana-program 3.0.0", + "solana-system-interface 3.2.0", +] + +[[package]] +name = "ephemeral-vrf-sdk-vrf-macro" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7b8b3fe3863a27d4c0f32da7b3cfeff179772fd4124d6c9fdcb9d4ab23cd602" dependencies = [ "proc-macro2", "quote", @@ -2504,7 +2602,7 @@ dependencies = [ "atomic", "pear", "serde", - "toml", + "toml 0.8.23", "uncased", "version_check", ] @@ -2918,7 +3016,7 @@ dependencies = [ "bincode", "magicblock-magic-program-api 0.12.0", "serde", - "solana-program", + "solana-program 3.0.0", ] [[package]] @@ -3584,10 +3682,10 @@ name = "integration-test-tools" version = "0.0.0" dependencies = [ "anyhow", - "borsh", + "borsh 1.6.0", "color-backtrace", "magicblock-config", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "rand 0.8.5", "rayon", "serde", @@ -3599,7 +3697,7 @@ dependencies = [ "solana-system-interface 3.2.0", "solana-transaction-status", "tempfile", - "toml", + "toml 0.8.23", "tracing", "ureq 2.12.1", "url", @@ -3836,16 +3934,16 @@ dependencies = [ "prost 0.14.3", "prost-types 0.14.3", "protobuf-src", - "solana-account", + "solana-account 3.4.0", "solana-account-decoder", - "solana-clock", + "solana-clock 3.0.1", "solana-hash 3.1.0", - "solana-message", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-signature", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status", "tonic 0.14.5", "tonic-build 0.14.5", @@ -4169,9 +4267,9 @@ name = "magic-domain-program" version = "0.3.0" source = "git+https://github.com/magicblock-labs/magic-domain-program.git?rev=335a22#335a22ba5aa7b8c4bc84d5053444c74c3b05cdac" dependencies = [ - "borsh", + "borsh 1.6.0", "bytemuck_derive", - "solana-program", + "solana-program 3.0.0", "solana-system-interface 3.2.0", ] @@ -4191,16 +4289,16 @@ dependencies = [ "magicblock-program", "magicblock-rpc-client", "rand 0.9.2", - "solana-account", + "solana-account 3.4.0", "solana-hash 3.1.0", - "solana-instruction", - "solana-loader-v3-interface", - "solana-loader-v4-interface", + "solana-instruction 3.4.0", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-signature", "solana-signer", - "solana-sysvar", + "solana-sysvar 3.1.1", "solana-transaction", "thiserror 2.0.18", "tokio", @@ -4222,7 +4320,7 @@ dependencies = [ "solana-hash 3.1.0", "solana-pubkey 3.0.0", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", "tokio", "tokio-util 0.7.17", @@ -4241,9 +4339,9 @@ dependencies = [ "memmap2 0.9.9", "parking_lot", "reflink-copy", - "solana-account", + "solana-account 3.4.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "tar", "thiserror 2.0.18", "tracing", @@ -4293,17 +4391,17 @@ dependencies = [ "parking_lot", "scc", "serde", - "solana-account", + "solana-account 3.4.0", "solana-account-decoder", "solana-fee-structure", "solana-keypair", - "solana-message", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-rpc-client-api", "solana-signature", "solana-system-transaction", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status", "sonic-rs", "thiserror 2.0.18", @@ -4318,7 +4416,7 @@ version = "0.12.0" dependencies = [ "agave-feature-set", "anyhow", - "borsh", + "borsh 1.6.0", "fd-lock", "magic-domain-program", "magicblock-account-cloner", @@ -4329,7 +4427,7 @@ dependencies = [ "magicblock-committor-service", "magicblock-config", "magicblock-core", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-ledger", "magicblock-magic-program-api 0.12.0", "magicblock-metrics", @@ -4341,32 +4439,32 @@ dependencies = [ "magicblock-validator-admin", "num_cpus", "paste", - "solana-account", - "solana-clock", + "solana-account 3.4.0", + "solana-clock 3.0.1", "solana-cluster-type 3.1.0", "solana-commitment-config", - "solana-feature-gate-interface", - "solana-fee-calculator", + "solana-feature-gate-interface 3.1.0", + "solana-fee-calculator 3.2.0", "solana-genesis-config", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", - "solana-message", - "solana-native-token", - "solana-program", - "solana-program-option", - "solana-program-pack", + "solana-message 3.1.0", + "solana-native-token 3.0.0", + "solana-program 3.0.0", + "solana-program-option 3.1.0", + "solana-program-pack 3.1.0", "solana-pubkey 3.0.0", "solana-rent 3.1.0", "solana-rpc-client", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-sha256-hasher 3.1.0", "solana-signature", "solana-signer", "solana-system-program", - "solana-sysvar", + "solana-sysvar 3.1.1", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "spl-token-interface", "thiserror 2.0.18", "tokio", @@ -4382,7 +4480,7 @@ dependencies = [ "arc-swap", "async-trait", "bincode", - "borsh", + "borsh 1.6.0", "futures-util", "helius-laserstream", "lru 0.16.2", @@ -4390,35 +4488,35 @@ dependencies = [ "magicblock-aml", "magicblock-config", "magicblock-core", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.0", "magicblock-metrics", "parking_lot", "scc", - "solana-account", + "solana-account 3.4.0", "solana-account-decoder", "solana-account-decoder-client-types", - "solana-address-lookup-table-interface", - "solana-clock", + "solana-address-lookup-table-interface 3.1.0", + "solana-clock 3.0.1", "solana-commitment-config", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", - "solana-loader-v3-interface", - "solana-loader-v4-interface", - "solana-message", - "solana-program", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", + "solana-message 3.1.0", + "solana-program 3.0.0", "solana-pubkey 3.0.0", "solana-pubsub-client", "solana-rent 3.1.0", "solana-rpc-client", "solana-rpc-client-api", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-signature", "solana-signer", "solana-system-interface 3.2.0", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "spl-token-2022-interface", "spl-token-interface", "thiserror 2.0.18", @@ -4434,13 +4532,13 @@ dependencies = [ name = "magicblock-committor-program" version = "0.12.0" dependencies = [ - "borsh", + "borsh 1.6.0", "paste", - "solana-account", - "solana-account-info", - "solana-program", + "solana-account 3.4.0", + "solana-account-info 3.1.1", + "solana-program 3.0.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-interface 3.2.0", "thiserror 2.0.18", ] @@ -4451,28 +4549,28 @@ version = "0.12.0" dependencies = [ "async-trait", "bincode", - "borsh", + "borsh 1.6.0", "futures-util", "lru 0.16.2", "magicblock-committor-program", "magicblock-core", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-metrics", "magicblock-program", "magicblock-rpc-client", "magicblock-table-mania", "rusqlite", - "solana-account", + "solana-account 3.4.0", "solana-account-decoder", - "solana-address-lookup-table-interface", + "solana-address-lookup-table-interface 3.1.0", "solana-commitment-config", "solana-compute-budget-interface", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", - "solana-message", + "solana-message 3.1.0", "solana-packet", - "solana-program", + "solana-program 3.0.0", "solana-pubkey 3.0.0", "solana-rpc-client", "solana-rpc-client-api", @@ -4480,7 +4578,7 @@ dependencies = [ "solana-signer", "solana-system-program", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "static_assertions", "thiserror 2.0.18", @@ -4503,7 +4601,7 @@ dependencies = [ "solana-keypair", "solana-pubkey 3.0.0", "solana-signer", - "toml", + "toml 0.8.23", "url", ] @@ -4516,17 +4614,17 @@ dependencies = [ "flume", "magicblock-magic-program-api 0.12.0", "serde", - "solana-account", + "solana-account 3.4.0", "solana-account-decoder", - "solana-clock", + "solana-clock 3.0.1", "solana-hash 3.1.0", - "solana-message", - "solana-program", + "solana-message 3.1.0", + "solana-program 3.0.0", "solana-pubkey 3.0.0", "solana-signature", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "spl-token-2022-interface", "spl-token-interface", @@ -4539,12 +4637,13 @@ dependencies = [ [[package]] name = "magicblock-delegation-program-api" version = "0.3.0" -source = "git+https://github.com/magicblock-labs/delegation-program.git?branch=snawaz%2Fupgrade#25386a7c1d406d06b8d07a4d5b0fd37d5e74213b" +source = "git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b#25386a7c1d406d06b8d07a4d5b0fd37d5e74213b" dependencies = [ "bincode", - "borsh", + "borsh 1.6.0", "bytemuck", "const-crypto", + "libsodium-rs", "num_enum", "pinocchio 0.10.2", "pinocchio-log", @@ -4553,10 +4652,11 @@ dependencies = [ "rkyv 0.7.45", "serde", "solana-address 2.6.0", - "solana-instruction", - "solana-loader-v3-interface", - "solana-program", - "solana-sdk-ids", + "solana-instruction 3.4.0", + "solana-loader-v3-interface 6.1.1", + "solana-program 3.0.0", + "solana-sdk", + "solana-sdk-ids 3.1.0", "solana-sha256-hasher 3.1.0", "solana-system-interface 2.0.0", "static_assertions", @@ -4566,11 +4666,13 @@ dependencies = [ [[package]] name = "magicblock-delegation-program-api" -version = "0.3.0" -source = "git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b#25386a7c1d406d06b8d07a4d5b0fd37d5e74213b" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "288904a9950bd20f27f0ef934f320ab1410bd35a6d5c9cf138eca276442b6b2e" dependencies = [ "bincode", - "borsh", + "borsh 0.10.4", + "borsh 1.6.0", "bytemuck", "const-crypto", "libsodium-rs", @@ -4582,16 +4684,17 @@ dependencies = [ "rkyv 0.7.45", "serde", "solana-address 2.6.0", - "solana-instruction", - "solana-loader-v3-interface", - "solana-program", + "solana-instruction 3.4.0", + "solana-loader-v3-interface 6.1.1", + "solana-program 3.0.0", + "solana-pubkey 2.4.0", "solana-sdk", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-sha256-hasher 3.1.0", "solana-system-interface 2.0.0", "static_assertions", "strum 0.27.2", - "thiserror 2.0.18", + "thiserror 1.0.69", ] [[package]] @@ -4612,10 +4715,10 @@ dependencies = [ "rocksdb", "serde", "solana-account-decoder", - "solana-clock", + "solana-clock 3.0.1", "solana-hash 3.1.0", - "solana-instruction", - "solana-message", + "solana-instruction 3.4.0", + "solana-message 3.1.0", "solana-metrics 2.3.13", "solana-pubkey 3.0.0", "solana-signature", @@ -4624,7 +4727,7 @@ dependencies = [ "solana-svm-measure", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status", "thiserror 2.0.18", "tokio", @@ -4634,12 +4737,14 @@ dependencies = [ [[package]] name = "magicblock-magic-program-api" -version = "0.9.0" -source = "git+https://github.com/magicblock-labs/magicblock-validator.git?branch=bmuddha%2Fepic%2Fmigration-solana-v3#ef8ebb18879f0a3c41c11159eb5a5358dd3c89c0" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dc8fba0307c90b91b70c9ed06d4242d6c4159f331b2f05bf8f875c2a94e0e98" dependencies = [ "bincode", + "const-crypto", "serde", - "solana-program", + "solana-program 3.0.0", "solana-signature", ] @@ -4650,7 +4755,7 @@ dependencies = [ "bincode", "const-crypto", "serde", - "solana-program", + "solana-program 3.0.0", "solana-signature", ] @@ -4686,28 +4791,28 @@ dependencies = [ "parking_lot", "rustc-hash 2.1.1", "serde", - "solana-account", + "solana-account 3.4.0", "solana-bpf-loader-program", "solana-compute-budget", "solana-compute-budget-instruction", "solana-compute-budget-program", - "solana-feature-gate-interface", + "solana-feature-gate-interface 3.1.0", "solana-fee-structure", - "solana-instruction", - "solana-loader-v3-interface", + "solana-instruction 3.4.0", + "solana-loader-v3-interface 6.1.1", "solana-loader-v4-program", "solana-precompile-error", - "solana-program", + "solana-program 3.0.0", "solana-program-runtime", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-svm", "solana-svm-callback", "solana-svm-transaction", "solana-system-program", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status", "solana-zk-elgamal-proof-program", "tokio", @@ -4722,30 +4827,30 @@ dependencies = [ "bincode", "lazy_static", "magicblock-core", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.0", "num-derive", "num-traits", "parking_lot", "serde", - "solana-account", - "solana-account-info", - "solana-clock", - "solana-fee-calculator", + "solana-account 3.4.0", + "solana-account-info 3.1.1", + "solana-clock 3.0.1", + "solana-fee-calculator 3.2.0", "solana-hash 3.1.0", - "solana-instruction", - "solana-instructions-sysvar", + "solana-instruction 3.4.0", + "solana-instructions-sysvar 3.0.0", "solana-keypair", - "solana-loader-v3-interface", - "solana-loader-v4-interface", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", "solana-program-runtime", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-seed-derivable", "solana-signature", "solana-signer", "solana-svm-log-collector", - "solana-sysvar", + "solana-sysvar 3.1.1", "solana-transaction", "solana-transaction-context", "thiserror 2.0.18", @@ -4768,7 +4873,7 @@ dependencies = [ "solana-hash 3.1.0", "solana-pubkey 3.0.0", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", "tokio", "tokio-util 0.7.17", @@ -4783,19 +4888,19 @@ dependencies = [ "futures-util", "magicblock-metrics", "serde_json", - "solana-account", + "solana-account 3.4.0", "solana-account-decoder-client-types", - "solana-address-lookup-table-interface", - "solana-clock", + "solana-address-lookup-table-interface 3.1.0", + "solana-clock 3.0.1", "solana-commitment-config", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-pubkey 3.0.0", "solana-pubsub-client", "solana-rpc-client", "solana-rpc-client-api", "solana-signature", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "thiserror 2.0.18", "tokio", @@ -4810,9 +4915,9 @@ dependencies = [ "futures-util", "magicblock-core", "magicblock-magic-program-api 0.12.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", - "solana-message", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-rpc-client", "solana-signature", @@ -4832,19 +4937,19 @@ dependencies = [ "magicblock-rpc-client", "rand 0.9.2", "sha3", - "solana-address-lookup-table-interface", - "solana-clock", + "solana-address-lookup-table-interface 3.1.0", + "solana-clock 3.0.1", "solana-commitment-config", "solana-compute-budget-interface", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", - "solana-message", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-signature", "solana-signer", - "solana-slot-hashes", + "solana-slot-hashes 3.0.1", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", "tokio", "tracing", @@ -4862,14 +4967,14 @@ dependencies = [ "magicblock-ledger", "magicblock-program", "rusqlite", - "solana-instruction", - "solana-message", + "solana-instruction 3.4.0", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-rpc-client", "solana-rpc-client-api", "solana-signature", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", "tokio", "tokio-util 0.7.17", @@ -4880,7 +4985,7 @@ dependencies = [ name = "magicblock-validator-admin" version = "0.12.0" dependencies = [ - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-program", "magicblock-rpc-client", "solana-commitment-config", @@ -5353,7 +5458,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.117", @@ -5667,7 +5772,7 @@ dependencies = [ "solana-address 2.6.0", "solana-define-syscall 4.0.1", "solana-instruction-view", - "solana-program-error", + "solana-program-error 3.0.0", ] [[package]] @@ -5818,6 +5923,15 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml 0.5.11", +] + [[package]] name = "proc-macro-crate" version = "3.4.0" @@ -5875,11 +5989,11 @@ name = "program-flexi-counter" version = "0.0.0" dependencies = [ "bincode", - "borsh", + "borsh 1.6.0", "ephemeral-rollups-sdk", "magicblock-magic-program-api 0.12.0", "serde", - "solana-program", + "solana-program 3.0.0", "solana-system-interface 3.2.0", ] @@ -5887,10 +6001,10 @@ dependencies = [ name = "program-mini" version = "0.0.0" dependencies = [ - "solana-program", + "solana-program 3.0.0", "solana-program-test", "solana-sdk", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-interface 3.2.0", "tokio", ] @@ -5899,12 +6013,12 @@ dependencies = [ name = "program-schedulecommit" version = "0.0.0" dependencies = [ - "borsh", + "borsh 1.6.0", "ephemeral-rollups-sdk", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.0", "rkyv 0.7.45", - "solana-program", + "solana-program 3.0.0", "solana-system-interface 3.2.0", "static_assertions", ] @@ -5913,10 +6027,10 @@ dependencies = [ name = "program-schedulecommit-security" version = "0.0.0" dependencies = [ - "borsh", + "borsh 1.6.0", "ephemeral-rollups-sdk", "program-schedulecommit", - "solana-program", + "solana-program 3.0.0", ] [[package]] @@ -6934,13 +7048,13 @@ name = "schedulecommit-client" version = "0.0.0" dependencies = [ "anyhow", - "borsh", + "borsh 1.6.0", "integration-test-tools", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "program-schedulecommit", "solana-commitment-config", "solana-compute-budget-interface", - "solana-program", + "solana-program 3.0.0", "solana-rpc-client", "solana-rpc-client-api", "solana-sdk", @@ -6953,25 +7067,25 @@ name = "schedulecommit-committor-service" version = "0.0.0" dependencies = [ "async-trait", - "borsh", + "borsh 1.6.0", "futures", "magicblock-committor-program", "magicblock-committor-service", "magicblock-core", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-program", "magicblock-rpc-client", "magicblock-table-mania", "program-flexi-counter", "program-schedulecommit", "rand 0.8.5", - "solana-account", + "solana-account 3.4.0", "solana-commitment-config", "solana-pubkey 3.0.0", "solana-rpc-client", "solana-rpc-client-api", "solana-sdk", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-interface 3.2.0", "test-kit", "tokio", @@ -6982,11 +7096,11 @@ dependencies = [ name = "schedulecommit-test-scenarios" version = "0.0.0" dependencies = [ - "borsh", + "borsh 1.6.0", "ephemeral-rollups-sdk", "integration-test-tools", "magicblock-core", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.0", "magicblock-program", "program-schedulecommit", @@ -6994,7 +7108,7 @@ dependencies = [ "schedulecommit-client", "serial_test", "solana-commitment-config", - "solana-program", + "solana-program 3.0.0", "solana-rpc-client", "solana-rpc-client-api", "solana-sdk", @@ -7007,7 +7121,7 @@ name = "schedulecommit-test-security" version = "0.0.0" dependencies = [ "integration-test-tools", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.0", "program-schedulecommit", "program-schedulecommit-security", @@ -7473,6 +7587,19 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "solana-account" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" +dependencies = [ + "solana-account-info 2.3.0", + "solana-clock 2.2.3", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", +] + [[package]] name = "solana-account" version = "3.4.0" @@ -7482,12 +7609,12 @@ dependencies = [ "qualifier_attr", "serde", "serde_bytes", - "solana-account-info", - "solana-clock", - "solana-instruction", + "solana-account-info 3.1.1", + "solana-clock 3.0.1", + "solana-instruction 3.4.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", - "solana-sysvar", + "solana-sdk-ids 3.1.0", + "solana-sysvar 3.1.1", ] [[package]] @@ -7503,26 +7630,26 @@ dependencies = [ "bv", "serde", "serde_json", - "solana-account", + "solana-account 3.4.0", "solana-account-decoder-client-types", - "solana-address-lookup-table-interface", - "solana-clock", + "solana-address-lookup-table-interface 3.1.0", + "solana-clock 3.0.1", "solana-config-interface", - "solana-epoch-schedule", - "solana-fee-calculator", - "solana-instruction", - "solana-loader-v3-interface", - "solana-nonce", - "solana-program-option", - "solana-program-pack", + "solana-epoch-schedule 3.1.0", + "solana-fee-calculator 3.2.0", + "solana-instruction 3.4.0", + "solana-loader-v3-interface 6.1.1", + "solana-nonce 3.1.0", + "solana-program-option 3.1.0", + "solana-program-pack 3.1.0", "solana-pubkey 3.0.0", "solana-rent 3.1.0", - "solana-sdk-ids", - "solana-slot-hashes", - "solana-slot-history", - "solana-stake-interface", - "solana-sysvar", - "solana-vote-interface", + "solana-sdk-ids 3.1.0", + "solana-slot-hashes 3.0.1", + "solana-slot-history 3.0.0", + "solana-stake-interface 2.0.2", + "solana-sysvar 3.1.1", + "solana-vote-interface 4.0.4", "spl-generic-token", "spl-token-2022-interface", "spl-token-group-interface", @@ -7542,11 +7669,24 @@ dependencies = [ "bs58", "serde", "serde_json", - "solana-account", + "solana-account 3.4.0", "solana-pubkey 3.0.0", "zstd", ] +[[package]] +name = "solana-account-info" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8f5152a288ef1912300fc6efa6c2d1f9bb55d9398eb6c72326360b8063987da" +dependencies = [ + "bincode", + "serde", + "solana-program-error 2.2.2", + "solana-program-memory 2.3.1", + "solana-pubkey 2.4.0", +] + [[package]] name = "solana-account-info" version = "3.1.1" @@ -7556,8 +7696,8 @@ dependencies = [ "bincode", "serde_core", "solana-address 2.6.0", - "solana-program-error", - "solana-program-memory", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", ] [[package]] @@ -7567,7 +7707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37ca34c37f92ee341b73d5ce7c8ef5bb38e9a87955b4bd343c63fa18b149215" dependencies = [ "solana-address 2.6.0", - "solana-program-error", + "solana-program-error 3.0.0", ] [[package]] @@ -7598,31 +7738,31 @@ dependencies = [ "seqlock", "serde", "smallvec", - "solana-account", - "solana-address-lookup-table-interface", + "solana-account 3.4.0", + "solana-address-lookup-table-interface 3.1.0", "solana-bucket-map", - "solana-clock", - "solana-epoch-schedule", - "solana-fee-calculator", + "solana-clock 3.0.1", + "solana-epoch-schedule 3.1.0", + "solana-fee-calculator 3.2.0", "solana-genesis-config", "solana-hash 3.1.0", "solana-lattice-hash", "solana-measure", - "solana-message", + "solana-message 3.1.0", "solana-metrics 3.1.12", "solana-nohash-hasher", "solana-pubkey 3.0.0", "solana-rayon-threadlimit", "solana-reward-info", "solana-sha256-hasher 3.1.0", - "solana-slot-hashes", + "solana-slot-hashes 3.0.1", "solana-svm-transaction", "solana-system-interface 2.0.0", - "solana-sysvar", + "solana-sysvar 3.1.1", "solana-time-utils 3.0.0", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "spl-generic-token", "static_assertions", "tempfile", @@ -7644,7 +7784,7 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1384b52c435a750cc9c538760fc7bb472fd78e65a9900a2d07312c5bb335b72" dependencies = [ - "borsh", + "borsh 1.6.0", "bytemuck", "bytemuck_derive", "curve25519-dalek 4.1.3", @@ -7657,12 +7797,29 @@ dependencies = [ "solana-atomic-u64 3.0.1", "solana-define-syscall 5.0.0", "solana-nullable", - "solana-program-error", + "solana-program-error 3.0.0", "solana-sanitize 3.0.1", "solana-sha256-hasher 3.1.0", "wincode 0.5.1", ] +[[package]] +name = "solana-address-lookup-table-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1673f67efe870b64a65cb39e6194be5b26527691ce5922909939961a6e6b395" +dependencies = [ + "bincode", + "bytemuck", + "serde", + "serde_derive", + "solana-clock 2.2.3", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-slot-hashes 2.2.1", +] + [[package]] name = "solana-address-lookup-table-interface" version = "3.1.0" @@ -7673,12 +7830,12 @@ dependencies = [ "bytemuck", "serde", "serde_derive", - "solana-clock", - "solana-instruction", + "solana-clock 3.0.1", + "solana-instruction 3.4.0", "solana-instruction-error", "solana-pubkey 4.2.0", - "solana-sdk-ids", - "solana-slot-hashes", + "solana-sdk-ids 3.1.0", + "solana-slot-hashes 3.0.1", ] [[package]] @@ -7705,22 +7862,22 @@ version = "3.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16034da9477c2ceb6bf03a04389d68f463fb9e09a7641b4517af4177976c5f59" dependencies = [ - "borsh", + "borsh 1.6.0", "futures", - "solana-account", + "solana-account 3.4.0", "solana-banks-interface", - "solana-clock", + "solana-clock 3.0.1", "solana-commitment-config", "solana-hash 3.1.0", - "solana-message", - "solana-program-pack", + "solana-message 3.1.0", + "solana-program-pack 3.1.0", "solana-pubkey 3.0.0", "solana-rent 3.1.0", "solana-signature", - "solana-sysvar", + "solana-sysvar 3.1.1", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "tarpc", "thiserror 2.0.18", "tokio", @@ -7734,16 +7891,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aeed8b00c1b30e10cada0de485c4c7aa2805bc54587d7fbfd4c89b9a6a2b7bb5" dependencies = [ "serde", - "solana-account", - "solana-clock", + "solana-account 3.4.0", + "solana-clock 3.0.1", "solana-commitment-config", "solana-hash 3.1.0", - "solana-message", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-signature", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "tarpc", ] @@ -7757,13 +7914,13 @@ dependencies = [ "bincode", "crossbeam-channel", "futures", - "solana-account", + "solana-account 3.4.0", "solana-banks-interface", "solana-client", - "solana-clock", + "solana-clock 3.0.1", "solana-commitment-config", "solana-hash 3.1.0", - "solana-message", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-runtime", "solana-runtime-transaction", @@ -7771,12 +7928,23 @@ dependencies = [ "solana-signature", "solana-svm", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "tarpc", "tokio", "tokio-serde", ] +[[package]] +name = "solana-big-mod-exp" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall 2.3.0", +] + [[package]] name = "solana-big-mod-exp" version = "3.0.0" @@ -7788,6 +7956,17 @@ dependencies = [ "solana-define-syscall 3.0.0", ] +[[package]] +name = "solana-bincode" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" +dependencies = [ + "bincode", + "serde", + "solana-instruction 2.3.3", +] + [[package]] name = "solana-bincode" version = "3.1.0" @@ -7799,6 +7978,18 @@ dependencies = [ "solana-instruction-error", ] +[[package]] +name = "solana-blake3-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0801e25a1b31a14494fc80882a036be0ffd290efc4c2d640bfcca120a4672" +dependencies = [ + "blake3", + "solana-define-syscall 2.3.0", + "solana-hash 2.3.0", + "solana-sanitize 2.2.1", +] + [[package]] name = "solana-blake3-hasher" version = "3.1.0" @@ -7855,7 +8046,7 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c04abbae16f57178a163125805637b8a076175bb5c0002fb04f4792bea901cf7" dependencies = [ - "borsh", + "borsh 1.6.0", ] [[package]] @@ -7867,18 +8058,18 @@ dependencies = [ "agave-syscalls", "bincode", "qualifier_attr", - "solana-account", - "solana-bincode", - "solana-clock", - "solana-instruction", - "solana-loader-v3-interface", - "solana-loader-v4-interface", + "solana-account 3.4.0", + "solana-bincode 3.1.0", + "solana-clock 3.0.1", + "solana-instruction 3.4.0", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", "solana-packet", - "solana-program-entrypoint", + "solana-program-entrypoint 3.1.1", "solana-program-runtime", "solana-pubkey 3.0.0", "solana-sbpf", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-svm-feature-set", "solana-svm-log-collector", "solana-svm-measure", @@ -7900,7 +8091,7 @@ dependencies = [ "modular-bitfield", "num_enum", "rand 0.8.5", - "solana-clock", + "solana-clock 3.0.1", "solana-measure", "solana-pubkey 3.0.0", "tempfile", @@ -7919,7 +8110,7 @@ dependencies = [ "solana-loader-v4-program", "solana-program-runtime", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-program", "solana-vote-program", "solana-zk-elgamal-proof-program", @@ -7939,7 +8130,7 @@ dependencies = [ "solana-compute-budget-program", "solana-loader-v4-program", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-program", "solana-vote-program", ] @@ -7960,16 +8151,16 @@ dependencies = [ "indicatif", "log", "rayon", - "solana-account", + "solana-account 3.4.0", "solana-client-traits", "solana-commitment-config", "solana-connection-cache", "solana-epoch-info", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", "solana-measure", - "solana-message", + "solana-message 3.1.0", "solana-net-utils", "solana-pubkey 3.0.0", "solana-pubsub-client", @@ -7984,7 +8175,7 @@ dependencies = [ "solana-time-utils 3.0.0", "solana-tpu-client", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "solana-udp-client", "thiserror 2.0.18", @@ -7998,19 +8189,32 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08618ed587e128105510c54ae3e456b9a06d674d8640db75afe66dad65cb4e02" dependencies = [ - "solana-account", + "solana-account 3.4.0", "solana-commitment-config", "solana-epoch-info", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", - "solana-message", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-signature", "solana-signer", "solana-system-interface 2.0.0", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", +] + +[[package]] +name = "solana-clock" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8584296123df8fe229b95e2ebfd37ae637fe9db9b7d4dd677ac5a78e80dbfce" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", ] [[package]] @@ -8021,9 +8225,9 @@ checksum = "95cf11109c3b6115cc510f1e31f06fdd52f504271bc24ef5f1249fbbcae5f9f3" dependencies = [ "serde", "serde_derive", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-sysvar-id 3.1.0", ] [[package]] @@ -8078,12 +8282,12 @@ dependencies = [ "solana-builtins-default-costs", "solana-compute-budget", "solana-compute-budget-interface", - "solana-instruction", + "solana-instruction 3.4.0", "solana-packet", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-svm-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", ] @@ -8093,9 +8297,9 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8292c436b269ad23cecc8b24f7da3ab07ca111661e25e00ce0e1d22771951ab9" dependencies = [ - "borsh", - "solana-instruction", - "solana-sdk-ids", + "borsh 1.6.0", + "solana-instruction 3.4.0", + "solana-sdk-ids 3.1.0", ] [[package]] @@ -8116,11 +8320,11 @@ dependencies = [ "bincode", "serde", "serde_derive", - "solana-account", - "solana-instruction", + "solana-account 3.4.0", + "solana-instruction 3.4.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", - "solana-short-vec", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.2.0", "solana-system-interface 2.0.0", ] @@ -8142,7 +8346,7 @@ dependencies = [ "solana-measure", "solana-metrics 3.1.12", "solana-time-utils 3.0.0", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", "tokio", ] @@ -8156,10 +8360,10 @@ dependencies = [ "agave-feature-set", "ahash 0.8.12", "log", - "solana-bincode", + "solana-bincode 3.1.0", "solana-borsh", "solana-builtins-default-costs", - "solana-clock", + "solana-clock 3.0.1", "solana-compute-budget", "solana-compute-budget-instruction", "solana-compute-budget-interface", @@ -8168,25 +8372,39 @@ dependencies = [ "solana-packet", "solana-pubkey 3.0.0", "solana-runtime-transaction", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-svm-transaction", "solana-system-interface 2.0.0", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-vote-program", ] +[[package]] +name = "solana-cpi" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc71126edddc2ba014622fc32d0f5e2e78ec6c5a1e0eb511b85618c09e9ea11" +dependencies = [ + "solana-account-info 2.3.0", + "solana-define-syscall 2.3.0", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-stable-layout 2.2.1", +] + [[package]] name = "solana-cpi" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" dependencies = [ - "solana-account-info", + "solana-account-info 3.1.1", "solana-define-syscall 4.0.1", - "solana-instruction", - "solana-program-error", + "solana-instruction 3.4.0", + "solana-program-error 3.0.0", "solana-pubkey 4.2.0", - "solana-stable-layout", + "solana-stable-layout 3.0.1", ] [[package]] @@ -8203,6 +8421,15 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "solana-decode-error" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c781686a18db2f942e70913f7ca15dc120ec38dcab42ff7557db2c70c625a35" +dependencies = [ + "num-traits", +] + [[package]] name = "solana-define-syscall" version = "2.3.0" @@ -8246,8 +8473,8 @@ checksum = "e1419197f1c06abf760043f6d64ba9d79a03ad5a43f18c7586471937122094da" dependencies = [ "bytemuck", "bytemuck_derive", - "solana-instruction", - "solana-sdk-ids", + "solana-instruction 3.4.0", + "solana-sdk-ids 3.1.0", ] [[package]] @@ -8260,6 +8487,20 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "solana-epoch-rewards" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b575d3dd323b9ea10bb6fe89bf6bf93e249b215ba8ed7f68f1a3633f384db7" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 2.3.0", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + [[package]] name = "solana-epoch-rewards" version = "3.0.1" @@ -8269,9 +8510,9 @@ dependencies = [ "serde", "serde_derive", "solana-hash 4.2.0", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-sysvar-id 3.1.0", ] [[package]] @@ -8285,6 +8526,19 @@ dependencies = [ "solana-hash 4.2.0", ] +[[package]] +name = "solana-epoch-schedule" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fce071fbddecc55d727b1d7ed16a629afe4f6e4c217bc8d00af3b785f6f67ed" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + [[package]] name = "solana-epoch-schedule" version = "3.1.0" @@ -8293,9 +8547,9 @@ checksum = "9ce264b7b42322325947c4136a09460bf5c73d9aa8262c9b0a2064be63ba8639" dependencies = [ "serde", "serde_derive", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-sysvar-id 3.1.0", ] [[package]] @@ -8308,6 +8562,27 @@ dependencies = [ "solana-pubkey 4.2.0", ] +[[package]] +name = "solana-example-mocks" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84461d56cbb8bb8d539347151e0525b53910102e4bced875d49d5139708e39d3" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface 2.2.2", + "solana-clock 2.2.3", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-keccak-hasher 2.2.1", + "solana-message 2.4.0", + "solana-nonce 2.2.1", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", + "thiserror 2.0.18", +] + [[package]] name = "solana-example-mocks" version = "3.0.0" @@ -8316,19 +8591,38 @@ checksum = "978855d164845c1b0235d4b4d101cadc55373fffaf0b5b6cfa2194d25b2ed658" dependencies = [ "serde", "serde_derive", - "solana-address-lookup-table-interface", - "solana-clock", + "solana-address-lookup-table-interface 3.1.0", + "solana-clock 3.0.1", "solana-hash 3.1.0", - "solana-instruction", - "solana-keccak-hasher", - "solana-message", - "solana-nonce", + "solana-instruction 3.4.0", + "solana-keccak-hasher 3.1.0", + "solana-message 3.1.0", + "solana-nonce 3.1.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-interface 2.0.0", "thiserror 2.0.18", ] +[[package]] +name = "solana-feature-gate-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f5c5382b449e8e4e3016fb05e418c53d57782d8b5c30aa372fc265654b956d" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account 2.2.1", + "solana-account-info 2.3.0", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", +] + [[package]] name = "solana-feature-gate-interface" version = "3.1.0" @@ -8338,13 +8632,13 @@ dependencies = [ "bincode", "serde", "serde_derive", - "solana-account", - "solana-account-info", - "solana-instruction", - "solana-program-error", + "solana-account 3.4.0", + "solana-account-info 3.1.1", + "solana-instruction 3.4.0", + "solana-program-error 3.0.0", "solana-pubkey 4.2.0", "solana-rent 4.2.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-interface 3.2.0", ] @@ -8359,6 +8653,17 @@ dependencies = [ "solana-svm-transaction", ] +[[package]] +name = "solana-fee-calculator" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89bc408da0fb3812bc3008189d148b4d3e08252c79ad810b245482a3f70cd8d" +dependencies = [ + "log", + "serde", + "serde_derive", +] + [[package]] name = "solana-fee-calculator" version = "3.2.0" @@ -8402,18 +8707,18 @@ dependencies = [ "memmap2 0.5.10", "serde", "serde_derive", - "solana-account", - "solana-clock", + "solana-account 3.4.0", + "solana-clock 3.0.1", "solana-cluster-type 3.1.0", - "solana-epoch-schedule", - "solana-fee-calculator", + "solana-epoch-schedule 3.1.0", + "solana-fee-calculator 3.2.0", "solana-hash 3.1.0", "solana-inflation", "solana-keypair", "solana-poh-config", "solana-pubkey 3.0.0", "solana-rent 3.1.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-sha256-hasher 3.1.0", "solana-shred-version", "solana-signer", @@ -8436,8 +8741,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b96e9f0300fa287b545613f007dfe20043d7812bee255f418c1eb649c93b63" dependencies = [ + "bytemuck", + "bytemuck_derive", "five8 0.2.1", "js-sys", + "serde", + "serde_derive", "solana-atomic-u64 2.2.1", "solana-sanitize 2.2.1", "wasm-bindgen", @@ -8458,7 +8767,7 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8064ea1d591ec791be95245058ca40f4f5345d390c200069d0f79bbf55bfae55" dependencies = [ - "borsh", + "borsh 1.6.0", "bytemuck", "bytemuck_derive", "five8 1.0.0", @@ -8479,6 +8788,24 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "solana-instruction" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab5682934bd1f65f8d2c16f21cb532526fcc1a09f796e2cacdb091eee5774ad" +dependencies = [ + "bincode", + "getrandom 0.2.16", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "serde_json", + "solana-define-syscall 2.3.0", + "solana-pubkey 2.4.0", + "wasm-bindgen", +] + [[package]] name = "solana-instruction" version = "3.4.0" @@ -8486,7 +8813,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37ebb0ffd19263051bc3f683fcc086134b8ff23af894dcb63f7563c7137b42f1" dependencies = [ "bincode", - "borsh", + "borsh 1.6.0", "serde", "serde_derive", "solana-define-syscall 5.0.0", @@ -8503,7 +8830,7 @@ dependencies = [ "num-traits", "serde", "serde_derive", - "solana-program-error", + "solana-program-error 3.0.0", ] [[package]] @@ -8515,7 +8842,24 @@ dependencies = [ "solana-account-view", "solana-address 2.6.0", "solana-define-syscall 4.0.1", - "solana-program-error", + "solana-program-error 3.0.0", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0e85a6fad5c2d0c4f5b91d34b8ca47118fc593af706e523cdbedf846a954f57" +dependencies = [ + "bitflags 2.10.0", + "solana-account-info 2.3.0", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-serialize-utils 2.2.1", + "solana-sysvar-id 2.2.1", ] [[package]] @@ -8525,20 +8869,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ddf67876c541aa1e21ee1acae35c95c6fbc61119814bfef70579317a5e26955" dependencies = [ "bitflags 2.10.0", - "solana-account-info", - "solana-instruction", + "solana-account-info 3.1.1", + "solana-instruction 3.4.0", "solana-instruction-error", - "solana-program-error", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", "solana-sanitize 3.0.1", - "solana-sdk-ids", - "solana-serialize-utils", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-serialize-utils 3.1.1", + "solana-sysvar-id 3.1.0", ] [[package]] name = "solana-keccak-hasher" -version = "3.1.0" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7aeb957fbd42a451b99235df4942d96db7ef678e8d5061ef34c9b34cae12f79" +dependencies = [ + "sha3", + "solana-define-syscall 2.3.0", + "solana-hash 2.3.0", + "solana-sanitize 2.2.1", +] + +[[package]] +name = "solana-keccak-hasher" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed1c0d16d6fdeba12291a1f068cdf0d479d9bff1141bf44afd7aa9d485f65ef8" dependencies = [ @@ -8565,6 +8921,19 @@ dependencies = [ "solana-signer", ] +[[package]] +name = "solana-last-restart-slot" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6360ac2fdc72e7463565cd256eedcf10d7ef0c28a1249d261ec168c1b55cdd" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + [[package]] name = "solana-last-restart-slot" version = "3.0.0" @@ -8573,9 +8942,9 @@ checksum = "dcda154ec827f5fc1e4da0af3417951b7e9b8157540f81f936c4a8b1156134d0" dependencies = [ "serde", "serde_derive", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-sysvar-id 3.1.0", ] [[package]] @@ -8590,6 +8959,20 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "solana-loader-v2-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ab08006dad78ae7cd30df8eea0539e207d08d91eaefb3e1d49a446e1c49654" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", +] + [[package]] name = "solana-loader-v2-interface" version = "3.0.0" @@ -8599,9 +8982,24 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "solana-instruction", + "solana-instruction 3.4.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f7162a05b8b0773156b443bccd674ea78bb9aa406325b467ea78c06c99a63a2" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", ] [[package]] @@ -8613,12 +9011,27 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "solana-instruction", + "solana-instruction 3.4.0", "solana-pubkey 4.2.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-interface 3.2.0", ] +[[package]] +name = "solana-loader-v4-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706a777242f1f39a83e2a96a2a6cb034cb41169c6ecbee2cf09cb873d9659e7e" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", +] + [[package]] name = "solana-loader-v4-interface" version = "3.1.0" @@ -8628,9 +9041,9 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "solana-instruction", + "solana-instruction 3.4.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-interface 2.0.0", ] @@ -8641,17 +9054,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e88b98ba6b408fe6fcf180784fc378d07ae63100c7dd413ff97474b6de30c5d" dependencies = [ "log", - "solana-account", - "solana-bincode", + "solana-account 3.4.0", + "solana-bincode 3.1.0", "solana-bpf-loader-program", - "solana-instruction", - "solana-loader-v3-interface", - "solana-loader-v4-interface", + "solana-instruction 3.4.0", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", "solana-packet", "solana-program-runtime", "solana-pubkey 3.0.0", "solana-sbpf", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-svm-log-collector", "solana-svm-measure", "solana-svm-type-overrides", @@ -8664,6 +9077,29 @@ version = "3.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de496c3f0e0cee33abd4ae958a8703e04ae1011f3c3e73b641bf319a18301c01" +[[package]] +name = "solana-message" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1796aabce376ff74bf89b78d268fa5e683d7d7a96a0a4e4813ec34de49d5314b" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-bincode 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-short-vec 2.2.1", + "solana-system-interface 1.0.0", + "solana-transaction-error 2.2.1", + "wasm-bindgen", +] + [[package]] name = "solana-message" version = "3.1.0" @@ -8677,11 +9113,11 @@ dependencies = [ "serde_derive", "solana-address 2.6.0", "solana-hash 4.2.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-sanitize 3.0.1", - "solana-sdk-ids", - "solana-short-vec", - "solana-transaction-error", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.2.0", + "solana-transaction-error 3.1.0", ] [[package]] @@ -8716,6 +9152,15 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "solana-msg" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36a1a14399afaabc2781a1db09cb14ee4cc4ee5c7a5a3cfcc601811379a8092" +dependencies = [ + "solana-define-syscall 2.3.0", +] + [[package]] name = "solana-msg" version = "3.1.0" @@ -8725,6 +9170,12 @@ dependencies = [ "solana-define-syscall 5.0.0", ] +[[package]] +name = "solana-native-token" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61515b880c36974053dd499c0510066783f0cc6ac17def0c7ef2a244874cf4a9" + [[package]] name = "solana-native-token" version = "3.0.0" @@ -8760,6 +9211,20 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" +[[package]] +name = "solana-nonce" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-pubkey 2.4.0", + "solana-sha256-hasher 2.2.1", +] + [[package]] name = "solana-nonce" version = "3.1.0" @@ -8768,7 +9233,7 @@ checksum = "cbc469152a63284ef959b80c59cda015262a021da55d3b8fe42171d89c4b64f8" dependencies = [ "serde", "serde_derive", - "solana-fee-calculator", + "solana-fee-calculator 3.2.0", "solana-hash 4.2.0", "solana-pubkey 4.2.0", "solana-sha256-hasher 3.1.0", @@ -8780,10 +9245,10 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "805fd25b29e5a1a0e6c3dd6320c9da80f275fbe4ff6e392617c303a2085c435e" dependencies = [ - "solana-account", + "solana-account 3.4.0", "solana-hash 3.1.0", - "solana-nonce", - "solana-sdk-ids", + "solana-nonce 3.1.0", + "solana-sdk-ids 3.1.0", ] [[package]] @@ -8846,13 +9311,13 @@ dependencies = [ "rayon", "serde", "solana-hash 3.1.0", - "solana-message", + "solana-message 3.1.0", "solana-metrics 3.1.12", "solana-packet", "solana-pubkey 3.0.0", "solana-rayon-threadlimit", - "solana-sdk-ids", - "solana-short-vec", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.2.0", "solana-signature", "solana-time-utils 3.0.0", "solana-transaction-context", @@ -8902,6 +9367,83 @@ dependencies = [ "solana-signer", ] +[[package]] +name = "solana-program" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98eca145bd3545e2fbb07166e895370576e47a00a7d824e325390d33bf467210" +dependencies = [ + "bincode", + "blake3", + "bs58", + "bytemuck", + "console_error_panic_hook", + "console_log", + "getrandom 0.2.16", + "lazy_static", + "log", + "memoffset", + "num-bigint 0.4.6", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info 2.3.0", + "solana-address-lookup-table-interface 2.2.2", + "solana-atomic-u64 2.2.1", + "solana-big-mod-exp 2.2.1", + "solana-bincode 2.2.1", + "solana-blake3-hasher 2.2.1", + "solana-clock 2.2.3", + "solana-cpi 2.2.1", + "solana-decode-error", + "solana-define-syscall 2.3.0", + "solana-epoch-rewards 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-example-mocks 2.2.1", + "solana-feature-gate-interface 2.2.2", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-instructions-sysvar 2.2.2", + "solana-keccak-hasher 2.2.1", + "solana-last-restart-slot 2.2.1", + "solana-loader-v2-interface 2.2.1", + "solana-loader-v3-interface 5.0.0", + "solana-loader-v4-interface 2.2.1", + "solana-message 2.4.0", + "solana-msg 2.2.1", + "solana-native-token 2.3.0", + "solana-nonce 2.2.1", + "solana-program-entrypoint 2.3.0", + "solana-program-error 2.2.2", + "solana-program-memory 2.3.1", + "solana-program-option 2.2.1", + "solana-program-pack 2.2.1", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-secp256k1-recover 2.2.1", + "solana-serde-varint 2.2.2", + "solana-serialize-utils 2.2.1", + "solana-sha256-hasher 2.2.1", + "solana-short-vec 2.2.1", + "solana-slot-hashes 2.2.1", + "solana-slot-history 2.2.1", + "solana-stable-layout 2.2.1", + "solana-stake-interface 1.2.1", + "solana-system-interface 1.0.0", + "solana-sysvar 2.3.0", + "solana-sysvar-id 2.2.1", + "solana-vote-interface 2.2.6", + "thiserror 2.0.18", + "wasm-bindgen", +] + [[package]] name = "solana-program" version = "3.0.0" @@ -8909,44 +9451,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91b12305dd81045d705f427acd0435a2e46444b65367d7179d7bdcfc3bc5f5eb" dependencies = [ "memoffset", - "solana-account-info", - "solana-big-mod-exp", - "solana-blake3-hasher", + "solana-account-info 3.1.1", + "solana-big-mod-exp 3.0.0", + "solana-blake3-hasher 3.1.0", "solana-borsh", - "solana-clock", - "solana-cpi", + "solana-clock 3.0.1", + "solana-cpi 3.1.0", "solana-define-syscall 3.0.0", - "solana-epoch-rewards", - "solana-epoch-schedule", + "solana-epoch-rewards 3.0.1", + "solana-epoch-schedule 3.1.0", "solana-epoch-stake", - "solana-example-mocks", - "solana-fee-calculator", + "solana-example-mocks 3.0.0", + "solana-fee-calculator 3.2.0", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-instruction-error", - "solana-instructions-sysvar", - "solana-keccak-hasher", - "solana-last-restart-slot", - "solana-msg", - "solana-native-token", - "solana-program-entrypoint", - "solana-program-error", - "solana-program-memory", - "solana-program-option", - "solana-program-pack", + "solana-instructions-sysvar 3.0.0", + "solana-keccak-hasher 3.1.0", + "solana-last-restart-slot 3.0.0", + "solana-msg 3.1.0", + "solana-native-token 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", + "solana-program-option 3.1.0", + "solana-program-pack 3.1.0", "solana-pubkey 3.0.0", "solana-rent 3.1.0", - "solana-sdk-ids", - "solana-secp256k1-recover", - "solana-serde-varint", - "solana-serialize-utils", + "solana-sdk-ids 3.1.0", + "solana-secp256k1-recover 3.1.1", + "solana-serde-varint 3.0.1", + "solana-serialize-utils 3.1.1", "solana-sha256-hasher 3.1.0", - "solana-short-vec", - "solana-slot-hashes", - "solana-slot-history", - "solana-stable-layout", - "solana-sysvar", - "solana-sysvar-id", + "solana-short-vec 3.2.0", + "solana-slot-hashes 3.0.1", + "solana-slot-history 3.0.0", + "solana-stable-layout 3.0.1", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", ] [[package]] @@ -8957,37 +9499,73 @@ checksum = "68d372660fc5c61b691279bcecb4bf92fa1a7cba3b357ef209404f425dafd394" dependencies = [ "bincode", "serde", - "solana-account", - "solana-loader-v3-interface", + "solana-account 3.4.0", + "solana-loader-v3-interface 6.1.1", "solana-pubkey 3.0.0", "solana-rent 3.1.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "spl-generic-token", ] +[[package]] +name = "solana-program-entrypoint" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ce041b1a0ed275290a5008ee1a4a6c48f5054c8a3d78d313c08958a06aedbd" +dependencies = [ + "solana-account-info 2.3.0", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", +] + [[package]] name = "solana-program-entrypoint" version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c9b0a1ff494e05f503a08b3d51150b73aa639544631e510279d6375f290997" dependencies = [ - "solana-account-info", + "solana-account-info 3.1.1", "solana-define-syscall 4.0.1", - "solana-program-error", + "solana-program-error 3.0.0", "solana-pubkey 4.2.0", ] +[[package]] +name = "solana-program-error" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee2e0217d642e2ea4bee237f37bd61bb02aec60da3647c48ff88f6556ade775" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-pubkey 2.4.0", +] + [[package]] name = "solana-program-error" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1af32c995a7b692a915bb7414d5f8e838450cf7c70414e763d8abcae7b51f28" dependencies = [ - "borsh", + "borsh 1.6.0", "serde", "serde_derive", ] +[[package]] +name = "solana-program-memory" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a5426090c6f3fd6cfdc10685322fede9ca8e5af43cd6a59e98bfe4e91671712" +dependencies = [ + "solana-define-syscall 2.3.0", +] + [[package]] name = "solana-program-memory" version = "3.1.0" @@ -8997,19 +9575,34 @@ dependencies = [ "solana-define-syscall 4.0.1", ] +[[package]] +name = "solana-program-option" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc677a2e9bc616eda6dbdab834d463372b92848b2bfe4a1ed4e4b4adba3397d0" + [[package]] name = "solana-program-option" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a88006a9b8594088cec9027ab77caaaa258a2aaa2083d3f086c44b42e50aeab" +[[package]] +name = "solana-program-pack" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319f0ef15e6e12dc37c597faccb7d62525a509fec5f6975ecb9419efddeb277b" +dependencies = [ + "solana-program-error 2.2.2", +] + [[package]] name = "solana-program-pack" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7701cb15b90667ae1c89ef4ac35a59c61e66ce58ddee13d729472af7f41d59" dependencies = [ - "solana-program-error", + "solana-program-error 3.0.0", ] [[package]] @@ -9024,24 +9617,24 @@ dependencies = [ "percentage", "rand 0.8.5", "serde", - "solana-account", - "solana-account-info", - "solana-clock", - "solana-epoch-rewards", - "solana-epoch-schedule", + "solana-account 3.4.0", + "solana-account-info 3.1.1", + "solana-clock 3.0.1", + "solana-epoch-rewards 3.0.1", + "solana-epoch-schedule 3.1.0", "solana-fee-structure", "solana-hash 3.1.0", - "solana-instruction", - "solana-last-restart-slot", - "solana-loader-v3-interface", - "solana-program-entrypoint", + "solana-instruction 3.4.0", + "solana-last-restart-slot 3.0.0", + "solana-loader-v3-interface 6.1.1", + "solana-program-entrypoint 3.1.1", "solana-pubkey 3.0.0", "solana-rent 3.1.0", "solana-sbpf", - "solana-sdk-ids", - "solana-slot-hashes", - "solana-stable-layout", - "solana-stake-interface", + "solana-sdk-ids 3.1.0", + "solana-slot-hashes 3.0.1", + "solana-stable-layout 3.0.1", + "solana-stake-interface 2.0.2", "solana-svm-callback", "solana-svm-feature-set", "solana-svm-log-collector", @@ -9050,8 +9643,8 @@ dependencies = [ "solana-svm-transaction", "solana-svm-type-overrides", "solana-system-interface 2.0.0", - "solana-sysvar", - "solana-sysvar-id", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", "solana-transaction-context", "thiserror 2.0.18", ] @@ -9072,55 +9665,81 @@ dependencies = [ "crossbeam-channel", "log", "serde", - "solana-account", - "solana-account-info", + "solana-account 3.4.0", + "solana-account-info 3.1.1", "solana-accounts-db", "solana-banks-client", "solana-banks-interface", "solana-banks-server", - "solana-clock", + "solana-clock 3.0.1", "solana-cluster-type 3.1.0", "solana-commitment-config", "solana-compute-budget", - "solana-epoch-rewards", - "solana-epoch-schedule", - "solana-fee-calculator", + "solana-epoch-rewards 3.0.1", + "solana-epoch-schedule 3.1.0", + "solana-fee-calculator 3.2.0", "solana-genesis-config", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", - "solana-loader-v3-interface", - "solana-message", - "solana-msg", - "solana-native-token", + "solana-loader-v3-interface 6.1.1", + "solana-message 3.1.0", + "solana-msg 3.1.0", + "solana-native-token 3.0.0", "solana-poh-config", "solana-program-binaries", - "solana-program-entrypoint", - "solana-program-error", + "solana-program-entrypoint 3.1.1", + "solana-program-error 3.0.0", "solana-program-runtime", "solana-pubkey 3.0.0", "solana-rent 3.1.0", "solana-runtime", "solana-sbpf", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-signer", - "solana-stable-layout", - "solana-stake-interface", + "solana-stable-layout 3.0.1", + "solana-stake-interface 2.0.2", "solana-svm", "solana-svm-log-collector", "solana-svm-timings", "solana-system-interface 2.0.0", - "solana-sysvar", - "solana-sysvar-id", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-vote-program", "spl-generic-token", "thiserror 2.0.18", "tokio", ] +[[package]] +name = "solana-pubkey" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b62adb9c3261a052ca1f999398c388f1daf558a1b492f60a6d9e64857db4ff1" +dependencies = [ + "borsh 0.10.4", + "borsh 1.6.0", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "five8 0.2.1", + "five8_const 0.1.4", + "getrandom 0.2.16", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-atomic-u64 2.2.1", + "solana-decode-error", + "solana-define-syscall 2.3.0", + "solana-sanitize 2.2.1", + "solana-sha256-hasher 2.2.1", + "wasm-bindgen", +] + [[package]] name = "solana-pubkey" version = "3.0.0" @@ -9154,7 +9773,7 @@ dependencies = [ "serde", "serde_json", "solana-account-decoder-client-types", - "solana-clock", + "solana-clock 3.0.1", "solana-pubkey 3.0.0", "solana-rpc-client-types", "solana-signature", @@ -9191,7 +9810,7 @@ dependencies = [ "solana-signer", "solana-streamer", "solana-tls-utils", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", "tokio", ] @@ -9215,6 +9834,19 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "solana-rent" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1aea8fdea9de98ca6e8c2da5827707fb3842833521b528a713810ca685d2480" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + [[package]] name = "solana-rent" version = "3.1.0" @@ -9223,9 +9855,9 @@ checksum = "e860d5499a705369778647e97d760f7670adfb6fc8419dd3d568deccd46d5487" dependencies = [ "serde", "serde_derive", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-sysvar-id 3.1.0", ] [[package]] @@ -9234,7 +9866,7 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9809b081e99bc142ce803bcd7ee18306759ce3b30a96a9da3f6f41c45e50ef0" dependencies = [ - "solana-sdk-macro", + "solana-sdk-macro 3.0.1", ] [[package]] @@ -9265,25 +9897,25 @@ dependencies = [ "semver", "serde", "serde_json", - "solana-account", + "solana-account 3.4.0", "solana-account-decoder", "solana-account-decoder-client-types", - "solana-clock", + "solana-clock 3.0.1", "solana-commitment-config", "solana-epoch-info", - "solana-epoch-schedule", - "solana-feature-gate-interface", + "solana-epoch-schedule 3.1.0", + "solana-feature-gate-interface 3.1.0", "solana-hash 3.1.0", - "solana-instruction", - "solana-message", + "solana-instruction 3.4.0", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-rpc-client-api", "solana-signature", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "solana-version", - "solana-vote-interface", + "solana-vote-interface 4.0.4", "tokio", ] @@ -9300,10 +9932,10 @@ dependencies = [ "serde", "serde_json", "solana-account-decoder-client-types", - "solana-clock", + "solana-clock 3.0.1", "solana-rpc-client-types", "solana-signer", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "thiserror 2.0.18", ] @@ -9314,14 +9946,14 @@ version = "3.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1fc7c6ad3eb7df35a1f97c820003439334ee0d5944b155e9cb78bf9e0ecce36" dependencies = [ - "solana-account", + "solana-account 3.4.0", "solana-commitment-config", "solana-hash 3.1.0", - "solana-message", - "solana-nonce", + "solana-message 3.1.0", + "solana-nonce 3.1.0", "solana-pubkey 3.0.0", "solana-rpc-client", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "thiserror 2.0.18", ] @@ -9336,16 +9968,16 @@ dependencies = [ "semver", "serde", "serde_json", - "solana-account", + "solana-account 3.4.0", "solana-account-decoder-client-types", "solana-address 1.1.0", - "solana-clock", + "solana-clock 3.0.1", "solana-commitment-config", - "solana-fee-calculator", + "solana-fee-calculator 3.2.0", "solana-inflation", "solana-reward-info", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "solana-version", "spl-generic-token", @@ -9400,16 +10032,16 @@ dependencies = [ "serde", "serde_json", "serde_with", - "solana-account", - "solana-account-info", + "solana-account 3.4.0", + "solana-account-info 3.1.1", "solana-accounts-db", - "solana-address-lookup-table-interface", + "solana-address-lookup-table-interface 3.1.0", "solana-bls-signatures", "solana-bpf-loader-program", "solana-bucket-map", "solana-builtins", "solana-client-traits", - "solana-clock", + "solana-clock 3.0.1", "solana-cluster-type 3.1.0", "solana-commitment-config", "solana-compute-budget", @@ -9417,30 +10049,30 @@ dependencies = [ "solana-compute-budget-interface", "solana-config-interface", "solana-cost-model", - "solana-cpi", + "solana-cpi 3.1.0", "solana-ed25519-program", "solana-epoch-info", "solana-epoch-rewards-hasher", - "solana-epoch-schedule", - "solana-feature-gate-interface", + "solana-epoch-schedule 3.1.0", + "solana-feature-gate-interface 3.1.0", "solana-fee", - "solana-fee-calculator", + "solana-fee-calculator 3.2.0", "solana-fee-structure", "solana-genesis-config", "solana-hard-forks", "solana-hash 3.1.0", "solana-inflation", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", "solana-lattice-hash", - "solana-loader-v3-interface", - "solana-loader-v4-interface", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", "solana-measure", - "solana-message", + "solana-message 3.1.0", "solana-metrics 3.1.12", - "solana-native-token", + "solana-native-token 3.0.0", "solana-nohash-hasher", - "solana-nonce", + "solana-nonce 3.1.0", "solana-nonce-account", "solana-packet", "solana-perf", @@ -9452,33 +10084,33 @@ dependencies = [ "solana-rent 3.1.0", "solana-reward-info", "solana-runtime-transaction", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-secp256k1-program", "solana-seed-derivable", "solana-serde", "solana-sha256-hasher 3.1.0", "solana-signature", "solana-signer", - "solana-slot-hashes", - "solana-slot-history", - "solana-stake-interface", + "solana-slot-hashes 3.0.1", + "solana-slot-history 3.0.0", + "solana-stake-interface 2.0.2", "solana-svm", "solana-svm-callback", "solana-svm-timings", "solana-svm-transaction", "solana-system-interface 2.0.0", "solana-system-transaction", - "solana-sysvar", - "solana-sysvar-id", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", "solana-time-utils 3.0.0", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "solana-unified-scheduler-logic", "solana-version", "solana-vote", - "solana-vote-interface", + "solana-vote-interface 4.0.4", "solana-vote-program", "spl-generic-token", "static_assertions", @@ -9500,14 +10132,14 @@ dependencies = [ "solana-compute-budget", "solana-compute-budget-instruction", "solana-hash 3.1.0", - "solana-message", + "solana-message 3.1.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-signature", "solana-svm-transaction", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", ] @@ -9549,35 +10181,44 @@ dependencies = [ "bincode", "bs58", "serde", - "solana-account", + "solana-account 3.4.0", "solana-epoch-info", "solana-epoch-rewards-hasher", "solana-fee-structure", "solana-inflation", "solana-keypair", - "solana-message", + "solana-message 3.1.0", "solana-offchain-message", "solana-presigner", - "solana-program", - "solana-program-memory", + "solana-program 3.0.0", + "solana-program-memory 3.1.0", "solana-pubkey 3.0.0", "solana-sanitize 3.0.1", - "solana-sdk-ids", - "solana-sdk-macro", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", "solana-seed-derivable", "solana-seed-phrase", "solana-serde", - "solana-serde-varint", - "solana-short-vec", + "solana-serde-varint 3.0.1", + "solana-short-vec 3.2.0", "solana-shred-version", "solana-signature", "solana-signer", "solana-time-utils 3.0.0", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", ] +[[package]] +name = "solana-sdk-ids" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5d8b9cc68d5c88b062a33e23a6466722467dde0035152d8fb1afbcdf350a5f" +dependencies = [ + "solana-pubkey 2.4.0", +] + [[package]] name = "solana-sdk-ids" version = "3.1.0" @@ -9587,6 +10228,18 @@ dependencies = [ "solana-address 2.6.0", ] +[[package]] +name = "solana-sdk-macro" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86280da8b99d03560f6ab5aca9de2e38805681df34e0bb8f238e69b29433b9df" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "solana-sdk-macro" version = "3.0.1" @@ -9613,6 +10266,17 @@ dependencies = [ "solana-signature", ] +[[package]] +name = "solana-secp256k1-recover" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" +dependencies = [ + "libsecp256k1", + "solana-define-syscall 2.3.0", + "thiserror 2.0.18", +] + [[package]] name = "solana-secp256k1-recover" version = "3.1.1" @@ -9632,8 +10296,8 @@ checksum = "445d8e12592631d76fc4dc57858bae66c9fd7cc838c306c62a472547fc9d0ce6" dependencies = [ "bytemuck", "openssl", - "solana-instruction", - "solana-sdk-ids", + "solana-instruction 3.4.0", + "solana-sdk-ids 3.1.0", ] [[package]] @@ -9667,7 +10331,7 @@ dependencies = [ "itertools 0.12.1", "log", "solana-client", - "solana-clock", + "solana-clock 3.0.1", "solana-connection-cache", "solana-hash 3.1.0", "solana-keypair", @@ -9693,6 +10357,15 @@ dependencies = [ "serde", ] +[[package]] +name = "solana-serde-varint" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a7e155eba458ecfb0107b98236088c3764a09ddf0201ec29e52a0be40857113" +dependencies = [ + "serde", +] + [[package]] name = "solana-serde-varint" version = "3.0.1" @@ -9702,6 +10375,17 @@ dependencies = [ "serde", ] +[[package]] +name = "solana-serialize-utils" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "817a284b63197d2b27afdba829c5ab34231da4a9b4e763466a003c40ca4f535e" +dependencies = [ + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", +] + [[package]] name = "solana-serialize-utils" version = "3.1.1" @@ -9735,6 +10419,15 @@ dependencies = [ "solana-hash 4.2.0", ] +[[package]] +name = "solana-short-vec" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c54c66f19b9766a56fa0057d060de8378676cb64987533fa088861858fc5a69" +dependencies = [ + "serde", +] + [[package]] name = "solana-short-vec" version = "3.2.0" @@ -9779,7 +10472,20 @@ checksum = "5bfea97951fee8bae0d6038f39a5efcb6230ecdfe33425ac75196d1a1e3e3235" dependencies = [ "solana-pubkey 3.0.0", "solana-signature", - "solana-transaction-error", + "solana-transaction-error 3.1.0", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8691982114513763e88d04094c9caa0376b867a29577939011331134c301ce" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 2.3.0", + "solana-sdk-ids 2.2.1", + "solana-sysvar-id 2.2.1", ] [[package]] @@ -9791,8 +10497,21 @@ dependencies = [ "serde", "serde_derive", "solana-hash 4.2.0", - "solana-sdk-ids", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-slot-history" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ccc1b2067ca22754d5283afb2b0126d61eae734fc616d23871b0943b0d935e" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sysvar-id 2.2.1", ] [[package]] @@ -9804,8 +10523,18 @@ dependencies = [ "bv", "serde", "serde_derive", - "solana-sdk-ids", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-stable-layout" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f14f7d02af8f2bc1b5efeeae71bc1c2b7f0f65cd75bcc7d8180f2c762a57f54" +dependencies = [ + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", ] [[package]] @@ -9814,10 +10543,29 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9f6a291ba063a37780af29e7db14bdd3dc447584d8ba5b3fc4b88e2bbc982fa" dependencies = [ - "solana-instruction", + "solana-instruction 3.4.0", "solana-pubkey 4.2.0", ] +[[package]] +name = "solana-stake-interface" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-clock 2.2.3", + "solana-cpi 2.2.1", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-system-interface 1.0.0", + "solana-sysvar-id 2.2.1", +] + [[package]] name = "solana-stake-interface" version = "2.0.2" @@ -9827,14 +10575,14 @@ dependencies = [ "num-traits", "serde", "serde_derive", - "solana-clock", - "solana-cpi", - "solana-instruction", - "solana-program-error", + "solana-clock 3.0.1", + "solana-cpi 3.1.0", + "solana-instruction 3.4.0", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", "solana-system-interface 2.0.0", - "solana-sysvar", - "solana-sysvar-id", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", ] [[package]] @@ -9848,12 +10596,12 @@ dependencies = [ "serde", "solana-account-decoder", "solana-hash 3.1.0", - "solana-instruction", - "solana-message", + "solana-instruction 3.4.0", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-signature", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status", "tonic-prost-build", ] @@ -9898,7 +10646,7 @@ dependencies = [ "solana-signer", "solana-time-utils 3.0.0", "solana-tls-utils", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-metrics-tracker", "thiserror 2.0.18", "tokio", @@ -9916,24 +10664,24 @@ dependencies = [ "percentage", "qualifier_attr", "serde", - "solana-account", - "solana-clock", + "solana-account 3.4.0", + "solana-clock 3.0.1", "solana-fee-structure", "solana-hash 3.1.0", - "solana-instruction", - "solana-instructions-sysvar", - "solana-loader-v3-interface", - "solana-loader-v4-interface", + "solana-instruction 3.4.0", + "solana-instructions-sysvar 3.0.0", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", "solana-loader-v4-program", - "solana-message", - "solana-nonce", + "solana-message 3.1.0", + "solana-nonce 3.1.0", "solana-nonce-account", - "solana-program-entrypoint", - "solana-program-pack", + "solana-program-entrypoint 3.1.1", + "solana-program-pack 3.1.0", "solana-program-runtime", "solana-pubkey 3.0.0", "solana-rent 3.1.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-svm-callback", "solana-svm-feature-set", "solana-svm-log-collector", @@ -9942,9 +10690,9 @@ dependencies = [ "solana-svm-transaction", "solana-svm-type-overrides", "solana-system-interface 2.0.0", - "solana-sysvar-id", + "solana-sysvar-id 3.1.0", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "spl-generic-token", "thiserror 2.0.18", ] @@ -9955,8 +10703,8 @@ version = "3.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb521c7f62db21661267a933f0d311a76b2b744a766b46f5a9a9395ce70f687c" dependencies = [ - "solana-account", - "solana-clock", + "solana-account 3.4.0", + "solana-clock 3.0.1", "solana-precompile-error", "solana-pubkey 3.0.0", ] @@ -10000,9 +10748,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ef6ff55ce4c24e26ad8b0e67bc604cbd54eabfc94540c4c2c93e51fa087ead5" dependencies = [ "solana-hash 3.1.0", - "solana-message", + "solana-message 3.1.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-signature", "solana-transaction", ] @@ -10016,6 +10764,22 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "solana-system-interface" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" +dependencies = [ + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "wasm-bindgen", +] + [[package]] name = "solana-system-interface" version = "2.0.0" @@ -10025,9 +10789,9 @@ dependencies = [ "num-traits", "serde", "serde_derive", - "solana-instruction", - "solana-msg", - "solana-program-error", + "solana-instruction 3.4.0", + "solana-msg 3.1.0", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", ] @@ -10041,9 +10805,9 @@ dependencies = [ "serde", "serde_derive", "solana-address 2.6.0", - "solana-instruction", - "solana-msg", - "solana-program-error", + "solana-instruction 3.4.0", + "solana-msg 3.1.0", + "solana-program-error 3.0.0", ] [[package]] @@ -10055,20 +10819,20 @@ dependencies = [ "bincode", "log", "serde", - "solana-account", - "solana-bincode", - "solana-fee-calculator", - "solana-instruction", - "solana-nonce", + "solana-account 3.4.0", + "solana-bincode 3.1.0", + "solana-fee-calculator 3.2.0", + "solana-instruction 3.4.0", + "solana-nonce 3.1.0", "solana-nonce-account", "solana-packet", "solana-program-runtime", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-svm-log-collector", "solana-svm-type-overrides", "solana-system-interface 2.0.0", - "solana-sysvar", + "solana-sysvar 3.1.1", "solana-transaction-context", ] @@ -10080,13 +10844,50 @@ checksum = "a31b5699ec533621515e714f1533ee6b3b0e71c463301d919eb59b8c1e249d30" dependencies = [ "solana-hash 3.1.0", "solana-keypair", - "solana-message", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-signer", "solana-system-interface 2.0.0", "solana-transaction", ] +[[package]] +name = "solana-sysvar" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c3595f95069f3d90f275bb9bd235a1973c4d059028b0a7f81baca2703815db" +dependencies = [ + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info 2.3.0", + "solana-clock 2.2.3", + "solana-define-syscall 2.3.0", + "solana-epoch-rewards 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-instructions-sysvar 2.2.2", + "solana-last-restart-slot 2.2.1", + "solana-program-entrypoint 2.3.0", + "solana-program-error 2.2.2", + "solana-program-memory 2.3.1", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-slot-hashes 2.2.1", + "solana-slot-history 2.2.1", + "solana-stake-interface 1.2.1", + "solana-sysvar-id 2.2.1", +] + [[package]] name = "solana-sysvar" version = "3.1.1" @@ -10100,25 +10901,35 @@ dependencies = [ "lazy_static", "serde", "serde_derive", - "solana-account-info", - "solana-clock", + "solana-account-info 3.1.1", + "solana-clock 3.0.1", "solana-define-syscall 4.0.1", - "solana-epoch-rewards", - "solana-epoch-schedule", - "solana-fee-calculator", + "solana-epoch-rewards 3.0.1", + "solana-epoch-schedule 3.1.0", + "solana-fee-calculator 3.2.0", "solana-hash 4.2.0", - "solana-instruction", - "solana-last-restart-slot", - "solana-program-entrypoint", - "solana-program-error", - "solana-program-memory", + "solana-instruction 3.4.0", + "solana-last-restart-slot 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", "solana-pubkey 4.2.0", "solana-rent 3.1.0", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-slot-hashes", - "solana-slot-history", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-slot-hashes 3.0.1", + "solana-slot-history 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-sysvar-id" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5762b273d3325b047cfda250787f8d796d781746860d5d0a746ee29f3e8812c1" +dependencies = [ + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", ] [[package]] @@ -10128,7 +10939,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" dependencies = [ "solana-address 2.6.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", ] [[package]] @@ -10170,12 +10981,12 @@ dependencies = [ "log", "rayon", "solana-client-traits", - "solana-clock", + "solana-clock 3.0.1", "solana-commitment-config", "solana-connection-cache", - "solana-epoch-schedule", + "solana-epoch-schedule 3.1.0", "solana-measure", - "solana-message", + "solana-message 3.1.0", "solana-net-utils", "solana-pubkey 3.0.0", "solana-pubsub-client", @@ -10185,7 +10996,7 @@ dependencies = [ "solana-signature", "solana-signer", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", "tokio", ] @@ -10201,7 +11012,7 @@ dependencies = [ "log", "lru 0.7.8", "rustls 0.23.35", - "solana-clock", + "solana-clock 3.0.1", "solana-connection-cache", "solana-keypair", "solana-measure", @@ -10228,15 +11039,15 @@ dependencies = [ "serde_derive", "solana-address 2.6.0", "solana-hash 4.2.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-instruction-error", - "solana-message", + "solana-message 3.1.0", "solana-sanitize 3.0.1", - "solana-sdk-ids", - "solana-short-vec", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.2.0", "solana-signature", "solana-signer", - "solana-transaction-error", + "solana-transaction-error 3.1.0", ] [[package]] @@ -10247,13 +11058,23 @@ dependencies = [ "bincode", "qualifier_attr", "serde", - "solana-account", - "solana-instruction", - "solana-instructions-sysvar", + "solana-account 3.4.0", + "solana-instruction 3.4.0", + "solana-instructions-sysvar 3.0.0", "solana-pubkey 3.0.0", "solana-rent 3.1.0", "solana-sbpf", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", +] + +[[package]] +name = "solana-transaction-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a9dc8fdb61c6088baab34fc3a8b8473a03a7a5fd404ed8dd502fa79b67cb1" +dependencies = [ + "solana-instruction 2.3.3", + "solana-sanitize 2.2.1", ] [[package]] @@ -10280,7 +11101,7 @@ dependencies = [ "rand 0.8.5", "solana-packet", "solana-perf", - "solana-short-vec", + "solana-short-vec 3.2.0", "solana-signature", ] @@ -10294,31 +11115,31 @@ dependencies = [ "agave-reserved-account-keys", "base64 0.22.1", "bincode", - "borsh", + "borsh 1.6.0", "bs58", "log", "serde", "serde_json", "solana-account-decoder", - "solana-address-lookup-table-interface", - "solana-clock", + "solana-address-lookup-table-interface 3.1.0", + "solana-clock 3.0.1", "solana-hash 3.1.0", - "solana-instruction", - "solana-loader-v2-interface", - "solana-loader-v3-interface", - "solana-message", - "solana-program-option", + "solana-instruction 3.4.0", + "solana-loader-v2-interface 3.0.0", + "solana-loader-v3-interface 6.1.1", + "solana-message 3.1.0", + "solana-program-option 3.1.0", "solana-pubkey 3.0.0", "solana-reward-info", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-signature", - "solana-stake-interface", + "solana-stake-interface 2.0.2", "solana-system-interface 2.0.0", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", - "solana-vote-interface", - "spl-associated-token-account-interface", + "solana-vote-interface 4.0.4", + "spl-associated-token-account-interface 2.0.0", "spl-memo-interface", "spl-token-2022-interface", "spl-token-group-interface", @@ -10340,14 +11161,14 @@ dependencies = [ "serde_json", "solana-account-decoder-client-types", "solana-commitment-config", - "solana-instruction", - "solana-message", + "solana-instruction 3.4.0", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-reward-info", "solana-signature", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", ] @@ -10362,7 +11183,7 @@ dependencies = [ "solana-keypair", "solana-net-utils", "solana-streamer", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", "tokio", ] @@ -10392,7 +11213,7 @@ dependencies = [ "semver", "serde", "solana-sanitize 3.0.1", - "solana-serde-varint", + "solana-serde-varint 3.0.1", ] [[package]] @@ -10404,24 +11225,48 @@ dependencies = [ "itertools 0.12.1", "log", "serde", - "solana-account", - "solana-bincode", - "solana-clock", + "solana-account 3.4.0", + "solana-bincode 3.1.0", + "solana-clock 3.0.1", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", "solana-packet", "solana-pubkey 3.0.0", - "solana-sdk-ids", - "solana-serialize-utils", + "solana-sdk-ids 3.1.0", + "solana-serialize-utils 3.1.1", "solana-signature", "solana-signer", "solana-svm-transaction", "solana-transaction", - "solana-vote-interface", + "solana-vote-interface 4.0.4", "thiserror 2.0.18", ] +[[package]] +name = "solana-vote-interface" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b80d57478d6599d30acc31cc5ae7f93ec2361a06aefe8ea79bc81739a08af4c3" +dependencies = [ + "bincode", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-clock 2.2.3", + "solana-decode-error", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-serde-varint 2.2.2", + "solana-serialize-utils 2.2.1", + "solana-short-vec 2.2.1", + "solana-system-interface 1.0.0", +] + [[package]] name = "solana-vote-interface" version = "4.0.4" @@ -10435,16 +11280,16 @@ dependencies = [ "serde", "serde_derive", "serde_with", - "solana-clock", + "solana-clock 3.0.1", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-instruction-error", "solana-pubkey 3.0.0", "solana-rent 3.1.0", - "solana-sdk-ids", - "solana-serde-varint", - "solana-serialize-utils", - "solana-short-vec", + "solana-sdk-ids 3.1.0", + "solana-serde-varint 3.0.1", + "solana-serialize-utils 3.1.1", + "solana-short-vec 3.2.0", "solana-system-interface 2.0.0", ] @@ -10460,23 +11305,23 @@ dependencies = [ "num-derive", "num-traits", "serde", - "solana-account", - "solana-bincode", - "solana-clock", - "solana-epoch-schedule", + "solana-account 3.4.0", + "solana-bincode 3.1.0", + "solana-clock 3.0.1", + "solana-epoch-schedule 3.1.0", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", "solana-packet", "solana-program-runtime", "solana-pubkey 3.0.0", "solana-rent 3.1.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-signer", - "solana-slot-hashes", + "solana-slot-hashes 3.0.1", "solana-transaction", "solana-transaction-context", - "solana-vote-interface", + "solana-vote-interface 4.0.4", "thiserror 2.0.18", ] @@ -10486,7 +11331,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5a91404c7de468dd80658cdb5d894ec803d1092ea6e2bfdf84eee6f07559c0d" dependencies = [ - "borsh", + "borsh 1.6.0", "bytemuck", "bytemuck_derive", ] @@ -10501,9 +11346,9 @@ dependencies = [ "bytemuck", "num-derive", "num-traits", - "solana-instruction", + "solana-instruction 3.4.0", "solana-program-runtime", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-svm-log-collector", "solana-zk-sdk", ] @@ -10532,9 +11377,9 @@ dependencies = [ "serde_json", "sha3", "solana-derivation-path", - "solana-instruction", + "solana-instruction 3.4.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-seed-derivable", "solana-seed-phrase", "solana-signature", @@ -10555,9 +11400,9 @@ dependencies = [ "bytemuck", "num-derive", "num-traits", - "solana-instruction", + "solana-instruction 3.4.0", "solana-program-runtime", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-svm-log-collector", "solana-zk-token-sdk", ] @@ -10584,9 +11429,9 @@ dependencies = [ "sha3", "solana-curve25519", "solana-derivation-path", - "solana-instruction", + "solana-instruction 3.4.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-seed-derivable", "solana-seed-phrase", "solana-signature", @@ -10663,14 +11508,24 @@ dependencies = [ "der", ] +[[package]] +name = "spl-associated-token-account-interface" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6bbe0794e532ac08428d3abf5bf8ae75bd81dfddd785c388e326c00c92c6f5" +dependencies = [ + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", +] + [[package]] name = "spl-associated-token-account-interface" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6433917b60441d68d99a17e121d9db0ea15a9a69c0e5afa34649cf5ba12612f" dependencies = [ - "borsh", - "solana-instruction", + "borsh 1.6.0", + "solana-instruction 3.4.0", "solana-pubkey 3.0.0", ] @@ -10681,7 +11536,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e597c5ff9ed7c74a54dbc47bae2f06e4db8c98f4356ad280200dc11878266db1" dependencies = [ "bytemuck", - "solana-program-error", + "solana-program-error 3.0.0", "solana-sha256-hasher 3.1.0", "spl-discriminator-derive", ] @@ -10726,7 +11581,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d4e2aedd58f858337fa609af5ad7100d4a243fdaf6a40d6eb4c28c5f19505d3" dependencies = [ - "solana-instruction", + "solana-instruction 3.4.0", "solana-pubkey 3.0.0", ] @@ -10736,14 +11591,14 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f9c6e142cdf1e7e77f480053ec9f0ce989890768ddf91f619b50f39d1b456f5" dependencies = [ - "borsh", + "borsh 1.6.0", "bytemuck", "bytemuck_derive", "num-derive", "num-traits", "num_enum", - "solana-program-error", - "solana-program-option", + "solana-program-error 3.0.0", + "solana-program-option 3.1.0", "solana-pubkey 3.0.0", "solana-zero-copy", "solana-zk-sdk", @@ -10761,13 +11616,13 @@ dependencies = [ "num-derive", "num-traits", "num_enum", - "solana-account-info", - "solana-instruction", - "solana-program-error", - "solana-program-option", - "solana-program-pack", + "solana-account-info 3.1.1", + "solana-instruction 3.4.0", + "solana-program-error 3.0.0", + "solana-program-option 3.1.0", + "solana-program-pack 3.1.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-zk-sdk", "spl-pod", "spl-token-confidential-transfer-proof-extraction", @@ -10785,14 +11640,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879a9ebad0d77383d3ea71e7de50503554961ff0f4ef6cbca39ad126e6f6da3a" dependencies = [ "bytemuck", - "solana-account-info", + "solana-account-info 3.1.1", "solana-curve25519", - "solana-instruction", - "solana-instructions-sysvar", - "solana-msg", - "solana-program-error", + "solana-instruction 3.4.0", + "solana-instructions-sysvar 3.0.0", + "solana-msg 3.1.0", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-zk-sdk", "spl-pod", "thiserror 2.0.18", @@ -10820,9 +11675,9 @@ dependencies = [ "num-traits", "num_enum", "solana-address 2.6.0", - "solana-instruction", + "solana-instruction 3.4.0", "solana-nullable", - "solana-program-error", + "solana-program-error 3.0.0", "solana-zero-copy", "spl-discriminator", "thiserror 2.0.18", @@ -10839,12 +11694,12 @@ dependencies = [ "num-derive", "num-traits", "num_enum", - "solana-instruction", - "solana-program-error", - "solana-program-option", - "solana-program-pack", + "solana-instruction 3.4.0", + "solana-program-error 3.0.0", + "solana-program-option 3.1.0", + "solana-program-pack 3.1.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "thiserror 2.0.18", ] @@ -10854,12 +11709,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c467c7c3bd056f8fe60119e7ec34ddd6f23052c2fa8f1f51999098063b72676" dependencies = [ - "borsh", + "borsh 1.6.0", "num-derive", "num-traits", "solana-borsh", - "solana-instruction", - "solana-program-error", + "solana-instruction 3.4.0", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", "spl-discriminator", "spl-pod", @@ -10877,8 +11732,8 @@ dependencies = [ "num-derive", "num-traits", "num_enum", - "solana-account-info", - "solana-program-error", + "solana-account-info 3.1.1", + "solana-program-error 3.0.0", "solana-zero-copy", "spl-discriminator", "thiserror 2.0.18", @@ -11042,7 +11897,7 @@ dependencies = [ name = "sysvars" version = "0.0.0" dependencies = [ - "solana-program", + "solana-program 3.0.0", ] [[package]] @@ -11131,30 +11986,55 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" +[[package]] +name = "test-aml" +version = "0.0.0" +dependencies = [ + "cleanass", + "ephemeral-rollups-sdk", + "integration-test-tools", + "magicblock-config", + "magicblock-core", + "magicblock-delegation-program-api 0.3.0", + "program-flexi-counter", + "program-mini", + "solana-loader-v4-interface 3.1.0", + "solana-sdk", + "solana-system-interface 3.2.0", + "spl-associated-token-account-interface 2.0.0", + "spl-memo-interface", + "spl-token-interface", + "tempfile", + "test-chainlink", + "test-kit", + "tokio", + "tracing", +] + [[package]] name = "test-chainlink" version = "0.0.0" dependencies = [ "bincode", - "borsh", + "borsh 1.6.0", "futures", "integration-test-tools", "magicblock-aml", "magicblock-chainlink", "magicblock-config", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "program-flexi-counter", "program-mini", - "solana-account", + "solana-account 3.4.0", "solana-commitment-config", - "solana-loader-v2-interface", - "solana-loader-v3-interface", - "solana-loader-v4-interface", + "solana-loader-v2-interface 3.0.0", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", "solana-pubkey 3.0.0", "solana-rpc-client", "solana-rpc-client-api", "solana-sdk", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-interface 3.2.0", "spl-token-interface", "tempfile", @@ -11168,13 +12048,13 @@ version = "0.0.0" dependencies = [ "integration-test-tools", "magicblock-core", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "program-flexi-counter", "program-mini", - "solana-loader-v4-interface", + "solana-loader-v4-interface 3.1.0", "solana-sdk", "solana-system-interface 3.2.0", - "spl-associated-token-account-interface", + "spl-associated-token-account-interface 2.0.0", "spl-memo-interface", "spl-token-interface", "test-chainlink", @@ -11195,7 +12075,7 @@ dependencies = [ "serial_test", "solana-rpc-client", "solana-sdk", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-interface 3.2.0", "tempfile", "test-kit", @@ -11211,15 +12091,15 @@ dependencies = [ "magicblock-core", "magicblock-ledger", "magicblock-processor", - "solana-account", - "solana-instruction", + "solana-account 3.4.0", + "solana-instruction 3.4.0", "solana-keypair", - "solana-program", + "solana-program 3.0.0", "solana-rpc-client", "solana-signature", "solana-signer", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "tempfile", "tokio", @@ -11238,12 +12118,12 @@ dependencies = [ "integration-test-tools", "magicblock-accounts-db", "magicblock-config", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "program-flexi-counter", "solana-commitment-config", "solana-rpc-client", "solana-sdk", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "solana-system-interface 3.2.0", "solana-transaction-status", "tempfile", @@ -11261,7 +12141,7 @@ dependencies = [ "magic-domain-program", "magicblock-api", "magicblock-config", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-program", "magicblock-validator-admin", "solana-commitment-config", @@ -11297,6 +12177,7 @@ dependencies = [ "ctrlc", "integration-test-tools", "teepee", + "tempfile", ] [[package]] @@ -11306,7 +12187,7 @@ dependencies = [ "ephemeral-rollups-sdk", "integration-test-tools", "log", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.0", "program-flexi-counter", "solana-rpc-client-api", @@ -11322,7 +12203,7 @@ dependencies = [ "magicblock-rpc-client", "magicblock-table-mania", "paste", - "solana-address-lookup-table-interface", + "solana-address-lookup-table-interface 3.1.0", "solana-commitment-config", "solana-pubkey 3.0.0", "solana-rpc-client", @@ -11621,6 +12502,15 @@ dependencies = [ "webpki-roots 0.26.11", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.23" diff --git a/test-integration/Cargo.toml b/test-integration/Cargo.toml index 10de745e0..592ab4a90 100644 --- a/test-integration/Cargo.toml +++ b/test-integration/Cargo.toml @@ -10,6 +10,7 @@ members = [ "schedulecommit/test-security", "test-chainlink", "test-cloning", + "test-aml", "test-committor-service", "test-config", "test-ledger-restore", @@ -36,8 +37,7 @@ chrono = "0.4" cleanass = "0.0.1" color-backtrace = { version = "0.7" } ctrlc = "3.4.7" -ephemeral-rollups-sdk = { git = "https://github.com/magicblock-labs/ephemeral-rollups-sdk.git", rev = "ccfc9f924dc40", default-features = false, features = [ - "disable-realloc", +ephemeral-rollups-sdk = { git = "https://github.com/magicblock-labs/ephemeral-rollups-sdk.git", rev = "cd3be977f402f3438ee920c959f7f7a5e02101f8", default-features = false, features = [ "modular-sdk", ] } futures = "0.3.31" diff --git a/test-integration/Makefile b/test-integration/Makefile index 25e1ca4f5..cde59eaaa 100644 --- a/test-integration/Makefile +++ b/test-integration/Makefile @@ -54,6 +54,15 @@ test-force-mb: $(PROGRAMS_SO) FORCE_MAGIC_BLOCK_VALIDATOR=1 \ cargo run --package test-runner --bin run-tests +test-aml: + RUN_TESTS=aml \ + $(MAKE) test +setup-aml-devnet: + RUST_LOG_STYLE=none \ + RUN_TESTS=aml \ + SETUP_ONLY=devnet \ + $(MAKE) test + test-schedulecommit: RUN_TESTS=schedulecommit \ $(MAKE) test @@ -274,6 +283,7 @@ ci-lint: lint list \ list-programs \ programs \ + setup-aml-devnet \ setup-chainlink-devnet \ setup-cloning-both \ setup-cloning-devnet \ @@ -296,6 +306,7 @@ ci-lint: lint setup-table-mania-devnet \ setup-task-scheduler-devnet \ test \ + test-aml \ test-chainlink \ test-cloning \ test-committor \ diff --git a/test-integration/configs/aml.devnet.toml b/test-integration/configs/aml.devnet.toml new file mode 100644 index 000000000..2b8f3dbdf --- /dev/null +++ b/test-integration/configs/aml.devnet.toml @@ -0,0 +1,65 @@ +lifecycle = "offline" +remotes = ["devnet"] + +[aperture] +listen = "0.0.0.0:7799" + +[commit] +compute-unit-price = 1_000_000 + +[accountsdb] +# size of the main storage, we have to preallocate in advance +# it's advised to set this value based on formula 1KB * N * 3, +# where N is the number of accounts expected to be stored in +# database, e.g. for million accounts this would be 3GB +database-size = 1048576000 # 1GB +# minimal indivisible unit of addressing in main storage +# offsets are calculated in terms of blocks +block-size = "block256" # possible values block128 | block256 | block512 +# size of index file, we have to preallocate, +# can be as low as 1% of main storage size, but setting it to higher values won't hurt +index-size = 20485760 +# max number of snapshots to keep around +max-snapshots = 7 + +[ledger] +reset = true +block-time = "50ms" + +[[programs]] +id = "3JnJ727jWEmPVU8qfXwtH63sCNDX7nMgsLbg8qy8aaPX" +path = "../programs/redline/redline.so" + +[[programs]] +id = "DELeGGvXpWV2fqJUhqcF5ZSYMS4JTLjteaAMARRSaeSh" +path = "../schedulecommit/elfs/dlp.so" + +[[programs]] +id = "DmnRGfyyftzacFb1XadYhWF6vWqXwtQk5tbr6XgR3BA1" +path = "../schedulecommit/elfs/mdp.so" + +[[programs]] +id = "SPLxh1LVZzEkX99H6rqYizhytLWPZVV296zyYDPagv2" +path = "../programs/ephemeral-token/ephemeral_token_program.so" + +[[programs]] +id = "MiniV31111111111111111111111111111111111111" +path = "../target/deploy/miniv3/program_mini.so" +auth = "MiniV3AUTH111111111111111111111111111111111" + +[[programs]] +id = "MiniV32111111111111111111111111111111111111" +path = "../target/deploy/miniv3/program_mini.so" +auth = "MiniV4AUTH211111111111111111111111111111111" + +[[programs]] +id = "MiniV33111111111111111111111111111111111111" +path = "../target/deploy/miniv3/program_mini.so" +auth = "MiniV4AUTH311111111111111111111111111111111" + +[[programs]] +id = "f1exzKGtdeVX3d6UXZ89cY7twiNJe9S5uq84RTA4Rq4" +path = "../target/deploy/program_flexi_counter.so" + +[metrics] +address = "0.0.0.0:9000" diff --git a/test-integration/test-aml/Cargo.toml b/test-integration/test-aml/Cargo.toml new file mode 100644 index 000000000..25e2aeabd --- /dev/null +++ b/test-integration/test-aml/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "test-aml" +version.workspace = true +edition.workspace = true + +[dependencies] +integration-test-tools = { workspace = true } +magicblock-core = { workspace = true } +magicblock-config = { workspace = true } +magicblock-delegation-program-api = { workspace = true, features = [ + "encryption", +] } +solana-sdk = { workspace = true } +solana-system-interface = { workspace = true } +tempfile = { workspace = true } +tokio = { workspace = true, features = ["full"] } + +[dev-dependencies] +cleanass = { workspace = true } +ephemeral-rollups-sdk = { workspace = true, features = ["spl", "modular-sdk"] } +program-flexi-counter = { workspace = true, features = ["no-entrypoint"] } +program-mini = { workspace = true, features = ["no-entrypoint"] } +tracing = { workspace = true } +test-chainlink = { workspace = true } +solana-loader-v4-interface = { workspace = true, features = ["serde"] } +spl-associated-token-account-interface = { workspace = true } +spl-token = { workspace = true } +spl-memo-interface = { workspace = true } +test-kit = { workspace = true } diff --git a/test-integration/test-aml/src/lib.rs b/test-integration/test-aml/src/lib.rs new file mode 100644 index 000000000..8ade82a29 --- /dev/null +++ b/test-integration/test-aml/src/lib.rs @@ -0,0 +1,341 @@ +use std::{ + collections::HashMap, + io::{self, Read, Write}, + net::TcpListener, + path::Path, + process::Child, + str::FromStr, + sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, RwLock, + }, + thread::{self, sleep}, + time::Duration, +}; + +use integration_test_tools::{ + expect, + loaded_accounts::{LoadedAccounts, DLP_TEST_AUTHORITY_BYTES}, + validator::{ + cleanup, resolve_programs, + start_magicblock_validator_with_config_struct, + }, + IntegrationTestContext, +}; +use magicblock_config::{ + config::{ + AccountsDbConfig, ChainLinkConfig, LedgerConfig, LifecycleMode, + LoadableProgram, RiskConfig, + }, + types::{Remote, StorageDirectory}, + ValidatorParams, +}; +use solana_sdk::{ + native_token::LAMPORTS_PER_SOL, pubkey::Pubkey, signature::Keypair, + signer::Signer, transaction::Transaction, +}; +use tempfile::TempDir; + +pub struct MockRangeServer { + base_url: String, + request_count: Arc, + shutdown: Arc, + worker: Option>, + risks: Arc>>, + requested_addresses: Arc>>, +} + +impl MockRangeServer { + pub fn start() -> io::Result { + let listener = TcpListener::bind("127.0.0.1:0")?; + listener.set_nonblocking(true)?; + let addr = listener.local_addr()?; + let request_count = Arc::new(AtomicUsize::new(0)); + let shutdown = Arc::new(AtomicBool::new(false)); + let worker_request_count = Arc::clone(&request_count); + let worker_shutdown = Arc::clone(&shutdown); + let risks = Arc::new(RwLock::new(HashMap::new())); + let requested_addresses = Arc::new(RwLock::new(Vec::new())); + + let worker_risks = Arc::clone(&risks); + let worker_requested_addresses = Arc::clone(&requested_addresses); + let worker = thread::spawn(move || { + while !worker_shutdown.load(Ordering::SeqCst) { + match listener.accept() { + Ok((mut stream, _)) => { + let mut buffer = [0u8; 4096]; + let read = stream.read(&mut buffer).unwrap_or(0); + let request = String::from_utf8_lossy(&buffer[..read]); + + let body = if request.starts_with("GET /risk/address?") + && request.contains("address=") + { + let address = request + .split("address=") + .nth(1) + .unwrap() + .split(['&', ' ']) + .next() + .unwrap(); + worker_requested_addresses + .write() + .unwrap() + .push(address.to_string()); + let risk_score = worker_risks + .read() + .unwrap() + .get(address) + .copied() + .unwrap_or(0); + worker_request_count.fetch_add(1, Ordering::SeqCst); + format!(r#"{{"riskScore":{risk_score}}}"#) + } else { + r#"{"error":"not found"}"#.to_string() + }; + let status = + if request.starts_with("GET /risk/address?") { + "200 OK" + } else { + "404 Not Found" + }; + let response = format!( + "HTTP/1.1 {status}\r\ncontent-type: application/json\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{}", + body.len(), + body + ); + let _ = stream.write_all(response.as_bytes()); + } + Err(err) if err.kind() == io::ErrorKind::WouldBlock => { + thread::sleep(Duration::from_millis(25)); + } + Err(_) => break, + } + } + }); + + Ok(Self { + base_url: format!("http://{addr}"), + request_count, + shutdown, + worker: Some(worker), + risks, + requested_addresses, + }) + } + + pub fn stop(&mut self) { + self.shutdown.store(true, Ordering::SeqCst); + if let Some(worker) = self.worker.take() { + let _ = worker.join(); + } + } + + pub fn set_risk(&self, address: &str, risk_score: u64) { + self.risks + .write() + .unwrap() + .insert(address.to_string(), risk_score); + } + + pub fn base_url(&self) -> &str { + &self.base_url + } + + pub fn request_count(&self) -> usize { + self.request_count.load(Ordering::SeqCst) + } + + pub fn requested_addresses(&self) -> Vec { + self.requested_addresses.read().unwrap().clone() + } +} + +impl Drop for MockRangeServer { + fn drop(&mut self) { + self.stop(); + } +} + +pub fn setup_validator_with_local_remote( + ledger_path: &Path, + programs: Option>, + reset_ledger: bool, + skip_keypair_match_check: bool, + loaded_accounts: &LoadedAccounts, + risk_base_url: String, +) -> (TempDir, Child, IntegrationTestContext) { + let accountsdb_config = AccountsDbConfig { + reset: reset_ledger, + ..Default::default() + }; + + let programs = resolve_programs(programs); + + let config = ValidatorParams { + ledger: LedgerConfig { + reset: reset_ledger, + verify_keypair: !skip_keypair_match_check, + ..Default::default() + }, + accountsdb: accountsdb_config.clone(), + programs, + lifecycle: LifecycleMode::Ephemeral, + remotes: vec![ + Remote::from_str(IntegrationTestContext::url_chain()).unwrap(), + Remote::from_str(IntegrationTestContext::ws_url_chain()).unwrap(), + ], + chainlink: ChainLinkConfig { + risk: RiskConfig { + enabled: true, + base_url: risk_base_url, + api_key: Some("test-api-key".to_string()), + ..Default::default() + }, + ..Default::default() + }, + storage: StorageDirectory(ledger_path.to_path_buf()), + ..Default::default() + }; + // Fund validator on chain + { + let chain_only_ctx = + IntegrationTestContext::try_new_chain_only().unwrap(); + + chain_only_ctx + .airdrop_chain( + &loaded_accounts.validator_authority(), + 20 * LAMPORTS_PER_SOL, + ) + .unwrap(); + + // Init fees vault for validator + init_validator_fees_vault( + &chain_only_ctx, + loaded_accounts.validator_authority_keypair(), + ); + chain_only_ctx + .ensure_magic_fee_vault_delegated_on_chain( + loaded_accounts.validator_authority_keypair(), + ) + .unwrap(); + } + + let (default_tmpdir_config, Some(mut validator), port) = + start_magicblock_validator_with_config_struct(config, loaded_accounts) + else { + panic!("validator should set up correctly"); + }; + + let ctx = expect!( + IntegrationTestContext::try_new_with_ephem_port(port), + validator + ); + (default_tmpdir_config, validator, ctx) +} + +/// Init validator fees vault for proper validator setup +pub fn init_validator_fees_vault( + chain_ctx: &IntegrationTestContext, + validator_identity: &Keypair, +) { + let vault_pda = dlp_api::pda::validator_fees_vault_pda_from_validator( + &validator_identity.pubkey(), + ); + if chain_ctx.fetch_chain_account(vault_pda).is_ok() { + // Account exists + return; + } + + // DLP authority in integration tests + let dlp_authority = + Keypair::try_from(&DLP_TEST_AUTHORITY_BYTES[..]).unwrap(); + + let latest_block_hash = chain_ctx.try_get_latest_blockhash_chain().unwrap(); + let ix = dlp_api::instruction_builder::init_validator_fees_vault( + validator_identity.pubkey(), + dlp_authority.pubkey(), + validator_identity.pubkey(), + ); + let mut tx = Transaction::new_signed_with_payer( + &[ix], + Some(&validator_identity.pubkey()), + &[validator_identity, &dlp_authority], + latest_block_hash, + ); + + chain_ctx + .send_and_confirm_transaction_chain( + &mut tx, + &[validator_identity, &dlp_authority], + ) + .unwrap(); +} + +pub fn token_balance_chain( + ctx: &IntegrationTestContext, + account: &Pubkey, +) -> u64 { + let balance = ctx + .try_chain_client() + .unwrap() + .get_token_account_balance(account) + .unwrap(); + balance.amount.parse::().unwrap() +} + +pub fn token_balance_ephem( + ctx: &IntegrationTestContext, + account: &Pubkey, +) -> Option { + ctx.try_ephem_client() + .unwrap() + .get_token_account_balance(account) + .ok() + .and_then(|balance| balance.amount.parse::().ok()) +} + +pub fn cleanup_both(validator: &mut Child, server: &mut MockRangeServer) { + cleanup(validator); + server.stop(); +} + +pub fn delegation_record_exists( + ctx: &IntegrationTestContext, + delegated_account: &Pubkey, +) -> bool { + let record_pubkey = + dlp_api::pda::delegation_record_pda_from_delegated_account( + delegated_account, + ); + ctx.fetch_chain_account(record_pubkey).is_ok() +} + +/// Polls until the delegation record for `delegated_account` disappears, +/// returning `true` if it did within the window. +pub fn wait_for_delegation_record_absent( + ctx: &IntegrationTestContext, + delegated_account: &Pubkey, +) -> bool { + for _ in 0..60 { + if !delegation_record_exists(ctx, delegated_account) { + return true; + } + sleep(Duration::from_millis(200)); + } + false +} + +/// Polls for a window asserting the delegation record stays present the whole +/// time, returning `false` if it ever disappears. +pub fn delegation_record_persists( + ctx: &IntegrationTestContext, + delegated_account: &Pubkey, +) -> bool { + for _ in 0..30 { + if !delegation_record_exists(ctx, delegated_account) { + return false; + } + sleep(Duration::from_millis(200)); + } + true +} diff --git a/test-integration/test-aml/tests/range_mock.rs b/test-integration/test-aml/tests/range_mock.rs new file mode 100644 index 000000000..dd3920c18 --- /dev/null +++ b/test-integration/test-aml/tests/range_mock.rs @@ -0,0 +1,282 @@ +use std::{thread::sleep, time::Duration}; + +use cleanass::assert; +use ephemeral_rollups_sdk::spl::{ + builders::{ + InitializeGlobalVaultBuilder, InitializeRentPdaBuilder, + SetupAndDelegateShuttleEphemeralAtaWithMergeBuilder, + }, + find_rent_pda, find_shuttle_ata, find_shuttle_ephemeral_ata, +}; +use integration_test_tools::{ + expect, + loaded_accounts::{LoadedAccounts, DLP_TEST_AUTHORITY_BYTES}, + tmpdir::resolve_tmp_dir, +}; +use magicblock_core::token_programs::derive_ata; +use solana_sdk::{ + program_pack::Pack, signature::Keypair, signer::Signer, + transaction::Transaction, +}; +use solana_system_interface::instruction as system_instruction; +use spl_associated_token_account_interface::instruction::create_associated_token_account_idempotent; +use spl_token::{instruction as spl_token_ix, state::Mint}; +use test_aml::{ + cleanup_both, delegation_record_exists, delegation_record_persists, + setup_validator_with_local_remote, wait_for_delegation_record_absent, + MockRangeServer, +}; +use test_kit::init_logger; + +const SHUTTLE_AMOUNT: u64 = 200; +const SHUTTLE_ID: u32 = 0; +const TMP_DIR_LEDGER: &str = "TMP_DIR_LEDGER"; + +#[test] +fn test_risky_shuttle_owner_merge_is_blocked() { + run_shuttle_merge_risk_case(9, false); +} + +#[test] +fn test_low_risk_shuttle_owner_merge_is_allowed() { + run_shuttle_merge_risk_case(1, true); +} + +/// Drives the shuttle + merge flow for a single owner risk score and asserts +/// the AML risk gate decision. +/// +/// `SetupAndDelegateShuttleEphemeralAtaWithMerge` delegates the shuttle ATA with +/// the merge attached as a post-delegation action. The merge's only signer is +/// the shuttle `owner`, so the validator risk-checks the owner before acting on +/// the delegation: +/// - a low-risk owner is allowed, so the shuttle ATA stays delegated; +/// - a risky owner is blocked, so the shuttle ATA is undelegated back to chain +/// instead of running the merge. +/// +/// Both cases must query the Range risk service for the owner. +fn run_shuttle_merge_risk_case(owner_risk: u64, expect_allowed: bool) { + init_logger!(); + + let fee_payer = Keypair::new(); + let owner = Keypair::new(); + let recipient = Keypair::new(); + let mint = Keypair::new(); + let source_ata = derive_ata(&owner.pubkey(), &mint.pubkey()); + let destination_ata = derive_ata(&recipient.pubkey(), &mint.pubkey()); + let validator_pk = Keypair::try_from(&DLP_TEST_AUTHORITY_BYTES[..]) + .unwrap() + .pubkey(); + + let (shuttle_ephemeral_ata, _) = + find_shuttle_ephemeral_ata(&owner.pubkey(), &mint.pubkey(), SHUTTLE_ID); + let (shuttle_ata, _) = + find_shuttle_ata(&shuttle_ephemeral_ata, &mint.pubkey()); + + let mut server = MockRangeServer::start().unwrap(); + server.set_risk(&owner.pubkey().to_string(), owner_risk); + + let (_tmpdir, ledger_path) = resolve_tmp_dir(TMP_DIR_LEDGER); + let (_, mut validator, ctx) = setup_validator_with_local_remote( + &ledger_path, + None, + true, + false, + &LoadedAccounts::with_delegation_program_test_authority(), + server.base_url().to_string(), + ); + + expect!( + ctx.airdrop_chain(&fee_payer.pubkey(), 2_000_000_000), + validator + ); + expect!(ctx.airdrop_chain(&owner.pubkey(), 2_000_000_000), validator); + + let chain_client = expect!(ctx.try_chain_client(), validator); + let mint_rent = expect!( + chain_client.get_minimum_balance_for_rent_exemption(Mint::LEN), + validator + ); + + // Create the mint, the owner's funded source ATA and the recipient's + // destination ATA the merge targets. + let setup_ixs = vec![ + system_instruction::create_account( + &fee_payer.pubkey(), + &mint.pubkey(), + mint_rent, + Mint::LEN as u64, + &spl_token::id(), + ), + expect!( + spl_token_ix::initialize_mint( + &spl_token::id(), + &mint.pubkey(), + &owner.pubkey(), + None, + 0, + ), + validator + ), + create_associated_token_account_idempotent( + &fee_payer.pubkey(), + &owner.pubkey(), + &mint.pubkey(), + &spl_token::id(), + ), + create_associated_token_account_idempotent( + &fee_payer.pubkey(), + &recipient.pubkey(), + &mint.pubkey(), + &spl_token::id(), + ), + expect!( + spl_token_ix::mint_to( + &spl_token::id(), + &mint.pubkey(), + &source_ata, + &owner.pubkey(), + &[], + SHUTTLE_AMOUNT, + ), + validator + ), + ]; + let mut setup_tx = + Transaction::new_with_payer(&setup_ixs, Some(&fee_payer.pubkey())); + let (_sig, confirmed) = expect!( + ctx.send_and_confirm_transaction_chain( + &mut setup_tx, + &[&fee_payer, &mint, &owner], + ), + validator + ); + assert!( + confirmed, + cleanup_both(&mut validator, &mut server), + "mint/ATA setup transaction failed" + ); + + // Initialize the shuttle prerequisites: the rent PDA (a shared vault that + // fronts rent for the delegated shuttle accounts, so it must hold lamports + // beyond its own rent exemption) and the per-mint global vault. + // The rent PDA is global and shared across tests, so only initialize it + // when it does not exist yet. + let (rent_pda, _) = find_rent_pda(); + if ctx.fetch_chain_account(rent_pda).is_err() { + let mut prereq_tx = Transaction::new_with_payer( + &[InitializeRentPdaBuilder { + payer: fee_payer.pubkey(), + } + .instruction()], + Some(&fee_payer.pubkey()), + ); + let (_sig, confirmed) = expect!( + ctx.send_and_confirm_transaction_chain( + &mut prereq_tx, + &[&fee_payer] + ), + validator + ); + assert!( + confirmed, + cleanup_both(&mut validator, &mut server), + "rent PDA initialization failed" + ); + } + expect!(ctx.airdrop_chain(&rent_pda, 1_000_000_000), validator); + + let mut vault_tx = Transaction::new_with_payer( + &[InitializeGlobalVaultBuilder { + payer: fee_payer.pubkey(), + mint: mint.pubkey(), + } + .instruction()], + Some(&fee_payer.pubkey()), + ); + let (_sig, confirmed) = expect!( + ctx.send_and_confirm_transaction_chain(&mut vault_tx, &[&fee_payer]), + validator + ); + assert!( + confirmed, + cleanup_both(&mut validator, &mut server), + "global vault initialization failed" + ); + + // Delegate the shuttle ATA with the merge attached as a post-delegation + // action. + let mut shuttle_tx = Transaction::new_with_payer( + &[SetupAndDelegateShuttleEphemeralAtaWithMergeBuilder { + payer: fee_payer.pubkey(), + owner: owner.pubkey(), + mint: mint.pubkey(), + source_ata, + destination_ata, + shuttle_id: SHUTTLE_ID, + amount: SHUTTLE_AMOUNT, + validator: Some(validator_pk), + } + .instruction()], + Some(&fee_payer.pubkey()), + ); + let (_sig, confirmed) = expect!( + ctx.send_and_confirm_transaction_chain( + &mut shuttle_tx, + &[&fee_payer, &owner], + ), + validator + ); + assert!( + confirmed, + cleanup_both(&mut validator, &mut server), + "shuttle setup + delegation transaction failed" + ); + assert!( + delegation_record_exists(&ctx, &shuttle_ata), + cleanup_both(&mut validator, &mut server), + "shuttle ATA delegation record was not created on base chain" + ); + + // The validator clones the delegated shuttle ATA and risk-checks the owner + // (the merge's only signer) before acting on the delegation. + let mut risk_checked = false; + for _ in 0..60 { + if server.request_count() > 0 { + risk_checked = true; + break; + } + sleep(Duration::from_millis(200)); + } + assert!( + risk_checked, + cleanup_both(&mut validator, &mut server), + "Range risk server was not queried" + ); + let requested_addresses = server.requested_addresses(); + assert!( + requested_addresses.contains(&owner.pubkey().to_string()), + cleanup_both(&mut validator, &mut server), + "Range risk server did not check shuttle owner; requested: {:?}", + requested_addresses + ); + + if expect_allowed { + // Low-risk owner: the merge is allowed, so the shuttle ATA keeps its + // delegation and is never undelegated back to chain. + assert!( + delegation_record_persists(&ctx, &shuttle_ata), + cleanup_both(&mut validator, &mut server), + "low-risk shuttle ATA was unexpectedly undelegated on base chain" + ); + } else { + // Risky owner: the merge is blocked, so the shuttle ATA is undelegated + // back to the base chain instead. + assert!( + wait_for_delegation_record_absent(&ctx, &shuttle_ata), + cleanup_both(&mut validator, &mut server), + "high-risk shuttle ATA was not undelegated on base chain" + ); + } + + cleanup_both(&mut validator, &mut server); +} diff --git a/test-integration/test-runner/Cargo.toml b/test-integration/test-runner/Cargo.toml index ca641d22c..be0e47435 100644 --- a/test-integration/test-runner/Cargo.toml +++ b/test-integration/test-runner/Cargo.toml @@ -14,3 +14,4 @@ path = "bin/run_tests.rs" ctrlc = { workspace = true } integration-test-tools = { workspace = true } teepee = { workspace = true } +tempfile = { workspace = true } diff --git a/test-integration/test-runner/bin/run_tests.rs b/test-integration/test-runner/bin/run_tests.rs index fadd7f727..48bb33e1a 100644 --- a/test-integration/test-runner/bin/run_tests.rs +++ b/test-integration/test-runner/bin/run_tests.rs @@ -34,6 +34,10 @@ pub fn main() { return; }; + let Ok(aml_output) = run_aml_tests(&manifest_dir, &config) else { + return; + }; + let Ok(cloning_output) = run_cloning_tests(&manifest_dir, &config) else { return; }; @@ -82,6 +86,7 @@ pub fn main() { assert_cargo_tests_passed(security_output, "security"); assert_cargo_tests_passed(scenarios_output, "scenarios"); assert_cargo_tests_passed(chainlink_output, "chainlink"); + assert_cargo_tests_passed(aml_output, "aml"); assert_cargo_tests_passed(cloning_output, "cloning"); assert_cargo_tests_passed(restore_ledger_output, "restore_ledger"); assert_cargo_tests_passed(magicblock_api_output, "magicblock_api"); @@ -220,6 +225,54 @@ fn run_chainlink_tests( } } +fn run_aml_tests( + manifest_dir: &str, + config: &TestConfigViaEnvVars, +) -> Result> { + const TEST_NAME: &str = "aml"; + if config.skip_entirely(TEST_NAME) { + return Ok(success_output()); + } + + let loaded_chain_accounts = + LoadedAccounts::with_delegation_program_test_authority(); + + let start_devnet_validator = || match start_validator( + "aml.devnet.toml", + ValidatorCluster::Chain(None), + &loaded_chain_accounts, + ) { + Some(validator) => validator, + None => { + panic!("Failed to start devnet validator properly"); + } + }; + + if config.run_test(TEST_NAME) { + eprintln!("======== Starting DEVNET Validator for AML ========"); + let mut devnet_validator = start_devnet_validator(); + + eprintln!("======== RUNNING AML TESTS ========"); + let test_aml_dir = format!("{}/../{}", manifest_dir, "test-aml"); + eprintln!("Running AML tests in {}", test_aml_dir); + let output = match run_test(test_aml_dir, Default::default()) { + Ok(output) => output, + Err(err) => { + eprintln!("Failed to run AML tests: {:?}", err); + cleanup_devnet_only(&mut devnet_validator); + return Err(err.into()); + } + }; + + cleanup_devnet_only(&mut devnet_validator); + Ok(output) + } else { + let devnet_validator = + config.setup_devnet(TEST_NAME).then(start_devnet_validator); + wait_for_ctrlc(devnet_validator, None, success_output()) + } +} + // The committor suite is split across CI shards to keep wall-clock down. // The `test_ix_commit_local` file alone takes ~33 min and is sliced into // smaller subsets; exact filters are used for the split shards whose names From ba227621bdb4ba709052abd5c11b18dd88645b24 Mon Sep 17 00:00:00 2001 From: Dodecahedr0x Date: Mon, 15 Jun 2026 18:23:29 +0200 Subject: [PATCH 6/7] fix: missing arm --- magicblock-account-cloner/src/lib.rs | 10 ++++++++++ test-integration/Cargo.lock | 14 +++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/magicblock-account-cloner/src/lib.rs b/magicblock-account-cloner/src/lib.rs index bdb99f9f6..c81fac311 100644 --- a/magicblock-account-cloner/src/lib.rs +++ b/magicblock-account-cloner/src/lib.rs @@ -870,6 +870,11 @@ mod tests { assert_eq!(executor_pubkey, pubkey); assert_eq!(executor_actions, actions); } + PostDelegationActionExecutorInstruction::ScheduleUndelegation { + .. + } => { + panic!("expected schedule undelegation instruction") + } } } @@ -916,6 +921,11 @@ mod tests { assert_eq!(executor_pubkey, pubkey); assert_eq!(executor_actions, actions); } + PostDelegationActionExecutorInstruction::ScheduleUndelegation { + .. + } => { + panic!("expected schedule undelegation instruction") + } } } } diff --git a/test-integration/Cargo.lock b/test-integration/Cargo.lock index 287881b2e..0bade0ff3 100644 --- a/test-integration/Cargo.lock +++ b/test-integration/Cargo.lock @@ -4489,7 +4489,7 @@ dependencies = [ "magicblock-aml", "magicblock-config", "magicblock-core", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.3", "magicblock-metrics", "parking_lot", @@ -4828,7 +4828,7 @@ dependencies = [ "bincode", "lazy_static", "magicblock-core", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.3", "num-derive", "num-traits", @@ -4916,7 +4916,7 @@ dependencies = [ "futures-util", "magicblock-core", "magicblock-magic-program-api 0.12.3", - "solana-instruction", + "solana-instruction 3.4.0", "solana-keypair", "solana-message 3.1.0", "solana-pubkey 3.0.0", @@ -6016,7 +6016,7 @@ version = "0.0.0" dependencies = [ "borsh 1.6.0", "ephemeral-rollups-sdk", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.3", "rkyv 0.7.45", "solana-program 3.0.0", @@ -7101,7 +7101,7 @@ dependencies = [ "ephemeral-rollups-sdk", "integration-test-tools", "magicblock-core", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.3", "magicblock-program", "program-schedulecommit", @@ -7122,7 +7122,7 @@ name = "schedulecommit-test-security" version = "0.0.0" dependencies = [ "integration-test-tools", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.3", "program-schedulecommit", "program-schedulecommit-security", @@ -12188,7 +12188,7 @@ dependencies = [ "ephemeral-rollups-sdk", "integration-test-tools", "log", - "magicblock-delegation-program-api 0.3.0 (git+https://github.com/magicblock-labs/delegation-program.git?rev=25386a7c1d406d06b8d07a4d5b0fd37d5e74213b)", + "magicblock-delegation-program-api 0.3.0", "magicblock-magic-program-api 0.12.3", "program-flexi-counter", "solana-rpc-client-api", From 877bf08b30b6e1a7067cb63ba6946d761c981e6f Mon Sep 17 00:00:00 2001 From: Dodecahedr0x Date: Tue, 16 Jun 2026 10:33:39 +0200 Subject: [PATCH 7/7] fix: config --- magicblock-account-cloner/src/lib.rs | 4 +-- test-integration/configs/aml.devnet.toml | 37 ------------------------ 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/magicblock-account-cloner/src/lib.rs b/magicblock-account-cloner/src/lib.rs index c81fac311..c921f9c3b 100644 --- a/magicblock-account-cloner/src/lib.rs +++ b/magicblock-account-cloner/src/lib.rs @@ -873,7 +873,7 @@ mod tests { PostDelegationActionExecutorInstruction::ScheduleUndelegation { .. } => { - panic!("expected schedule undelegation instruction") + panic!("expected execute instruction") } } } @@ -924,7 +924,7 @@ mod tests { PostDelegationActionExecutorInstruction::ScheduleUndelegation { .. } => { - panic!("expected schedule undelegation instruction") + panic!("expected execute instruction") } } } diff --git a/test-integration/configs/aml.devnet.toml b/test-integration/configs/aml.devnet.toml index 2b8f3dbdf..389b7e9ce 100644 --- a/test-integration/configs/aml.devnet.toml +++ b/test-integration/configs/aml.devnet.toml @@ -4,32 +4,10 @@ remotes = ["devnet"] [aperture] listen = "0.0.0.0:7799" -[commit] -compute-unit-price = 1_000_000 - -[accountsdb] -# size of the main storage, we have to preallocate in advance -# it's advised to set this value based on formula 1KB * N * 3, -# where N is the number of accounts expected to be stored in -# database, e.g. for million accounts this would be 3GB -database-size = 1048576000 # 1GB -# minimal indivisible unit of addressing in main storage -# offsets are calculated in terms of blocks -block-size = "block256" # possible values block128 | block256 | block512 -# size of index file, we have to preallocate, -# can be as low as 1% of main storage size, but setting it to higher values won't hurt -index-size = 20485760 -# max number of snapshots to keep around -max-snapshots = 7 - [ledger] reset = true block-time = "50ms" -[[programs]] -id = "3JnJ727jWEmPVU8qfXwtH63sCNDX7nMgsLbg8qy8aaPX" -path = "../programs/redline/redline.so" - [[programs]] id = "DELeGGvXpWV2fqJUhqcF5ZSYMS4JTLjteaAMARRSaeSh" path = "../schedulecommit/elfs/dlp.so" @@ -42,21 +20,6 @@ path = "../schedulecommit/elfs/mdp.so" id = "SPLxh1LVZzEkX99H6rqYizhytLWPZVV296zyYDPagv2" path = "../programs/ephemeral-token/ephemeral_token_program.so" -[[programs]] -id = "MiniV31111111111111111111111111111111111111" -path = "../target/deploy/miniv3/program_mini.so" -auth = "MiniV3AUTH111111111111111111111111111111111" - -[[programs]] -id = "MiniV32111111111111111111111111111111111111" -path = "../target/deploy/miniv3/program_mini.so" -auth = "MiniV4AUTH211111111111111111111111111111111" - -[[programs]] -id = "MiniV33111111111111111111111111111111111111" -path = "../target/deploy/miniv3/program_mini.so" -auth = "MiniV4AUTH311111111111111111111111111111111" - [[programs]] id = "f1exzKGtdeVX3d6UXZ89cY7twiNJe9S5uq84RTA4Rq4" path = "../target/deploy/program_flexi_counter.so"