-
Notifications
You must be signed in to change notification settings - Fork 8
poc #74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
poc #74
Conversation
WalkthroughThis pull request introduces a comprehensive Changes
Sequence Diagram(s)sequenceDiagram
actor Client
participant Server as /solana/program
participant Preparer as Instruction Preparer
participant IDLCache as IDL Cache
participant RPC as Solana RPC
participant Executor as Solana Executor
Client->>Server: POST /solana/program (ProgramCall[])
Server->>Preparer: prepare_calls_parallel()
par Parallel Preparation
Preparer->>IDLCache: get_idl(program_id)
alt IDL in Cache
IDLCache-->>Preparer: return Arc<ProgramIdl>
else Cache Miss
IDLCache->>RPC: fetch_anchor_idl_account(program_id)
alt Anchor IDL Found
RPC-->>IDLCache: return compressed IDL
IDLCache->>IDLCache: decompress & parse
else Anchor Fails
IDLCache->>RPC: fetch_pmp_idl_account(program_id)
RPC-->>IDLCache: return IDL (zlib or JSON)
IDLCache->>IDLCache: decompress & parse
end
IDLCache->>IDLCache: cache_insert(program_id, idl)
IDLCache-->>Preparer: return Arc<ProgramIdl>
end
Preparer->>Preparer: resolve_accounts(idl, provided_accounts)
note over Preparer: Derive PDAs, resolve seeds, handle signer/system accounts
Preparer->>Preparer: encode_instruction(idl, args)
note over Preparer: Apply Anchor discriminator (SHA256), encode via Borsh/Bincode
Preparer-->>Server: PreparedProgramCall (instruction_data, accounts)
end
Server->>Server: aggregate_results()
alt All Prepared
Server->>Executor: execute_solana(instructions)
Executor-->>Server: QueuedSolanaTransactionResponse
Server-->>Client: 202 Accepted + TxId
else Any Failed
Server-->>Client: 400 ValidationError + error details
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes This diff introduces substantial new functionality spanning multiple layers: six new core libraries with dense logic (account resolution, PDA derivation, IDL caching and parsing, instruction encoding), integration into the HTTP server with a new endpoint, comprehensive error handling across three modules, new dependencies, and extensive test coverage. While changes are cohesive and well-organized, the breadth of heterogeneous components (Solana cryptography, IDL parsing, instruction encoding, async caching) and the depth of logic in each module require careful review for correctness, security implications, and proper error handling. Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 17
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
solana-core/Cargo.toml (1)
1-4: Add Rust toolchain version pinning to support edition 2024.The repository uses edition 2024 (which requires Rust ≥ 1.85.0, stabilized Feb 20, 2025) but does not pin a toolchain version. CI workflows do not specify rust-version, so builds will use the default on ubuntu-latest, which may be older than required.
Create a
rust-toolchain.tomlfile in the repository root with:[toolchain] channel = "1.85"Alternatively, add explicit Rust version setup in CI workflows before build steps.
🧹 Nitpick comments (41)
.gitignore (1)
5-6: Ignore env files; keep a committed template.Good addition. Consider a broader pattern while preserving
.env.example.+.env* +!.env.example -.env.test -.envcore/src/error.rs (1)
357-363: Ensure JSON shape + schema consistency for the new variant.
- Confirm
engine_solana_core::error::SolanaProgramErrorderives Serialize/ToSchema; otherwise HTTP serialization/docs break.- Align field case with other variants for consistency.
#[schema(title = "Solana Program Interaction Error")] #[error("Solana program interaction error: {message}")] - SolanaProgramError { + #[serde(rename_all = "camelCase")] + SolanaProgramError { message: String, kind: engine_solana_core::error::SolanaProgramError, },If already deriving Serialize/ToSchema in engine-solana-core, ignore the first point. Otherwise, add those derives there.
solana-core/src/transaction.rs (1)
31-31: Equality derives are appropriate; consider Hash too.Deriving Hash can help use InstructionDataEncoding as a map key in caches or metrics.
-#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema, PartialEq, Eq)] +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema, PartialEq, Eq, Hash)]server/Cargo.toml (1)
17-17: Ensure workspace membership and feature scope for new local crate.Add engine-solana-core to the root Cargo.toml [workspace] members and confirm feature flags are minimal to avoid pulling heavy deps into the server binary.
solana-core/tests/program_interaction_tests.rs (4)
31-37: Avoid hard failure on missing SOLANA_MAINNET_RPC_URL; provide fallback.Use a sensible default or skip networked tests when the env var isn’t set to keep CI green.
Apply this diff:
-fn create_test_idl_cache() -> IdlCache { +fn create_test_idl_cache() -> IdlCache { init_test_env(); - let rpc_url = std::env::var("SOLANA_MAINNET_RPC_URL") - .expect("SOLANA_MAINNET_RPC_URL must be set in .env.test file"); + let rpc_url = std::env::var("SOLANA_MAINNET_RPC_URL") + .unwrap_or_else(|_| "https://api.mainnet-beta.solana.com".to_string()); IdlCache::new(rpc_url) }
349-397: Gate real network test behind an env flag to prevent flakiness.This test depends on mainnet and RPC stability. Skip unless explicitly enabled.
Apply this diff:
#[tokio::test] async fn test_fetch_jupiter_idl_from_chain() { + if std::env::var("RUN_SOLANA_NETWORK_TESTS").unwrap_or_default() != "1" { + eprintln!("Skipping networked test_fetch_jupiter_idl_from_chain (set RUN_SOLANA_NETWORK_TESTS=1 to run)"); + return; + } let cache = create_test_idl_cache();
499-502: Relax timing thresholds to reduce CI flakes.Cache lookups are fast but 10ms can be exceeded on shared runners.
Apply this diff:
- // Both should be very fast (< 1ms) - assert!(first_duration.as_millis() < 10, "Cache should be fast"); - assert!(second_duration.as_millis() < 10, "Cache should be fast"); + // Both should be very fast; allow generous headroom on CI + assert!(first_duration.as_millis() < 50, "Cache should be fast"); + assert!(second_duration.as_millis() < 50, "Cache should be fast");
235-241: Use numeric JSON for amounts to match typical IDL arg types.Amounts are usually u64; avoid quoting to reduce accidental type mismatches later.
Apply this diff:
- map.insert("amountIn".to_string(), json!("1000000000")); - map.insert("minimumAmountOut".to_string(), json!("150000000")); + map.insert("amountIn".to_string(), json!(1_000_000_000u64)); + map.insert("minimumAmountOut".to_string(), json!(150_000_000u64));solana-core/tests/jupiter_idl.json (1)
11-27: Prefer IDL-provided discriminators when available.Jupiter IDL includes explicit 8‑byte discriminators per instruction. The encoder should use these when present, falling back to Anchor’s sha256("global:") only if absent. This avoids edge‑case mismatches.
SOLANA_PROGRAM_ENDPOINT_SPEC.md (4)
21-25: Add languages to fenced code blocks (markdownlint MD040).Use explicit languages for all code fences, e.g.,
json,rust, ```shell. This improves rendering and linting.Also applies to: 41-45, 56-69, 89-97, 110-137, 321-372, 731-749, 754-778, 783-806
414-420: Punctuation: use “etc.” with a period.Replace “etc” with “etc.” in those bullet points.
Also applies to: 429-436
60-86: Request shape inconsistency: “instructions” vs “params”.Spec shows request.instructions, while the type SendSolanaProgramRequest and handler use params. Align to one field name to avoid API confusion and docs drift.
Also applies to: 272-314
550-558: Anchor dependency version mismatch.Spec lists anchor‑lang/anchor‑spl 0.30, while code references anchor_lang 0.32.x types. Update the document to reflect the actual versions used or declare version ranges.
solana-core/src/instruction_encoder.rs (4)
33-49: Bincode path unimplemented; doc claims support.Either implement bincode serialization or adjust docs to state Borsh‑only for now. Consider feature‑gating native/bincode until ready.
35-42: Use IDL discriminator when present; fallback to computed Anchor discriminator.Rely on instruction.discriminator if provided by the IDL to avoid mismatches with non‑standard encoders; compute only when absent.
- let discriminator = Self::calculate_anchor_discriminator(instruction_name); - data.extend_from_slice(&discriminator); + if let Some(d) = &instruction.discriminator { + data.extend_from_slice(d); + } else { + let discriminator = Self::calculate_anchor_discriminator(instruction_name); + data.extend_from_slice(&discriminator); + }
76-86: Optional args: treat missing Option as None instead of error.Current logic errors when an optional arg key is omitted. If arg_def.ty is Option(_), default to JSON null when key is missing.
- for arg_def in arg_definitions { - let value = arg_values.get(&arg_def.name).ok_or_else(|| { + for arg_def in arg_definitions { + let value = match (&arg_def.ty, arg_values.get(&arg_def.name)) { + (IdlType::Option(_), None) => &serde_json::Value::Null, + (_, Some(v)) => v, + _ => { SolanaProgramError::InvalidArgument { arg: arg_def.name.clone(), error: "Missing required argument".to_string(), - } - })?; + }.into() + };
319-336: Strengthen tests; assert known values and cover edge cases.
- Assert a known discriminator value (e.g., for “claim”) rather than printing.
- Add tests for numeric bounds (u8/u16 overflows, negative i8 underflows).
- Add Option(None) and Vec(Pubkey) cases.
Also applies to: 330-336
solana-core/tests/pda_derivation_tests.rs (1)
276-279: Bump assertion is brittle; don’t assume a minimum.Bump is 0..=255. Replace “bump >= 253” with a sanity check (e.g., just validate determinism, or 0<=bump<=255 which is always true).
- assert!(bump >= 253, "Bump should be a valid bump seed (253-255)"); + assert!(bump <= 255, "Bump must be within 0..=255");solana-core/src/lib.rs (2)
19-20: Avoid blanket re-export of Anchor IDL types
pub use anchor_lang::idl::types::*leaks a large, unstable surface and risks name collisions. Prefer a namespaced re-export (e.g.,pub mod anchor_idl { pub use anchor_lang::idl::types::*; }) or selectively re-export only what you need.
10-16: Consolidate/align re-exports to prevent duplicationYou also re-export
IdlField/IdlTypeviaidl_types.rs. Double re-exports can confuse downstream users and break semver when any source changes. Consider centralizing re-exports in one place (this file) and haveidl_types.rsimport internally.solana-core/src/error.rs (2)
5-50: Solid, structured error surface; align JSON field casingEnum and display messages look good. For API consistency with other request/response types using camelCase, consider renaming payload fields to camelCase (e.g.,
programId,instructionName) or wrapping details under adetailsobject. This avoids mixed casing next to#[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")].
52-52: Result alias scope
pub type Result<T> = ...is fine, but exporting it at crate root can shadowstd::result::Resultin consumers. Consider encouragingengine_solana_core::error::Resultin docs to avoid ambiguity.solana-core/tests/integration_tests.rs (5)
76-103: Add meaningful assertions or explicitly expect failureCurrently, this branch logs and always passes. Either assert expected success/failure or keep it ignored. Example minimal assertion:
- match result { + match result { Ok(prepared) => { // ... } Err(e) => { eprintln!("\n⚠ Failed to prepare Jupiter swap"); eprintln!("Error: {:?}", e); - println!("\nThis is expected - account resolution is not yet fully implemented"); + // Until account resolution lands, we expect an error. + // Remove this assert and the #[ignore] once implemented. + assert!(true, "Known limitation: account resolution pending"); } }Would you prefer I convert this to a table-driven test that enumerates known failing/missing accounts to assert specific error variants?
105-116: Network-dependent test: add skip-on-missing-env guardMainnet IDL fetch can flake. Add an early-return if
SOLANA_MAINNET_RPC_URLis unset, similar to the helper guard.
191-213: Avoid hard-coding Anchor discriminator bytesHard-coded discriminator
[62, 198, 214, 193, 213, 159, 108, 210]is brittle. Compute it at runtime via SHA-256 ofb"global:claim"and compare first 8 bytes.+use sha2::{Digest, Sha256}; @@ - assert_eq!(&decoded_data[..8], &[62, 198, 214, 193, 213, 159, 108, 210], "Discriminator should match IDL"); + let mut hasher = Sha256::new(); + hasher.update(b"global:claim"); + let disc = &hasher.finalize()[..8]; + assert_eq!(&decoded_data[..8], disc, "Discriminator should match Anchor rule");Please ensure
sha2is present in[dev-dependencies]. If not, I can open a PR to addsha2 = "0.10"there.
308-310: Mark Raydium IDL test as ignored or add assertionsThis test is informative-only and network-dependent. Recommend ignoring by default:
-#[tokio::test] +#[tokio::test] +#[ignore] // enable with RUN_MAINNET_TESTS and add assertions when stable
397-417: Convert checklist test to doc or ignore itThis prints a checklist and always passes. Either move to docs or ignore to keep CI signal high:
-#[test] +#[test] +#[ignore] // documentation-style checklist; not a real testsolana-core/src/idl_types.rs (2)
33-40: Doc comment mismatchThe doc says “detecting Anchor if discriminators are present,” but no detection is implemented. Either implement detection or update the comment to reflect the new default behavior.
90-91: Re-export duplication with lib.rsYou also re-export
IdlType/IdlFieldhere whilelib.rsre-exports all Anchor IDL types. Consider removing one to avoid ambiguous imports for users.server/src/http/routes/solana_program.rs (2)
77-90: Bound parallel preparations to protect the server
join_allfires all futures at once. Largeinstructionsarrays can cause load spikes (RPC connections, CPU). Use a bounded stream (e.g.,.buffer_unordered(16)).Example:
-use futures::future::join_all; +use futures::{future::join_all, stream, StreamExt}; @@ - let preparation_results = join_all(prepare_futures).await; + let preparation_results: Vec<_> = + stream::iter(prepare_futures).buffer_unordered(16).collect().await;
117-133: Preserve partial successes or return structured per-instruction errorsYou currently fail the whole request if any preparation fails. If single-transaction semantics are required, document it. Otherwise, consider returning both prepared instructions and a structured error list to let clients decide.
Also, return typed error bodies (array of
{ index, instruction, error: { type, ... } }) instead of a concatenated string to improve client UX.solana-core/src/account_resolver.rs (2)
79-91: Pre-validate seed lengths (<=32 bytes) before PDA derivationfind_program_address fails when any seed exceeds 32 bytes; surfacing a clear error improves UX.
- let seed_refs: Vec<&[u8]> = seed_bytes.iter().map(|v| v.as_slice()).collect(); + for s in &seed_bytes { + if s.len() > 32 { + return Err(SolanaProgramError::InvalidSeed { + error: format!("Seed length {} exceeds 32 bytes", s.len()), + }); + } + } + let seed_refs: Vec<&[u8]> = seed_bytes.iter().map(|v| v.as_slice()).collect(); ```<!-- review_comment_end --> --- `223-232`: **ResolvedAccount is defined in two modules; unify to one type** Duplicate structs here and in program.rs increase drift risk. Reuse a single exported type. <!-- review_comment_end --> </blockquote></details> <details> <summary>solana-core/src/idl_cache.rs (3)</summary><blockquote> `46-63`: **Deduplicate concurrent fetches with get_with/try_get_with** Current get→fetch→insert can trigger duplicate network calls under concurrency. Use moka’s get_with. ```diff - if let Some(idl) = self.cache.get(program_id).await { - tracing::debug!(program_id = %program_id, "IDL cache hit"); - return Ok(idl); - } - // Cache miss - fetch from on-chain - tracing::debug!(program_id = %program_id, "IDL cache miss, fetching from on-chain"); - let idl = self.fetch_idl(program_id).await?; - let idl_arc = Arc::new(idl); - self.cache.insert(*program_id, idl_arc.clone()).await; - Ok(idl_arc) + let idl_arc = self + .cache + .get_with(*program_id, async { + tracing::debug!(program_id = %program_id, "IDL cache miss, fetching from on-chain"); + Arc::new(self.fetch_idl(program_id).await.expect("idl fetch")) + }) + .await; + Ok(idl_arc)Do the same for get_idl_with_client.
299-330: PMP path: guard against oversized decompression and non-JSON payloadsUnbounded zlib decompression can be abused. Add a soft size cap and fall back early when data is clearly not zlib.
- let mut decoder = ZlibDecoder::new(&account.data[..]); + let mut decoder = ZlibDecoder::new(&account.data[..]); let mut decompressed = Vec::new(); - match decoder.read_to_end(&mut decompressed) { + match decoder.read_to_end(&mut decompressed) { Ok(_) => { + if decompressed.len() > 2 * 1024 * 1024 { + return Err(SolanaProgramError::IdlFetchError { + program: program_id.to_string(), + error: "Decompressed IDL exceeds 2MB limit".to_string(), + }); + } // Successfully decompressed, parse as JSONAlso consider checking account.owner for the PMP program before processing.
365-398: Test noise: remove println! outputUse tracing in tests or drop prints to keep logs clean.
solana-core/src/program.rs (4)
278-293: Remove unnecessary async from resolve_accountsThe method performs no awaits. Make it synchronous to simplify call sites and avoid .await.
- async fn resolve_accounts( + fn resolve_accounts( ... - self.resolve_accounts(&idl, &signer, &program_id).await?; + self.resolve_accounts(&idl, &signer, &program_id)?; ```<!-- review_comment_end --> --- `287-291`: **Enforce 32‑byte seed limit when building PDA seeds** Return a clear error if any seed exceeds 32 bytes. ```diff - let seed_bytes = self.resolve_seed_value(seed_def, resolved_accounts, args)?; + let seed_bytes = self.resolve_seed_value(seed_def, resolved_accounts, args)?; + if seed_bytes.len() > 32 { + return Err(SolanaProgramError::InvalidSeed { + error: format!("Seed '{}' exceeds 32 bytes", hex::encode(&seed_bytes)), + }); + } seeds.push(seed_bytes); ```<!-- review_comment_end --> --- `235-243`: **Fixed-IDL addresses labeled as System; consider a distinct source** A literal address in the IDL isn’t necessarily a system/sysvar account. Use a new AccountSource variant (e.g., Fixed) to avoid misleading provenance. <!-- review_comment_end --> --- `139-147`: **Built-in IDL TODO: clarify behavior or implement** You detect well-known programs with has_builtin_idl() but always fall through to fetch. Either implement built‑in IDLs or document the fallback clearly. <!-- review_comment_end --> </blockquote></details> <details> <summary>solana-core/src/builtin_programs.rs (1)</summary><blockquote> `237-249`: **From<String>/<&str> always maps to Address; confirm intent** Constructors treat any string (including “spl-token”) as Address, relying on ProgramInfo::from_identifier to re-map. If you want stronger typing, consider TryFrom<&str> that prefers Named on known aliases. <!-- review_comment_end --> </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used**: CodeRabbit UI **Review profile**: CHILL **Plan**: Pro **Disabled knowledge base sources:** - Linear integration is disabled by default for public repositories > You can enable these sources in your CodeRabbit configuration. <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 3beb5ce17d8cab112c4b5cc3ffd8d7ae7bf09c6e and 9cefe566c5b48e4422840ecc60508e18a2f1f78b. </details> <details> <summary>⛔ Files ignored due to path filters (1)</summary> * `Cargo.lock` is excluded by `!**/*.lock` </details> <details> <summary>📒 Files selected for processing (25)</summary> * `.gitignore` (1 hunks) * `Cargo.toml` (1 hunks) * `SOLANA_PROGRAM_ENDPOINT_SPEC.md` (1 hunks) * `core/src/error.rs` (2 hunks) * `eip7702-core/src/constants.rs` (1 hunks) * `server/Cargo.toml` (1 hunks) * `server/src/http/error.rs` (1 hunks) * `server/src/http/routes/mod.rs` (1 hunks) * `server/src/http/routes/solana_program.rs` (1 hunks) * `server/src/http/server.rs` (2 hunks) * `server/src/main.rs` (3 hunks) * `solana-core/Cargo.toml` (1 hunks) * `solana-core/src/account_resolver.rs` (1 hunks) * `solana-core/src/builtin_programs.rs` (1 hunks) * `solana-core/src/error.rs` (1 hunks) * `solana-core/src/idl_cache.rs` (1 hunks) * `solana-core/src/idl_types.rs` (1 hunks) * `solana-core/src/instruction_encoder.rs` (1 hunks) * `solana-core/src/lib.rs` (1 hunks) * `solana-core/src/program.rs` (1 hunks) * `solana-core/src/transaction.rs` (1 hunks) * `solana-core/tests/integration_tests.rs` (1 hunks) * `solana-core/tests/jupiter_idl.json` (1 hunks) * `solana-core/tests/pda_derivation_tests.rs` (1 hunks) * `solana-core/tests/program_interaction_tests.rs` (1 hunks) </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🧬 Code graph analysis (11)</summary> <details> <summary>server/src/main.rs (2)</summary><blockquote> <details> <summary>server/src/http/server.rs (1)</summary> * `new` (50-118) </details> <details> <summary>server/src/queue/manager.rs (1)</summary> * `new` (52-318) </details> </blockquote></details> <details> <summary>server/src/http/server.rs (1)</summary><blockquote> <details> <summary>server/src/http/routes/solana_program.rs (1)</summary> * `send_solana_program` (60-166) </details> </blockquote></details> <details> <summary>solana-core/tests/program_interaction_tests.rs (6)</summary><blockquote> <details> <summary>solana-core/src/account_resolver.rs (6)</summary> * `serde_json` (178-178) * `pubkey` (56-68) * `get_system_account` (176-181) * `test_pda_derivation` (269-275) * `derive_pda` (79-91) * `to_bytes` (200-215) </details> <details> <summary>solana-core/src/idl_cache.rs (2)</summary> * `new` (25-34) * `default` (345-348) </details> <details> <summary>solana-core/src/builtin_programs.rs (4)</summary> * `from_identifier` (60-78) * `from_identifier` (122-145) * `program_id` (27-45) * `name` (48-57) </details> <details> <summary>solana-core/src/program.rs (1)</summary> * `seeds` (226-226) </details> <details> <summary>solana-core/src/idl_types.rs (1)</summary> * `from_json` (35-39) </details> <details> <summary>solana-core/src/instruction_encoder.rs (1)</summary> * `encode_instruction` (17-52) </details> </blockquote></details> <details> <summary>solana-core/tests/pda_derivation_tests.rs (1)</summary><blockquote> <details> <summary>solana-core/src/account_resolver.rs (3)</summary> * `pubkey` (56-68) * `derive_pda` (79-91) * `derive_ata` (105-116) </details> </blockquote></details> <details> <summary>solana-core/src/instruction_encoder.rs (2)</summary><blockquote> <details> <summary>solana-core/src/account_resolver.rs (2)</summary> * `serde_json` (178-178) * `s` (148-148) </details> <details> <summary>solana-core/src/program.rs (1)</summary> * `s` (347-347) </details> </blockquote></details> <details> <summary>solana-core/tests/integration_tests.rs (2)</summary><blockquote> <details> <summary>solana-core/tests/program_interaction_tests.rs (2)</summary> * `init_test_env` (24-29) * `create_test_idl_cache` (32-37) </details> <details> <summary>solana-core/src/idl_cache.rs (1)</summary> * `new` (25-34) </details> </blockquote></details> <details> <summary>server/src/http/routes/solana_program.rs (2)</summary><blockquote> <details> <summary>server/src/http/server.rs (1)</summary> * `new` (50-118) </details> <details> <summary>solana-core/src/idl_cache.rs (1)</summary> * `new` (25-34) </details> </blockquote></details> <details> <summary>solana-core/src/account_resolver.rs (3)</summary><blockquote> <details> <summary>solana-core/src/program.rs (2)</summary> * `seeds` (226-226) * `s` (347-347) </details> <details> <summary>solana-core/src/builtin_programs.rs (2)</summary> * `program_id` (27-45) * `name` (48-57) </details> <details> <summary>solana-core/tests/program_interaction_tests.rs (1)</summary> * `test_pda_derivation` (112-138) </details> </blockquote></details> <details> <summary>solana-core/src/builtin_programs.rs (2)</summary><blockquote> <details> <summary>solana-core/src/account_resolver.rs (2)</summary> * `pubkey` (56-68) * `s` (148-148) </details> <details> <summary>solana-core/src/program.rs (1)</summary> * `s` (347-347) </details> </blockquote></details> <details> <summary>solana-core/src/idl_cache.rs (1)</summary><blockquote> <details> <summary>solana-core/src/idl_types.rs (1)</summary> * `from_json` (35-39) </details> </blockquote></details> <details> <summary>solana-core/src/program.rs (5)</summary><blockquote> <details> <summary>solana-core/src/account_resolver.rs (3)</summary> * `pubkey` (56-68) * `serde_json` (178-178) * `s` (148-148) </details> <details> <summary>solana-core/src/builtin_programs.rs (4)</summary> * `program_id` (27-45) * `name` (48-57) * `from_identifier` (60-78) * `from_identifier` (122-145) </details> <details> <summary>solana-core/src/instruction_encoder.rs (4)</summary> * `encode_instruction` (17-52) * `s` (278-278) * `s` (296-296) * `s` (308-308) </details> <details> <summary>solana-core/src/idl_types.rs (1)</summary> * `from_json` (35-39) </details> <details> <summary>solana-core/src/idl_cache.rs (1)</summary> * `new` (25-34) </details> </blockquote></details> </details><details> <summary>🪛 LanguageTool</summary> <details> <summary>SOLANA_PROGRAM_ENDPOINT_SPEC.md</summary> [style] ~418-~418: In American English, abbreviations like “etc.” require a period. Context: ...4. Handle system accounts (rent, clock, etc) 5. Write integration tests **Delivera... (ETC_PERIOD) --- [style] ~429-~429: In American English, abbreviations like “etc.” require a period. Context: ...program IDs (System, Token, Token-2022, etc) 3. Implement instruction builders for ... (ETC_PERIOD) </details> </details> <details> <summary>🪛 markdownlint-cli2 (0.18.1)</summary> <details> <summary>SOLANA_PROGRAM_ENDPOINT_SPEC.md</summary> 21-21: Fenced code blocks should have a language specified (MD040, fenced-code-language) --- 42-42: Fenced code blocks should have a language specified (MD040, fenced-code-language) --- 56-56: Fenced code blocks should have a language specified (MD040, fenced-code-language) </details> </details> </details> <details> <summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)</summary> * GitHub Check: Socket Security: Pull Request Alerts </details> <details> <summary>🔇 Additional comments (11)</summary><blockquote> <details> <summary>core/src/error.rs (1)</summary><blockquote> `842-849`: **From<…> mapping looks fine; verify downstream pattern matches and HTTP mapping.** - Adding a public enum variant can break exhaustive matches; ensure all call sites updated. - Confirm `server/src/http/error.rs` maps this variant to the intended status (e.g., 400). </blockquote></details> <details> <summary>solana-core/Cargo.toml (2)</summary><blockquote> `34-38`: **Reqwest/Tokio feature surfaces.** - Using `reqwest` with only `json` assumes TLS features come from the workspace; confirm TLS backend (rustls or native-tls) is enabled at workspace level. - `tokio` only enables `sync`; confirm no runtime/macros needed here. --- `40-45`: **SPL interface crates: good choice.** Interfaces over on-chain program crates keeps deps light. LGTM. </blockquote></details> <details> <summary>server/src/http/routes/mod.rs (1)</summary><blockquote> `8-8`: **Route module exposure looks good; wire into router + docs.** Confirm router registration and OpenAPI exposure for `/solana/program`. </blockquote></details> <details> <summary>server/src/main.rs (2)</summary><blockquote> `43-46`: **LGTM: cloning URLs avoids unintended moves.** --- `145-145`: **Current idl_cache implementation is architecturally correct; review comment's suggestion misrepresents the design.** The codebase intentionally uses a single shared `idl_cache` by design. As documented in `main.rs` (lines 125–126): "Use mainnet for IDL fetching since IDLs are typically the same across networks. The cache is shared across all Solana networks." The `idl_cache` addition to `EngineServerState` aligns with existing patterns (e.g., `kms_client_cache`). Routes that use it (e.g., `solana_program.rs:79`) access it directly without chain-specific selection, which is correct for shared Solana IDLs. No `idl_cache_for_chain` method or multi-cache selection logic exists in the codebase because it is not needed under the current architecture. > Likely an incorrect or invalid review comment. </blockquote></details> <details> <summary>server/src/http/error.rs (1)</summary><blockquote> `100-101`: **LGTM: map SolanaProgramError to 400.** Appropriate for client/preparation errors; keep SolanaRpcError mapping for transport issues as 5xx/4xx as already implemented. </blockquote></details> <details> <summary>server/src/http/server.rs (1)</summary><blockquote> `72-74`: **LGTM: route registered for /solana/program.** Confirm the handler has utoipa annotations so it appears in OpenAPI. </blockquote></details> <details> <summary>solana-core/tests/pda_derivation_tests.rs (1)</summary><blockquote> `8-11`: **No action needed—the import path is correct.** The crate name in solana-core/Cargo.toml is `engine-solana-core`. In Rust, hyphens in package names automatically convert to underscores when used in imports, so `use engine_solana_core::{...}` is the correct import syntax for this crate name. > Likely an incorrect or invalid review comment. </blockquote></details> <details> <summary>Cargo.toml (1)</summary><blockquote> `31-35`: **Version alignment confirmed correct; no issues found.** All Solana crates are consistently aligned: solana-sdk/client/transaction-status/connection-cache/commitment-config/compute-budget-interface at v3.0, with solana-system-interface v2.0 (the correct pairing for SDK 3.x as system instructions were separated into the standalone v2.0 crate). Workspace audit confirms no conflicting versions across member crates—all Solana dependencies are centralized in the root and homogeneous at their respective versions. </blockquote></details> <details> <summary>solana-core/src/account_resolver.rs (1)</summary><blockquote> `45-47`: **SysvarRecentBlockhashes exists in solana-sdk 3.0.0 but is deprecated; document status and future removal plan** The sysvar is deprecated in solana-sdk 3.x but the constant still exists and compiles without breaking. The enum variant is publicly exposed via serde aliases for deserialization, so removing it would break external API consumers. No internal usage found in the codebase. To mitigate future SDK incompatibility: - Add a `#[deprecated]` attribute to the variant with a migration note pointing to modern alternatives (e.g., `getLatestBlockhash` RPC or newer sysvar crates) - Document the removal plan if you intend to drop it in a future version </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| bincode = "1.3" | ||
| borsh = "1.5" # Borsh serialization for Anchor programs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Serialization stack added; confirm single source of truth for Borsh/Bincode.
Since borsh 1.5 and bincode 1.3 are added at workspace level, ensure crates don’t pin conflicting minor versions locally. Also verify the encoder’s “bincode path” is either implemented or feature‑gated to avoid runtime Unsupported errors.
🏁 Script executed:
#!/bin/bash
# Check for duplicate version specs in crate manifests
fd Cargo.toml | xargs -I{} rg -nP '^(borsh|bincode)\s*=\s*".*"' {}Length of output: 78
🏁 Script executed:
#!/bin/bash
# Find all Cargo.toml files in the workspace
echo "=== All Cargo.toml files ==="
fd Cargo.toml
echo -e "\n=== Check for bincode/borsh in non-root crates ==="
# Exclude root Cargo.toml and check if any crate-level manifests define these
fd Cargo.toml -not -path './Cargo.toml' | xargs -I{} sh -c 'echo "File: {}"; rg -P "(borsh|bincode)\s*=" {} || echo " (none)"'
echo -e "\n=== Search for bincode path usage ==="
rg -nP -i 'bincode.*path|path.*bincode' -A2 -B2Length of output: 543
🏁 Script executed:
#!/bin/bash
# Search for feature-gating or encoding implementation
echo "=== Search for feature flags or conditional compilation ==="
rg -nP '^\s*#\[cfg.*bincode'
echo -e "\n=== Search for Unsupported error or encoding context ==="
rg -nP 'Unsupported|bincode.*encode|encode.*bincode' -C2 --type rustLength of output: 7781
Bincode serialization is unimplemented and will cause runtime errors.
Verification confirms no conflicting dependency versions exist (only root Cargo.toml defines borsh and bincode). However, the bincode encoder path is explicitly unimplemented at solana-core/src/instruction_encoder.rs:43-47 and returns SolanaProgramError::UnsupportedType when encountered. Either implement bincode serialization or feature-gate it to prevent runtime failures.
🤖 Prompt for AI Agents
In Cargo.toml around lines 37-38 the bincode dependency is enabled but the
bincode encoder is unimplemented in solana-core/src/instruction_encoder.rs
(lines ~43-47), causing runtime UnsupportedType errors; either implement the
bincode path or remove/feature-gate the dependency: A) Implement bincode
serialization by wiring the unimplemented branch to call bincode::serialize on
the instruction payload and map serialization errors to SolanaProgramError,
updating solana-core error conversions accordingly; or B) Make bincode an
optional dependency in Cargo.toml and add a feature (e.g., "bincode") that gates
both the dependency and the encoder branch, and update Cargo.toml features and
code cfg(attributes) so builds without that feature don’t hit the unimplemented
path.
| pub struct SendSolanaProgramRequest { | ||
| /// Idempotency key for this transaction (defaults to random UUID) | ||
| #[serde(default)] | ||
| pub idempotency_key: String, | ||
|
|
||
| /// Solana execution options |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Idempotency key: doc says random UUID, code defaults to empty string
Empty keys break idempotency (collisions across requests). Generate a UUID when missing.
pub struct SendSolanaProgramRequest {
/// Idempotency key for this transaction (defaults to random UUID)
- #[serde(default)]
- pub idempotency_key: String,
+ #[serde(default)]
+ pub idempotency_key: String,
}And in the handler:
@@
- let transaction_id = request.idempotency_key.clone();
+ let transaction_id = if request.idempotency_key.is_empty() {
+ uuid::Uuid::now_v7().to_string()
+ } else {
+ request.idempotency_key.clone()
+ };
@@
- let transaction_request = SendSolanaTransactionRequest {
- idempotency_key: request.idempotency_key,
+ let transaction_request = SendSolanaTransactionRequest {
+ idempotency_key: transaction_id.clone(),
instructions: prepared_instructions,
execution_options: request.execution_options,
webhook_options: request.webhook_options,
};Add import:
+use uuid::Uuid;Committable suggestion skipped: line range outside the PR's diff.
|
|
||
| // Solana IDL cache for program interaction | ||
| pub idl_cache: Arc<engine_solana_core::IdlCache>, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Carry per‑cluster IDL caches in state and expose a selector.
Single cache won’t respect chain_id. Replace with three caches and a helper to choose by chain, to keep route code clean.
Apply this diff:
- // Solana IDL cache for program interaction
- pub idl_cache: Arc<engine_solana_core::IdlCache>,
+ // Solana IDL caches per cluster for correct IDL resolution
+ pub idl_cache_mainnet: Arc<engine_solana_core::IdlCache>,
+ pub idl_cache_devnet: Arc<engine_solana_core::IdlCache>,
+ pub idl_cache_local: Arc<engine_solana_core::IdlCache>,Then add (outside this hunk):
impl EngineServerState {
pub fn idl_cache_for_chain(&self, chain_id: &str) -> &Arc<engine_solana_core::IdlCache> {
match chain_id {
// adapt to your ChainId representation if not plain string
s if s.eq_ignore_ascii_case("solana:mainnet") || s.eq_ignore_ascii_case("mainnet") => &self.idl_cache_mainnet,
s if s.eq_ignore_ascii_case("solana:devnet") || s.eq_ignore_ascii_case("devnet") => &self.idl_cache_devnet,
_ => &self.idl_cache_local,
}
}
}🤖 Prompt for AI Agents
In server/src/http/server.rs around lines 36 to 39, the EngineServerState
currently holds a single idl_cache that doesn't respect chain/cluster, so
replace that single field with three Arc<engine_solana_core::IdlCache> fields
named idl_cache_mainnet, idl_cache_devnet, and idl_cache_local, update any
constructor/initialization sites to populate these three caches, and add the
provided idl_cache_for_chain(&self, chain_id: &str) ->
&Arc<engine_solana_core::IdlCache> helper implementation (adjusting chain_id
matching to your ChainId type if it's not a plain str); also ensure necessary
use/imports for Arc and engine_solana_core are present and update any code that
referenced the old idl_cache to call idl_cache_for_chain or use the new fields
directly.
| // Initialize Solana IDL cache | ||
| // Use mainnet for IDL fetching since IDLs are typically the same across networks | ||
| // The cache is shared across all Solana networks | ||
| let idl_cache = Arc::new(engine_solana_core::IdlCache::new( | ||
| config.solana.mainnet.http_url.clone(), | ||
| )); | ||
|
|
||
| tracing::info!("Solana IDL cache initialized with mainnet RPC"); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cluster-agnostic IDL cache will mis-fetch on devnet/local; make IDL cache cluster-aware.
Using a single mainnet RPC for all requests can fetch the wrong IDL or fail for programs that only exist on devnet/local. Provide per‑cluster caches and select by chain_id.
Apply this diff here:
- // Initialize Solana IDL cache
- // Use mainnet for IDL fetching since IDLs are typically the same across networks
- // The cache is shared across all Solana networks
- let idl_cache = Arc::new(engine_solana_core::IdlCache::new(
- config.solana.mainnet.http_url.clone(),
- ));
-
- tracing::info!("Solana IDL cache initialized with mainnet RPC");
+ // Initialize per‑cluster Solana IDL caches
+ let idl_cache_mainnet = Arc::new(engine_solana_core::IdlCache::new(
+ config.solana.mainnet.http_url.clone(),
+ ));
+ let idl_cache_devnet = Arc::new(engine_solana_core::IdlCache::new(
+ config.solana.devnet.http_url.clone(),
+ ));
+ let idl_cache_local = Arc::new(engine_solana_core::IdlCache::new(
+ config.solana.local.http_url.clone(),
+ ));
+
+ tracing::info!("Solana IDL caches initialized (mainnet/devnet/local)");And pass all three into server state:
- idl_cache,
+ idl_cache_mainnet,
+ idl_cache_devnet,
+ idl_cache_local,Add a selector helper (outside this hunk) to EngineServerState and use it in the solana_program route to pick the correct cache based on request.execution_options.chain_id.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Initialize Solana IDL cache | |
| // Use mainnet for IDL fetching since IDLs are typically the same across networks | |
| // The cache is shared across all Solana networks | |
| let idl_cache = Arc::new(engine_solana_core::IdlCache::new( | |
| config.solana.mainnet.http_url.clone(), | |
| )); | |
| tracing::info!("Solana IDL cache initialized with mainnet RPC"); | |
| // Initialize per‑cluster Solana IDL caches | |
| let idl_cache_mainnet = Arc::new(engine_solana_core::IdlCache::new( | |
| config.solana.mainnet.http_url.clone(), | |
| )); | |
| let idl_cache_devnet = Arc::new(engine_solana_core::IdlCache::new( | |
| config.solana.devnet.http_url.clone(), | |
| )); | |
| let idl_cache_local = Arc::new(engine_solana_core::IdlCache::new( | |
| config.solana.local.http_url.clone(), | |
| )); | |
| tracing::info!("Solana IDL caches initialized (mainnet/devnet/local)"); |
| anchor-lang = { version = "0.32.1", features = ["idl-build"], default-features = false } | ||
| bincode = { workspace = true } # Solana's native serialization format | ||
| borsh = { workspace = true } # Borsh serialization for Anchor programs | ||
| sha2 = "0.10" # For calculating Anchor discriminators | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Anchor/Solana compatibility check.
Verify anchor-lang = 0.32.1 is compatible with the Solana SDK version set in the workspace (comments mention SDK 3.0).
🌐 Web query:
Is anchor-lang 0.32.1 compatible with Solana SDK v2.x/v3.x (system-interface v2), and if not, which anchor-lang version matches Solana 2.x/3.x?
💡 Result:
Short answer: No — anchor-lang 0.32.1 is intended for Solana v2 (recommended v2.3.0) and its crate dependencies still pin solana-system-interface = "1", so it does not target a Solana SDK with system-interface v2. For Solana 2.x use Anchor 0.31.x–0.32.x (0.32.x recommends Solana 2.3.0). There is no official anchor-lang release documented that switches solana-system-interface to v2 in the 0.32.1 sources or release notes. [1][2][3]
Sources:
- anchor-lang 0.32.1 release notes (recommended Solana version 2.3.0). [1]
- anchor-lang 0.32.1 Cargo.toml showing solana-system-interface = "1". [2]
- anchor 0.31.0/0.32.0 release notes (Solana 2.x recommendations). [3]
If you want, I can look for any newer anchor releases (post‑0.32.1) that update solana-system-interface to v2.
I need to check if there are newer anchor-lang versions supporting Solana 3.x with system-interface v2, since the workspace comments mention SDK 3.0.
🌐 Web query:
anchor-lang Solana 3.x system-interface v2 compatible version
💡 Result:
I don't have enough detail to give a precise compatible version. Can you paste the error message or your Cargo.toml (anchor-lang and solana-* versions) — or tell me which Solana 3.x crate/version (e.g. solana-program 3.x / system-interface v2) you're trying to match?
I need to check the actual workspace Solana SDK version to assess whether anchor-lang 0.32.1 is truly incompatible. Let me inspect the codebase.
---
🏁 Script executed:
```shell
#!/bin/bash
# Search for Solana SDK version pins in workspace Cargo.toml
fd Cargo.toml --max-depth 2 -x grep -l "solana" {} \;
Length of output: 98
🏁 Script executed:
#!/bin/bash
# Look for Solana version dependencies in root workspace
cat Cargo.toml 2>/dev/null | grep -A2 -B2 "solana\|anchor"Length of output: 430
🏁 Script executed:
#!/bin/bash
# Search for "SDK 3.0" or version references in comments
rg -n "SDK|solana.*3\.0|system-interface.*2" --max-count=10Length of output: 1312
The incompatibility is confirmed. The workspace requires Solana 3.0 with system-interface v2, but anchor-lang 0.32.1 pins system-interface v1. I need to find which anchor-lang version targets Solana 3.0.
🌐 Web query:
anchor-lang latest version Solana 3.0 migration release notes
💡 Result:
Latest Anchor (anchor-lang) release: 0.32.0 (released 2025‑10‑08). Key Solana‑3.0‑related notes: Anchor 0.32.0 replaces the solana-program crate with smaller crates and updates CLI/CLI tooling to work with newer Solana tooling (part of the Solana 3 / Agave transition); see the Anchor changelog and release notes for full migration steps. [1][2]
Sources
- Anchor changelog (0.32.0) — 2025‑10‑08. [1]
- Anchor release notes (0.31.0) — upgrade instructions and recommended Solana/Agave tool versions. [2]
I need to confirm the system-interface version that anchor-lang 0.32.0 and 0.32.1 actually depend on.
🌐 Web query:
anchor-lang 0.32.0 0.32.1 solana-system-interface version dependency
💡 Result:
Short answer: anchor-lang 0.32.0 and 0.32.1 depend on solana-system-interface = "1" (crate version 1.0.0). [1][2]
Sources:
- anchor-lang Cargo.toml (0.32.1) showing solana-system-interface = "1". [1]
- anchor/client Cargo.lock showing solana-system-interface 1.0.0 in the dependency graph. [2]
Anchor-lang 0.32.1 is incompatible with Solana SDK 3.0 — update to a compatible version.
The workspace pins solana-system-interface = "2.0" (for Solana 3.0), but anchor-lang 0.32.1 depends on solana-system-interface = "1". This creates a dependency conflict. Either:
- Downgrade the workspace to Solana 2.x (where anchor-lang 0.32.x is designed to work), or
- Hold on anchor-lang until a version supporting Solana 3.0 / system-interface v2 is released.
| Value::Array(arr) => { | ||
| // Flatten array of bytes | ||
| arr.iter() | ||
| .map(|v| { | ||
| v.as_u64() | ||
| .ok_or_else(|| SolanaProgramError::InvalidArgument { | ||
| arg: "seed".to_string(), | ||
| error: "Array elements must be numbers".to_string(), | ||
| }) | ||
| .map(|n| n as u8) | ||
| }) | ||
| .collect() | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validate array elements are byte-sized in serialize_arg_for_seed
Casting u64→u8 silently wraps values >255.
- Value::Array(arr) => {
- // Flatten array of bytes
- arr.iter()
- .map(|v| {
- v.as_u64()
- .ok_or_else(|| SolanaProgramError::InvalidArgument {
- arg: "seed".to_string(),
- error: "Array elements must be numbers".to_string(),
- })
- .map(|n| n as u8)
- })
- .collect()
- }
+ Value::Array(arr) => {
+ arr.iter()
+ .map(|v| {
+ let n = v.as_u64().ok_or_else(|| SolanaProgramError::InvalidArgument {
+ arg: "seed".to_string(),
+ error: "Array elements must be numbers".to_string(),
+ })?;
+ if n > 255 {
+ return Err(SolanaProgramError::InvalidArgument {
+ arg: "seed".to_string(),
+ error: format!("Byte value {} exceeds 255", n),
+ });
+ }
+ Ok(n as u8)
+ })
+ .collect()
+ }
```<!-- review_comment_end -->
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```suggestion
Value::Array(arr) => {
arr.iter()
.map(|v| {
let n = v.as_u64().ok_or_else(|| SolanaProgramError::InvalidArgument {
arg: "seed".to_string(),
error: "Array elements must be numbers".to_string(),
})?;
if n > 255 {
return Err(SolanaProgramError::InvalidArgument {
arg: "seed".to_string(),
error: format!("Byte value {} exceeds 255", n),
});
}
Ok(n as u8)
})
.collect()
}🤖 Prompt for AI Agents
In solana-core/src/program.rs around lines 367 to 379, the code casts u64 values
to u8 without checking bounds which allows silent wrapping for values >255;
modify the mapping so each array element is validated for byte range before
casting — for each v, call v.as_u64(), then if n > 255 return a
SolanaProgramError::InvalidArgument with arg "seed" and an error message like
"Array elements must be bytes (0..=255)"; only after that safe-guard cast n as
u8 and collect the bytes, preserving the existing error for non-numeric
elements.
| /// Helper to create test IDL cache | ||
| fn create_test_idl_cache() -> IdlCache { | ||
| init_test_env(); | ||
|
|
||
| let rpc_url = std::env::var("SOLANA_MAINNET_RPC_URL") | ||
| .expect("SOLANA_MAINNET_RPC_URL must be set in .env.test"); | ||
|
|
||
| IdlCache::new(rpc_url) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard external-RPC tests to avoid CI flakes/panics
expect("SOLANA_MAINNET_RPC_URL must be set...") will panic in CI. Skip gracefully when env is missing.
Apply:
fn create_test_idl_cache() -> IdlCache {
- init_test_env();
-
- let rpc_url = std::env::var("SOLANA_MAINNET_RPC_URL")
- .expect("SOLANA_MAINNET_RPC_URL must be set in .env.test");
-
- IdlCache::new(rpc_url)
+ init_test_env();
+ let rpc_url = match std::env::var("SOLANA_MAINNET_RPC_URL") {
+ Ok(v) => v,
+ Err(_) => {
+ eprintln!("SKIP: SOLANA_MAINNET_RPC_URL not set; skipping integration test.");
+ // Provide a dummy URL; callers should early-return before using it.
+ return IdlCache::new("http://localhost:0".into());
+ }
+ };
+ IdlCache::new(rpc_url)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /// Helper to create test IDL cache | |
| fn create_test_idl_cache() -> IdlCache { | |
| init_test_env(); | |
| let rpc_url = std::env::var("SOLANA_MAINNET_RPC_URL") | |
| .expect("SOLANA_MAINNET_RPC_URL must be set in .env.test"); | |
| IdlCache::new(rpc_url) | |
| } | |
| /// Helper to create test IDL cache | |
| fn create_test_idl_cache() -> IdlCache { | |
| init_test_env(); | |
| let rpc_url = match std::env::var("SOLANA_MAINNET_RPC_URL") { | |
| Ok(v) => v, | |
| Err(_) => { | |
| eprintln!("SKIP: SOLANA_MAINNET_RPC_URL not set; skipping integration test."); | |
| // Provide a dummy URL; callers should early-return before using it. | |
| return IdlCache::new("http://localhost:0".into()); | |
| } | |
| }; | |
| IdlCache::new(rpc_url) | |
| } |
🤖 Prompt for AI Agents
In solana-core/tests/integration_tests.rs around lines 21 to 29, the helper
currently calls expect on SOLANA_MAINNET_RPC_URL which will panic in CI; change
the helper to avoid panicking by returning an Option<IdlCache> (or Result)
instead of IdlCache, use std::env::var("SOLANA_MAINNET_RPC_URL").ok() to check
for the env var, and if missing return None so callers/tests can detect the
absence and skip the test gracefully (or propagate a clear error) rather than
panic.
| #[tokio::test] | ||
| async fn test_jupiter_swap_instruction() { | ||
| let cache = create_test_idl_cache(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mark exploratory test as ignored (passes even on failure)
This test doesn’t assert invariants; it prints on both Ok/Err. Mark as ignored until account resolution is ready.
-#[tokio::test]
+#[tokio::test]
+#[ignore] // enable when account resolution is implemented and assertions are added📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #[tokio::test] | |
| async fn test_jupiter_swap_instruction() { | |
| let cache = create_test_idl_cache(); | |
| #[tokio::test] | |
| #[ignore] // enable when account resolution is implemented and assertions are added | |
| async fn test_jupiter_swap_instruction() { | |
| let cache = create_test_idl_cache(); |
🤖 Prompt for AI Agents
In solana-core/tests/integration_tests.rs around lines 35 to 37, the exploratory
test prints results for both Ok and Err and does not assert invariants; mark it
as ignored until account resolution is implemented by adding the #[ignore] test
attribute to the test declaration (e.g. change the attributes on the test
function to include #[ignore]) so the test runner skips it during normal runs.
| } else { | ||
| hex::decode(&prepared.instruction.data).expect("Valid hex") | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Ensure hex crate is available in dev-deps
hex::decode/encode requires the hex crate. Verify it exists in workspace dev-dependencies.
🏁 Script executed:
#!/bin/bash
# Verify hex and base64 versions in Cargo.toml files
rg -nP '^\\s*hex\\s*=\\s*' -g '*Cargo.toml' -S
rg -nP '^\\s*base64\\s*=\\s*' -g '*Cargo.toml' -SLength of output: 0
I need to use a broader search approach to verify the hex crate availability. The empty output suggests the regex pattern may not match the actual formatting.
🏁 Script executed:
#!/bin/bash
# Search for hex usage in the test file
echo "=== Checking for hex usage in integration_tests.rs ==="
fd 'integration_tests.rs' -x cat {} | head -50
echo -e "\n=== Search for hex in Cargo.toml files (all occurrences) ==="
fd 'Cargo.toml' -x grep -n 'hex' {}
echo -e "\n=== Check workspace root Cargo.toml structure ==="
cat Cargo.toml 2>/dev/null | head -100Length of output: 4021
🏁 Script executed:
#!/bin/bash
# Search for hex usage in the test file
echo "=== Checking for hex usage in integration_tests.rs ==="
fd 'integration_tests.rs' -x cat {} | head -50
echo -e "\n=== Search for hex in Cargo.toml files (all occurrences) ==="
fd 'Cargo.toml' -x grep -n 'hex' {}
echo -e "\n=== Check workspace root Cargo.toml structure ==="
cat Cargo.toml 2>/dev/null | head -100Length of output: 4021
🏁 Script executed:
#!/bin/bash
# Find solana-core Cargo.toml and check dev-dependencies
echo "=== solana-core Cargo.toml content ==="
cat solana-core/Cargo.toml
echo -e "\n=== Check for hex in solana-core dev-dependencies ==="
grep -A 50 '\[dev-dependencies\]' solana-core/Cargo.toml | head -60Length of output: 1730
Add hex to solana-core dev-dependencies
The hex crate is declared in [dependencies] but missing from [dev-dependencies]. Integration tests are compiled with dev-dependencies only, so hex::decode at lines 201-203 will fail to compile. Add hex = { workspace = true } to the [dev-dependencies] section of solana-core/Cargo.toml.
🤖 Prompt for AI Agents
In solana-core/tests/integration_tests.rs around lines 201 to 203, the test uses
hex::decode but the hex crate is only listed under [dependencies]; add hex = {
workspace = true } to the [dev-dependencies] section of solana-core/Cargo.toml
so integration tests (which compile with dev-dependencies) can use hex::decode.
| "name": "route_plan", | ||
| "type": { "vec": { "defined": { "name": "RoutePlanStep" } } } | ||
| }, | ||
| { "name": "out_amount", "type": "u64" }, | ||
| { "name": "quoted_in_amount", "type": "u64" }, | ||
| { "name": "slippage_bps", "type": "u16" }, | ||
| { "name": "platform_fee_bps", "type": "u8" } | ||
| ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IDL uses complex defined types your encoder doesn’t support yet.
Many args reference defined structs/enums (e.g., vec, Swap variants). Current InstructionEncoder returns UnsupportedType for IdlType::Defined, so these instructions can’t be encoded yet. Prioritize Defined types support or gate tests to simpler instructions until ready.
Also applies to: 670-993
🤖 Prompt for AI Agents
In solana-core/tests/jupiter_idl.json around lines 149-156 (and similarly for
ranges ~670-993), the IDL declares fields using defined complex types (e.g.,
vec<RoutePlanStep>, Swap variants) which our InstructionEncoder currently treats
as IdlType::Defined and returns UnsupportedType; update the encoder to handle
IdlType::Defined by resolving the referenced type definitions (structs/enums)
from the IDL and recursively encoding their fields/variants (including vectors
and nested defined types), or alternatively adjust the tests/IDL to use only
primitive/inline types until Defined support is implemented; ensure
decoding/encoding symmetry and add unit tests covering a struct, an enum
(variant), and a vec of a defined struct.
Summary by CodeRabbit
Release Notes
New Features
/solana/programAPI endpoint for executing Solana program instructions with type-safe instruction building via IDL supportTests
Documentation
Chores