Skip to content

Commit 4a9076f

Browse files
apollo_deployments: assemble and deserialize node config from jsonnet
1 parent 4951016 commit 4a9076f

4 files changed

Lines changed: 130 additions & 6 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Testing chain_params: the per chain/env mandatory values, read directly by the applicative config.
2+
{
3+
chain_id: 'SN_SEPOLIA',
4+
native_classes_whitelist: '[]',
5+
recorder_url: 'https://recorder_url',
6+
starknet_url: 'https://starknet_url/',
7+
base_layer_config: {
8+
bpo1_start_block_number: 9456501,
9+
bpo2_start_block_number: 9504747,
10+
fusaka_no_bpo_start_block_number: 9408577,
11+
starknet_contract_address: '0x0000000000000000000000000000000000000001',
12+
},
13+
batcher_config: {
14+
static_config: {
15+
first_block_with_partial_block_hash: null,
16+
},
17+
},
18+
consensus_manager_config: {
19+
network_config: {
20+
advertised_multiaddr: null,
21+
bootstrap_peer_multiaddr: null,
22+
},
23+
staking_manager_config: {
24+
dynamic_config: {
25+
default_committee: '0,100:',
26+
},
27+
},
28+
},
29+
gateway_config: {
30+
static_config: {
31+
proof_archive_writer_config: {
32+
bucket_name: 'test-bucket',
33+
},
34+
},
35+
},
36+
mempool_p2p_config: {
37+
network_config: {
38+
advertised_multiaddr: null,
39+
bootstrap_peer_multiaddr: null,
40+
},
41+
},
42+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Testing node_params: the per-node mandatory values, read directly by the applicative config.
2+
{
3+
validator_id: '0x64',
4+
}

crates/apollo_deployments/src/deployment_definitions_test.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::deployment_definitions::ComponentConfigInService;
1313
use crate::deployments::consolidated::ConsolidatedNodeServiceName;
1414
use crate::deployments::distributed::DistributedNodeServiceName;
1515
use crate::deployments::hybrid::HybridNodeServiceName;
16-
use crate::jsonnet::assert_infra_matches_rust;
16+
use crate::jsonnet::{assert_build_deserializes, assert_infra_matches_rust};
1717
use crate::service::NodeType;
1818
use crate::test_utils::SecretsConfigOverride;
1919

@@ -49,6 +49,33 @@ fn distributed_infra_matches_rust() {
4949
assert_infra_matches_rust::<DistributedNodeServiceName>();
5050
}
5151

52+
/// Verifies build('consolidated', params) deserializes into SequencerNodeConfig per service.
53+
#[test]
54+
fn build_consolidated_deserializes_into_node_config() {
55+
env::set_current_dir(resolve_project_relative_path("").unwrap())
56+
.expect("Couldn't set working dir.");
57+
58+
assert_build_deserializes::<ConsolidatedNodeServiceName>();
59+
}
60+
61+
/// Verifies build('hybrid', params) deserializes into SequencerNodeConfig per service.
62+
#[test]
63+
fn build_hybrid_deserializes_into_node_config() {
64+
env::set_current_dir(resolve_project_relative_path("").unwrap())
65+
.expect("Couldn't set working dir.");
66+
67+
assert_build_deserializes::<HybridNodeServiceName>();
68+
}
69+
70+
/// Verifies build('distributed', params) deserializes into SequencerNodeConfig per service.
71+
#[test]
72+
fn build_distributed_deserializes_into_node_config() {
73+
env::set_current_dir(resolve_project_relative_path("").unwrap())
74+
.expect("Couldn't set working dir.");
75+
76+
assert_build_deserializes::<DistributedNodeServiceName>();
77+
}
78+
5279
/// Test that the deployment file is up to date.
5380
#[test]
5481
fn deployment_files_are_up_to_date() {

crates/apollo_deployments/src/jsonnet.rs

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::path::PathBuf;
22

3+
use apollo_node_config::node_config::SequencerNodeConfig;
34
use jrsonnet_evaluator::trace::PathResolver;
45
use jrsonnet_evaluator::{FileImportResolver, State};
56
use serde_json::Value;
@@ -8,14 +9,24 @@ use strum::IntoEnumIterator;
89
use crate::service::{GetComponentConfigs, NodeService, NodeType};
910

1011
const JSONNET_DIR: &str = "crates/apollo_deployments/jsonnet";
12+
const TESTING_CHAIN_PARAMS_PATH: &str = "testing/chain_params.libsonnet";
13+
const TESTING_NODE_PARAMS_PATH: &str = "testing/node_params.libsonnet";
1114

12-
/// Evaluates `services/<layout>.jsonnet` (the per-layout infra renderer) and returns its JSON.
13-
fn eval_layout_infra(layout: &str) -> Value {
15+
/// Evaluates a jsonnet `snippet` against a fresh evaluator (stdlib installed, imports resolved
16+
/// relative to the jsonnet dir) and converts the result to a serde `Value`. `context` labels the
17+
/// evaluation in panic messages.
18+
fn eval_jsonnet(context: &str, snippet: String) -> Value {
1419
let state = jsonnet_state();
1520
let _guard = state.enter();
16-
let entry = format!("services/{layout}.jsonnet");
17-
let val = state.import(entry.as_str()).expect("failed to evaluate the layout infra renderer");
18-
serde_json::to_value(&val).expect("infra config is not serializable")
21+
let val = state
22+
.evaluate_snippet(context.to_owned(), snippet)
23+
.expect("Failed to evaluate jsonnet snippet.");
24+
serde_json::to_value(&val).expect("Failed to serialize jsonnet result to Value.")
25+
}
26+
27+
/// Evaluates `services/<layout>.jsonnet` (the per-layout infra renderer) and returns its JSON.
28+
fn eval_layout_infra(layout: &str) -> Value {
29+
eval_jsonnet("layout infra", format!("import 'services/{layout}.jsonnet'"))
1930
}
2031

2132
/// A jrsonnet evaluator with the stdlib installed and file imports resolved relative to the jsonnet
@@ -57,6 +68,46 @@ where
5768
}
5869
}
5970

71+
/// Evaluates `build(layout, { chain_params, node_params })` and returns its JSON: a map from service
72+
/// name to that service's fully-assembled config. The testing params supply only the mandatory
73+
/// chain_params + node_params buckets; `replacers` is omitted, so every replacer falls back to its
74+
/// applicative-config default.
75+
fn eval_build(layout: &str) -> Value {
76+
let layout_literal = serde_json::to_string(layout).unwrap();
77+
eval_jsonnet(
78+
"build",
79+
format!(
80+
"(import 'lib/build.libsonnet').build({layout_literal}, {{ chain_params: import \
81+
'{TESTING_CHAIN_PARAMS_PATH}', node_params: import '{TESTING_NODE_PARAMS_PATH}' }})"
82+
),
83+
)
84+
}
85+
86+
/// Asserts that `build(layout, params)` produces, for every service of layout `S`, an object that
87+
/// deserializes into `SequencerNodeConfig`.
88+
pub(crate) fn assert_build_deserializes<S>()
89+
where
90+
S: GetComponentConfigs + IntoEnumIterator + Into<NodeService>,
91+
{
92+
let some_service: NodeService =
93+
S::iter().next().expect("a layout has at least one service").into();
94+
let layout = NodeType::from(&some_service).to_string();
95+
let built = eval_build(&layout);
96+
let services = built.as_object().unwrap();
97+
98+
// Sanity check: the build result should have at least one service.
99+
assert!(!services.is_empty(), "build({layout}) produced no services");
100+
101+
for (service_name, config) in services {
102+
serde_json::from_value::<SequencerNodeConfig>(config.clone()).unwrap_or_else(|error| {
103+
panic!(
104+
"service {service_name} of layout {layout} does not deserialize into \
105+
SequencerNodeConfig: {error}"
106+
)
107+
});
108+
}
109+
}
110+
60111
/// Clones a `components` map with `url` and `port` removed from each component object — the two
61112
/// fields the Rust config leaves as deploy-time placeholders, so they can't be compared against the
62113
/// jsonnet's baked-in real values.

0 commit comments

Comments
 (0)