Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
b5de874
chore(graph, runtime, store): resolve compiler warnings
isum Sep 25, 2025
0ff1e56
feat(graph): add Nozzle Flight service client
isum Sep 25, 2025
f5e6fc6
feat(graph): add Nozzle stream aggregator
isum Sep 25, 2025
1e6136c
feat(graph): add Nozzle data decoder
isum Sep 25, 2025
dc9e82d
feat(graph): add SQL query parser, resolver and validator
isum Sep 25, 2025
23f4656
feat(graph): use a new identifier type in Nozzle related modules
isum Sep 25, 2025
d3a873e
feat(graph): add Nozzle Subgraph schema generation
isum Sep 25, 2025
39eef8b
feat(graph): add Nozzle Subgraph manifest
isum Sep 25, 2025
6090826
feat(graph): add reorg handling to the Nozzle FlightClient
isum Oct 28, 2025
439cc49
feat(graph, core): extend SubgraphInstanceManager trait
isum Oct 28, 2025
3b8eca6
feat(core, graph, node): allow multiple subgraph instance managers
isum Oct 28, 2025
fedf345
test: fix compile errors
isum Oct 28, 2025
5195ddd
fix(graph): update deterministic error patterns in Nozzle Flight client
isum Oct 28, 2025
3533ea0
feat(graph): add Nozzle related ENV variables
isum Oct 28, 2025
097ec93
fix(graph): make block range filter return a new query
isum Oct 28, 2025
dac6f67
feat(graph): add decoding utilities
isum Oct 28, 2025
d9ba7a8
fix(graph): use decoding utilities in the stream aggregator
isum Oct 28, 2025
25e88c5
feat(graph): add more details to Nozzle data sources
isum Oct 28, 2025
f7b49f6
feat(core, graph, node): add Nozzle subgraph deployment
isum Oct 28, 2025
9986685
feat(graph): add a dedicated Nozzle manifest resolver
isum Oct 28, 2025
c4c1672
feat(node): add shutdown token
isum Oct 28, 2025
fe153e5
feat(core, graph): add Nozzle subgraph runner
isum Oct 28, 2025
71f2649
chore(all): rename Nozzle to Amp
isum Oct 29, 2025
634fd38
fix(graph): produce consistent query hashes for logging
isum Nov 5, 2025
4204585
fix(core, graph): simplify SQL query requirements
isum Nov 5, 2025
02480e0
chore(graph): fix typos
isum Nov 5, 2025
ff6971f
fix(graph): use nozzle-resume header name
isum Nov 5, 2025
0894e0a
fix(graph): extend common column aliases
isum Nov 6, 2025
dbc4810
fix(core, graph): use named streams in the stream aggregator
isum Nov 6, 2025
b3e9b53
fix(core, graph): simplify working with identifiers
isum Nov 6, 2025
783ed99
fix(graph): validate query output column names
isum Nov 6, 2025
34b0525
fix(graph): support all versions of the Amp server
isum Nov 6, 2025
9af12b3
fix(graph): extend the list of common column aliases
isum Nov 11, 2025
3a28f67
test(graph): add decoder unit-tests
isum Nov 11, 2025
b3044af
feat(core, graph): add Amp subgraph metrics
isum Nov 18, 2025
c96c0c6
fix(graph): allow more complex dataset and table names
isum Nov 20, 2025
ef5c9a9
fix(graph): remove CTE name requirements
isum Nov 20, 2025
a9fa049
fix(graph, node): add option to authenticate Flight service requests
isum Nov 20, 2025
83b7da9
fix(graph): update temporary predefined list of source context tables
isum Nov 21, 2025
957ef3a
docs: add docs for Amp-powered subgraphs
isum Nov 21, 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
1,565 changes: 1,453 additions & 112 deletions Cargo.lock

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,21 @@ substreams-entity-change = "2"
substreams-near-core = "=0.10.2"
rand = { version = "0.9.1", features = ["os_rng"] }

prometheus = "0.13.4"

# Dependencies related to Amp subgraphs
ahash = "0.8.11"
alloy = { version = "1.0.12", default-features = false, features = ["json-abi", "serde"] }
arrow = { version = "=55.0.0" }
arrow-flight = { version = "=55.0.0", features = ["flight-sql-experimental"] }
futures = "0.3.31"
half = "2.7.1"
indoc = "2.0.7"
lazy-regex = "3.4.1"
parking_lot = "0.12.4"
sqlparser-latest = { version = "0.57.0", package = "sqlparser", features = ["visitor"] }
tokio-util = "0.7.15"

# Incremental compilation on Rust 1.58 causes an ICE on build. As soon as graph node builds again, these can be removed.
[profile.test]
incremental = false
Expand Down
1 change: 1 addition & 0 deletions chain/ethereum/src/runtime/runtime_adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ impl blockchain::RuntimeAdapter<Chain> for RuntimeAdapter {
create_host_fns(abis, archive, call_cache, eth_adapters, eth_call_gas)
}
data_source::DataSource::Offchain(_) => vec![],
data_source::DataSource::Amp(_) => vec![],
};

Ok(host_fns)
Expand Down
13 changes: 13 additions & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ thiserror = { workspace = true }
cid = "0.11.1"
anyhow = "1.0"

# Dependencies related to Amp subgraphs
alloy.workspace = true
arrow.workspace = true
chrono.workspace = true
futures.workspace = true
indoc.workspace = true
itertools.workspace = true
parking_lot.workspace = true
prometheus.workspace = true
slog.workspace = true
tokio-util.workspace = true
tokio.workspace = true

[dev-dependencies]
tower-test = { git = "https://github.com/tower-rs/tower.git" }
wiremock = "0.6.3"
166 changes: 166 additions & 0 deletions core/src/amp_subgraph/manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
use std::sync::Arc;

use anyhow::Context;
use async_trait::async_trait;
use graph::{
amp,
components::{
link_resolver::LinkResolver,
metrics::MetricsRegistry,
store::{DeploymentLocator, SubgraphStore},
subgraph::SubgraphInstanceManager,
},
env::EnvVars,
log::factory::LoggerFactory,
prelude::CheapClone,
};
use slog::{debug, error};
use tokio_util::sync::CancellationToken;

use super::{runner, Metrics, Monitor};

/// Manages Amp subgraph runner futures.
///
/// Creates and schedules Amp subgraph runner futures for execution on demand.
/// Also handles stopping previously started Amp subgraph runners.
pub struct Manager<SS, LR, AC> {
logger_factory: LoggerFactory,
metrics_registry: Arc<MetricsRegistry>,
env_vars: Arc<EnvVars>,
monitor: Monitor,
subgraph_store: Arc<SS>,
link_resolver: Arc<LR>,
amp_client: Arc<AC>,
}

impl<SS, LR, AC> Manager<SS, LR, AC>
where
SS: SubgraphStore,
LR: LinkResolver,
AC: amp::Client,
{
/// Creates a new Amp subgraph manager.
pub fn new(
logger_factory: &LoggerFactory,
metrics_registry: Arc<MetricsRegistry>,
env_vars: Arc<EnvVars>,
cancel_token: &CancellationToken,
subgraph_store: Arc<SS>,
link_resolver: Arc<LR>,
amp_client: Arc<AC>,
) -> Self {
let logger = logger_factory.component_logger("AmpSubgraphManager", None);
let logger_factory = logger_factory.with_parent(logger);

let monitor = Monitor::new(&logger_factory, cancel_token);

Self {
logger_factory,
metrics_registry,
env_vars,
monitor,
subgraph_store,
link_resolver,
amp_client,
}
}
}

#[async_trait]
impl<SS, LR, AC> SubgraphInstanceManager for Manager<SS, LR, AC>
where
SS: SubgraphStore,
LR: LinkResolver,
AC: amp::Client + Send + Sync + 'static,
{
fn can_manage(
&self,
deployment: &DeploymentLocator,
raw_manifest: &serde_yaml::Mapping,
) -> bool {
let logger = self.logger_factory.subgraph_logger(deployment);
let can_manage = amp::manifest::is_amp_manifest(raw_manifest);

if can_manage {
debug!(logger, "Subgraph assigned to Amp instance manager");
}

can_manage
}

async fn start_subgraph(
self: Arc<Self>,
deployment: DeploymentLocator,
raw_manifest: serde_yaml::Mapping,
_stop_block: Option<i32>,
) {
let manager = self.cheap_clone();

self.monitor.start(
deployment.cheap_clone(),
Box::new(move |cancel_token| {
Box::pin(async move {
let logger = manager.logger_factory.subgraph_logger(&deployment);

let store = manager
.subgraph_store
.cheap_clone()
.writable(logger.cheap_clone(), deployment.id, Vec::new().into())
.await
.context("failed to create writable store")?;

let metrics = Metrics::new(
&logger,
manager.metrics_registry.cheap_clone(),
store.cheap_clone(),
deployment.hash.cheap_clone(),
);

let manifest = amp::Manifest::resolve::<graph_chain_ethereum::Chain, _>(
&logger,
manager.link_resolver.cheap_clone(),
manager.amp_client.cheap_clone(),
manager.env_vars.max_spec_version.cheap_clone(),
deployment.hash.cheap_clone(),
raw_manifest,
)
.await?;

store
.start_subgraph_deployment(&logger)
.await
.context("failed to start subgraph deployment")?;

let runner_context = runner::Context::new(
&logger,
&manager.env_vars.amp,
manager.amp_client.cheap_clone(),
store,
deployment.hash.cheap_clone(),
manifest,
metrics,
);

let runner_result = runner::new_runner(runner_context)(cancel_token).await;

match manager.subgraph_store.stop_subgraph(&deployment).await {
Ok(()) => {
debug!(logger, "Subgraph writer stopped");
}
Err(e) => {
error!(logger, "Failed to stop subgraph writer";
"e" => ?e
);
}
}

runner_result
})
}),
);
}

async fn stop_subgraph(&self, deployment: DeploymentLocator) {
self.monitor.stop(deployment);
}
}
Loading