Skip to content

Commit f14f753

Browse files
apollo_deployments: assemble and deserialize node config from jsonnet
1 parent 5ad58a2 commit f14f753

3 files changed

Lines changed: 238 additions & 23 deletions

File tree

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// Testing `overrides` that satisfies the applicative config's schema.
2+
{
3+
// Cross-cutting values (the CONFIG_POINTERS targets), referenced as flat keys.
4+
chain_id: 'SN_SEPOLIA',
5+
eth_fee_token_address: '0x1',
6+
strk_fee_token_address: '0x2',
7+
recorder_url: 'https://recorder_url',
8+
starknet_url: 'https://starknet_url/',
9+
native_classes_whitelist: '[]',
10+
validator_id: '0x64',
11+
versioned_constants_overrides: null,
12+
13+
// Per-component required values, at their exact schema paths.
14+
base_layer_config: {
15+
bpo1_start_block_number: 9456501,
16+
bpo2_start_block_number: 9504747,
17+
fusaka_no_bpo_start_block_number: 9408577,
18+
starknet_contract_address: '0x0000000000000000000000000000000000000001',
19+
},
20+
batcher_config: {
21+
dynamic_config: {
22+
n_concurrent_txs: 100,
23+
proposer_idle_detection_delay_millis: 1500,
24+
},
25+
static_config: {
26+
block_builder_config: {
27+
bouncer_config: {
28+
block_max_capacity: {
29+
n_events: 5000,
30+
receipt_l2_gas: 5800000000,
31+
state_diff_size: 4000,
32+
},
33+
},
34+
execute_config: {
35+
n_workers: 28,
36+
},
37+
},
38+
first_block_with_partial_block_hash: null,
39+
},
40+
},
41+
class_manager_config: {
42+
static_config: {
43+
class_manager_config: {
44+
max_compiled_contract_class_object_size: 4089446,
45+
},
46+
},
47+
},
48+
committer_config: {
49+
storage_config: {
50+
cache_size: 10000000,
51+
inner_storage_config: {
52+
cache_size: 8589934592,
53+
},
54+
},
55+
verify_state_diff_hash: true,
56+
},
57+
consensus_manager_config: {
58+
consensus_manager_config: {
59+
dynamic_config: {
60+
require_virtual_proposer_vote: false,
61+
timeouts: {
62+
proposal: {
63+
base: 9.1,
64+
max: 15.0,
65+
},
66+
},
67+
},
68+
},
69+
context_config: {
70+
dynamic_config: {
71+
build_proposal_margin_millis: 1000,
72+
compare_retrospective_block_hash: false,
73+
min_l2_gas_price_per_height: '',
74+
override_eth_to_fri_rate: null,
75+
override_l1_data_gas_price_fri: null,
76+
override_l1_gas_price_fri: null,
77+
override_l2_gas_price_fri: null,
78+
},
79+
},
80+
network_config: {
81+
advertised_multiaddr: null,
82+
bootstrap_peer_multiaddr: null,
83+
port: 53080,
84+
},
85+
staking_manager_config: {
86+
dynamic_config: {
87+
default_committee: '0,100:',
88+
override_committee: null,
89+
},
90+
},
91+
},
92+
gateway_config: {
93+
static_config: {
94+
authorized_declarer_accounts: null,
95+
proof_archive_writer_config: {
96+
bucket_name: 'test-bucket',
97+
},
98+
stateful_tx_validator_config: {
99+
max_allowed_nonce_gap: 200,
100+
},
101+
stateless_tx_validator_config: {
102+
max_contract_bytecode_size: 81920,
103+
min_gas_price: 8000000000,
104+
},
105+
},
106+
},
107+
http_server_config: {
108+
static_config: {
109+
port: 8080,
110+
},
111+
},
112+
mempool_config: {
113+
dynamic_config: {
114+
transaction_ttl: 300,
115+
},
116+
},
117+
mempool_p2p_config: {
118+
network_config: {
119+
advertised_multiaddr: null,
120+
bootstrap_peer_multiaddr: null,
121+
port: 53200,
122+
},
123+
},
124+
monitoring_endpoint_config: {
125+
port: 8082,
126+
},
127+
sierra_compiler_config: {
128+
audited_libfuncs_only: false,
129+
max_bytecode_size: 81920,
130+
},
131+
state_sync_config: {
132+
static_config: {
133+
central_sync_client_config: {
134+
central_source_config: {
135+
class_cache_size: 128,
136+
concurrent_requests: 20,
137+
http_headers: '',
138+
max_classes_to_download: 20,
139+
max_state_updates_to_download: 20,
140+
max_state_updates_to_store_in_memory: 20,
141+
retry_config: {
142+
max_retries: 10,
143+
retry_base_millis: 30,
144+
retry_max_delay_millis: 30000,
145+
},
146+
starknet_url: 'https://starknet_url/',
147+
},
148+
sync_config: {
149+
base_layer_propagation_sleep_duration: 10,
150+
blocks_before_tip_to_disable_batching: 100,
151+
blocks_max_stream_size: 1000,
152+
collect_pending_data: false,
153+
latest_block_poll_interval_millis: 500,
154+
recoverable_error_sleep_duration: 3,
155+
state_updates_max_stream_size: 1000,
156+
store_sierras_and_casms_block_threshold: 0,
157+
verify_blocks: false,
158+
},
159+
},
160+
network_config: null,
161+
p2p_sync_client_config: null,
162+
rpc_config: {
163+
port: 8083,
164+
},
165+
},
166+
},
167+
}

crates/apollo_deployments/src/deployment_definitions_test.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@ use strum::IntoEnumIterator;
1010
use tempfile::NamedTempFile;
1111

1212
use crate::deployment_definitions::ComponentConfigInService;
13-
use crate::jsonnet::{
14-
test_consolidated_infra_matches_rust,
15-
test_distributed_infra_matches_rust,
16-
test_hybrid_infra_matches_rust,
17-
};
13+
use crate::deployments::consolidated::ConsolidatedNodeServiceName;
14+
use crate::deployments::distributed::DistributedNodeServiceName;
15+
use crate::deployments::hybrid::HybridNodeServiceName;
16+
use crate::jsonnet::{assert_build_deserializes, assert_infra_matches_rust};
1817
use crate::service::NodeType;
1918
use crate::test_utils::SecretsConfigOverride;
2019

@@ -27,7 +26,7 @@ fn hybrid_infra_matches_rust() {
2726
env::set_current_dir(resolve_project_relative_path("").unwrap())
2827
.expect("Couldn't set working dir.");
2928

30-
test_hybrid_infra_matches_rust();
29+
assert_infra_matches_rust::<HybridNodeServiceName>();
3130
}
3231

3332
/// Verifies the jsonnet consolidated infra config matches the Rust deployment definitions
@@ -37,7 +36,7 @@ fn consolidated_infra_matches_rust() {
3736
env::set_current_dir(resolve_project_relative_path("").unwrap())
3837
.expect("Couldn't set working dir.");
3938

40-
test_consolidated_infra_matches_rust();
39+
assert_infra_matches_rust::<ConsolidatedNodeServiceName>();
4140
}
4241

4342
/// Verifies the jsonnet distributed infra config matches the Rust deployment definitions
@@ -47,7 +46,34 @@ fn distributed_infra_matches_rust() {
4746
env::set_current_dir(resolve_project_relative_path("").unwrap())
4847
.expect("Couldn't set working dir.");
4948

50-
test_distributed_infra_matches_rust();
49+
assert_infra_matches_rust::<DistributedNodeServiceName>();
50+
}
51+
52+
/// Verifies build('consolidated', overrides) 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', overrides) 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', overrides) 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>();
5177
}
5278

5379
/// Test that the deployment file is up to date.

crates/apollo_deployments/src/jsonnet.rs

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
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;
67
use strum::IntoEnumIterator;
78

8-
use crate::deployments::consolidated::ConsolidatedNodeServiceName;
9-
use crate::deployments::distributed::DistributedNodeServiceName;
10-
use crate::deployments::hybrid::HybridNodeServiceName;
119
use crate::service::{GetComponentConfigs, NodeService, NodeType};
1210

1311
const JSONNET_DIR: &str = "crates/apollo_deployments/jsonnet";
14-
12+
const TESTING_OVERRIDES_PATH: &str = "testing/overrides.libsonnet";
1513
/// Evaluates `services/<layout>.jsonnet` (the per-layout infra renderer) and returns its JSON.
1614
fn eval_layout_infra(layout: &str) -> Value {
1715
let state = jsonnet_state();
@@ -32,7 +30,7 @@ fn jsonnet_state() -> State {
3230

3331
/// Asserts the jsonnet-derived infra of every service of layout `S` matches the Rust source of
3432
/// truth (`<layout>.rs`'s `get_component_configs`).
35-
fn assert_infra_matches_rust<S>()
33+
pub(crate) fn assert_infra_matches_rust<S>()
3634
where
3735
S: GetComponentConfigs + IntoEnumIterator + Into<NodeService>,
3836
{
@@ -60,19 +58,43 @@ where
6058
}
6159
}
6260

63-
/// The jsonnet hybrid infra matches `deployments/hybrid.rs`.
64-
pub fn test_hybrid_infra_matches_rust() {
65-
assert_infra_matches_rust::<HybridNodeServiceName>();
61+
/// Evaluates `build(layout, overrides)` and returns its JSON: a map from service name to that
62+
/// service's fully-assembled config..
63+
fn eval_build(layout: &str, overrides: &str) -> Value {
64+
let state = jsonnet_state();
65+
let _guard = state.enter();
66+
let layout_literal = serde_json::to_string(layout).unwrap();
67+
let snippet =
68+
format!("(import 'lib/build.libsonnet').build({layout_literal}, import '{overrides}')");
69+
let val = state
70+
.evaluate_snippet("build_entry.jsonnet", snippet)
71+
.expect("build.libsonnet failed to evaluate");
72+
serde_json::to_value(&val).expect("build result is not serializable")
6673
}
6774

68-
/// The jsonnet consolidated infra matches `deployments/consolidated.rs`.
69-
pub fn test_consolidated_infra_matches_rust() {
70-
assert_infra_matches_rust::<ConsolidatedNodeServiceName>();
71-
}
75+
/// Asserts that `build(layout, testing_overrides)` produces, for every service of layout `S`, an
76+
/// object that deserializes into `SequencerNodeConfig`.
77+
pub(crate) fn assert_build_deserializes<S>()
78+
where
79+
S: GetComponentConfigs + IntoEnumIterator + Into<NodeService>,
80+
{
81+
let some_service: NodeService =
82+
S::iter().next().expect("a layout has at least one service").into();
83+
let layout = NodeType::from(&some_service).to_string();
84+
let built = eval_build(&layout, TESTING_OVERRIDES_PATH);
85+
let services = built.as_object().unwrap();
7286

73-
/// The jsonnet distributed infra matches `deployments/distributed.rs`.
74-
pub fn test_distributed_infra_matches_rust() {
75-
assert_infra_matches_rust::<DistributedNodeServiceName>();
87+
// Sanity check: the build result should have at least one service.
88+
assert!(!services.is_empty(), "build({layout}) produced no services");
89+
90+
for (service_name, config) in services {
91+
serde_json::from_value::<SequencerNodeConfig>(config.clone()).unwrap_or_else(|error| {
92+
panic!(
93+
"service {service_name} of layout {layout} does not deserialize into \
94+
SequencerNodeConfig: {error}"
95+
)
96+
});
97+
}
7698
}
7799

78100
/// Clones a `components` map with `url` and `port` removed from each component object — the two

0 commit comments

Comments
 (0)