Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
47cedac
chore: add local laser-sdk with downgraded yellowstone crates (v7.0.0)
thlorenz Oct 18, 2025
77e6cab
chore: move out common pubsub code to separate module
thlorenz Oct 18, 2025
f48da9b
chore: initial chainlink laser
thlorenz Oct 18, 2025
a4f0e07
chore: subscription update uses Account
thlorenz Oct 22, 2025
5aac783
feat: laser grpc implemented with adjustments to pubsub as well
thlorenz Oct 24, 2025
f529c5f
feat: integrate Laser gRPC as an endpoint option
thlorenz Oct 24, 2025
d0311b4
chore: remove invalid import
thlorenz Oct 26, 2025
81f8abc
feat: initial manual test for helius laser gRPC integration
thlorenz Oct 26, 2025
d4135af
chore: don't multiplex laser gRPC connections
thlorenz Oct 26, 2025
0ba9501
chore: debug log for which pubsub client is used
thlorenz Oct 26, 2025
39d2af8
fix: run laser client actor on separate tokio task
thlorenz Oct 26, 2025
c2f1e33
chore: test script working
thlorenz Oct 26, 2025
b667331
feat: fully automated manual test
thlorenz Oct 26, 2025
0899746
chore: use helius-sdk github fork
thlorenz Oct 26, 2025
aa0c8b8
chore: fmt
thlorenz Oct 26, 2025
ba3580b
chore: update cargo lock of test-integration
thlorenz Oct 26, 2025
c5bc16e
fix: lint issue
thlorenz Oct 26, 2025
c76a66d
chore: adapt integration tests and add test helpers
thlorenz Oct 26, 2025
500ebc0
chore: fix outdatec comment
thlorenz Oct 27, 2025
508bf98
chore: remove Send + Sync implementations from ChainLaserActor
thlorenz Oct 27, 2025
4bc1d53
chore: remove unnecessary async in test script
thlorenz Oct 27, 2025
df5aaf5
chore: add phony targets
thlorenz Oct 27, 2025
e85f603
chore: better cleanup for manual test
thlorenz Oct 27, 2025
7e9510e
chore: properly failing when script returns non-zero
thlorenz Oct 27, 2025
6cf4f72
chore: parallel initialization of pubsub clients
thlorenz Oct 27, 2025
9e06ee4
chore: typo fix
thlorenz Oct 27, 2025
775ca4a
chore: style improvement
thlorenz Oct 27, 2025
c763599
chore: fmt
thlorenz Oct 27, 2025
c78772e
chore: init stream only when needed
thlorenz Oct 27, 2025
ed09009
chore: address empty select issue
thlorenz Oct 27, 2025
56215a1
chore: fix lint
thlorenz Oct 27, 2025
3cf8f13
chore: return ok after warning about already subscribed account
thlorenz Oct 27, 2025
d3f293a
fix: send response for recycle connections
thlorenz Oct 27, 2025
be27ee7
chore: send error when removing non-existent sub for laser
thlorenz Oct 27, 2025
c0741de
Merge branch 'master' into thlorenz/laser-grpc
thlorenz Oct 29, 2025
e646942
chore: default lru capacity to 7_000
thlorenz Oct 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
435 changes: 406 additions & 29 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ fs_extra = "1.3.0"
futures = "0.3"
futures-util = "0.3.30"
git-version = "0.3.9"
helius-laserstream = { git = "https://github.com/magicblock-labs/laserstream-sdk", branch = "v0.2.2-magicblock" }
hostname = "0.4.0"
http-body-util = "0.1.3"
hyper = "1.6.0"
Expand Down
4 changes: 2 additions & 2 deletions magicblock-accounts/src/scheduled_commits_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use magicblock_account_cloner::ChainlinkCloner;
use magicblock_accounts_db::AccountsDb;
use magicblock_chainlink::{
remote_account_provider::{
chain_pubsub_client::ChainPubsubClientImpl,
chain_rpc_client::ChainRpcClientImpl,
chain_updates_client::ChainUpdatesClient,
},
submux::SubMuxClient,
Chainlink,
Expand Down Expand Up @@ -48,7 +48,7 @@ const POISONED_MUTEX_MSG: &str =

pub type ChainlinkImpl = Chainlink<
ChainRpcClientImpl,
SubMuxClient<ChainPubsubClientImpl>,
SubMuxClient<ChainUpdatesClient>,
AccountsDb,
ChainlinkCloner,
>;
Expand Down
4 changes: 2 additions & 2 deletions magicblock-aperture/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use magicblock_account_cloner::ChainlinkCloner;
use magicblock_accounts_db::AccountsDb;
use magicblock_chainlink::{
remote_account_provider::{
chain_pubsub_client::ChainPubsubClientImpl,
chain_rpc_client::ChainRpcClientImpl,
chain_updates_client::ChainUpdatesClient,
},
submux::SubMuxClient,
Chainlink,
Expand All @@ -21,7 +21,7 @@ use transactions::TransactionsCache;

pub type ChainlinkImpl = Chainlink<
ChainRpcClientImpl,
SubMuxClient<ChainPubsubClientImpl>,
SubMuxClient<ChainUpdatesClient>,
AccountsDb,
ChainlinkCloner,
>;
Expand Down
43 changes: 31 additions & 12 deletions magicblock-api/src/external_config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::HashSet;

use magicblock_accounts::{AccountsConfig, RemoteCluster};
use magicblock_chainlink::remote_account_provider::chain_laser_client::is_helius_laser_url;
use magicblock_config::{errors::ConfigResult, RemoteConfig};
use solana_sdk::pubkey::Pubkey;

Expand Down Expand Up @@ -59,19 +60,29 @@ pub fn remote_cluster_from_remote(
.map(|ws_urls| ws_urls.iter().map(|x| x.to_string()).collect())
.unwrap_or_else(|| {
let mut ws_url = rpc_url.clone();
ws_url
.set_scheme(if rpc_url.scheme() == "https" {
"wss"
} else {
"ws"
})
.expect("valid scheme");
if let Some(port) = ws_url.port() {
// We only multiplex if the ws urls are actually websockets and only
// then do we adjust the protocol.
// We do not need to do this if we subscribe via GRPC, i.e. helius
// laser which is more stable.
let is_grpc = is_grpc_url(ws_url.as_ref());
if !is_grpc {
ws_url
.set_port(Some(port + 1))
.expect("valid url with port");
.set_scheme(if rpc_url.scheme() == "https" {
"wss"
} else {
"ws"
})
.expect("valid scheme");
if let Some(port) = ws_url.port() {
ws_url
.set_port(Some(port + 1))
.expect("valid url with port");
}
}
vec![ws_url.to_string(); WS_MULTIPLEX_COUNT]
vec![
ws_url.to_string();
if is_grpc { 1 } else { WS_MULTIPLEX_COUNT }
]
});
(rpc_url.to_string(), ws_urls)
}
Expand All @@ -88,10 +99,14 @@ pub fn remote_cluster_from_remote(
.first()
.expect("at least one ws url must be set for CustomWithWs")
.to_string();
let ws_urls = vec![ws_url; 3];
let is_grpc = is_grpc_url(&ws_url.to_string());
let ws_urls =
vec![ws_url; if is_grpc { 1 } else { WS_MULTIPLEX_COUNT }];
(rpc_url, ws_urls)
}
CustomWithMultipleWs => {
// NOTE: we assume that if multiple ws urls are provided the user wants
// to multiplex no matter if any is a GRPC based pubsub.
let rpc_url = remote_config
.url
.as_ref()
Expand Down Expand Up @@ -138,3 +153,7 @@ fn allowed_program_ids_from_allowed_programs(
None
}
}

fn is_grpc_url(url: &str) -> bool {
is_helius_laser_url(url)
}
9 changes: 4 additions & 5 deletions magicblock-api/src/magic_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use magicblock_aperture::{
use magicblock_chainlink::{
config::ChainlinkConfig,
remote_account_provider::{
chain_pubsub_client::ChainPubsubClientImpl,
chain_rpc_client::ChainRpcClientImpl,
chain_updates_client::ChainUpdatesClient,
},
submux::SubMuxClient,
Chainlink,
Expand Down Expand Up @@ -98,7 +98,7 @@ use crate::{

type ChainlinkImpl = Chainlink<
ChainRpcClientImpl,
SubMuxClient<ChainPubsubClientImpl>,
SubMuxClient<ChainUpdatesClient>,
AccountsDb,
ChainlinkCloner,
>;
Expand Down Expand Up @@ -392,9 +392,8 @@ impl MagicValidator {
let endpoints = remote_cluster
.ws_urls
.iter()
.map(|pubsub_url| Endpoint {
rpc_url: rpc_url.clone(),
pubsub_url: pubsub_url.clone(),
.map(|pubsub_url| {
Endpoint::new(rpc_url.clone(), pubsub_url.to_string())
})
.collect::<Vec<_>>();

Expand Down
1 change: 1 addition & 0 deletions magicblock-chainlink/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ async-trait = { workspace = true }
bincode = { workspace = true }
env_logger = { workspace = true }
futures-util = { workspace = true }
helius-laserstream = { workspace = true }
log = { workspace = true }
lru = { workspace = true }
magicblock-core = { workspace = true }
Expand Down
11 changes: 3 additions & 8 deletions magicblock-chainlink/src/chainlink/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use crate::{
config::ChainlinkConfig,
fetch_cloner::FetchAndCloneResult,
remote_account_provider::{
ChainPubsubClient, ChainPubsubClientImpl, ChainRpcClient,
ChainRpcClientImpl, Endpoint, RemoteAccountProvider,
chain_updates_client::ChainUpdatesClient, ChainPubsubClient,
ChainRpcClient, ChainRpcClientImpl, Endpoint, RemoteAccountProvider,
},
submux::SubMuxClient,
};
Expand Down Expand Up @@ -89,12 +89,7 @@ impl<T: ChainRpcClient, U: ChainPubsubClient, V: AccountsBank, C: Cloner>
faucet_pubkey: Pubkey,
config: ChainlinkConfig,
) -> ChainlinkResult<
Chainlink<
ChainRpcClientImpl,
SubMuxClient<ChainPubsubClientImpl>,
V,
C,
>,
Chainlink<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>, V, C>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

Stabilize the public return type with an alias to avoid downstream churn.

Exposing SubMuxClient<ChainUpdatesClient> in the public signature leaks backend details and may force downstream changes next time the backend evolves. Add a stable alias and use it in the signature.

Apply:

@@
-    ) -> ChainlinkResult<
-        Chainlink<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>, V, C>,
-    > {
+    ) -> ChainlinkResult<
+        Chainlink<ChainRpcClientImpl, ChainUpdatesMuxClient, V, C>,
+    > {

And define the alias once in this module (near other pub uses):

@@
 pub use blacklisted_accounts::*;
 
+/// Stable alias for the multiplexed updates client to keep backend details abstract.
+pub type ChainUpdatesMuxClient = SubMuxClient<ChainUpdatesClient>;

Run to find other occurrences that could switch to the alias:


🏁 Script executed:

#!/bin/bash
rg -nP --type=rust -C1 'SubMuxClient\s*<\s*ChainUpdatesClient\s*>'

Length of output: 3562


Define and use a public type alias to stabilize the chain updates client interface.

The pattern SubMuxClient<ChainUpdatesClient> appears across 14 locations in the codebase (test-integration, magicblock-api, magicblock-chainlink, magicblock-aperture, magicblock-accounts). Exposing this concrete backend type in public signatures creates tight coupling and forces downstream changes when the implementation evolves.

Suggested approach:

Define the alias in magicblock-chainlink/src/chainlink/mod.rs:

 pub use blacklisted_accounts::*;
 
+/// Stable alias for the multiplexed updates client to keep backend details abstract.
+pub type ChainUpdatesMuxClient = SubMuxClient<ChainUpdatesClient>;

Update the public return type at line 92:

-    ) -> ChainlinkResult<
-        Chainlink<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>, V, C>,
-    > {
+    ) -> ChainlinkResult<
+        Chainlink<ChainRpcClientImpl, ChainUpdatesMuxClient, V, C>,
+    > {

Additional refactoring opportunities: Consider updating other public signatures in magicblock-chainlink/src/remote_account_provider/mod.rs (lines 172, 184, 275, 302, 960) and similar public exports across other modules to use the alias for consistency.

📝 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.

Suggested change
Chainlink<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>, V, C>,
Chainlink<ChainRpcClientImpl, ChainUpdatesMuxClient, V, C>,
🤖 Prompt for AI Agents
magicblock-chainlink/src/chainlink/mod.rs around line 92: define a public type
alias such as pub type ChainUpdatesBackend = SubMuxClient<ChainUpdatesClient>;
then replace the exposed concrete type usage at line 92
(Chainlink<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>, V, C>) with the
alias (Chainlink<ChainRpcClientImpl, ChainUpdatesBackend, V, C>) to decouple the
public API from the concrete implementation; also scan and update other public
signatures in magicblock-chainlink/src/remote_account_provider/mod.rs (lines
172, 184, 275, 302, 960) and other modules cited to use the same alias to
stabilize the interface.

> {
// Extract accounts provider and create fetch cloner while connecting
// the subscription channel
Expand Down
Loading
Loading