Skip to content

Commit 4e8c344

Browse files
apollo_node_config,apollo_config_manager,apollo_integration_tests: retire preset config-generation path
Delete the flat-preset config generation now that everything loads native: remove ConfigPointersMap and DeploymentBaseAppConfig::{as_value, dump_config_file, config_pointers_map, get/modify_config_pointers, validate_all_pointer_targets_set}. Migrate the integration-test setup and config_manager_runner_tests off the pointer- resolved as_value path to the native as_native_value path (the config_manager test was already failing at HEAD: it passed a single --config_file but native load requires two). Promote normalize_pointer_groups to a shared cfg(testing/test) helper in config_utils. create_node_config now sets validator_id directly on the real struct (the native dump ignored the pointer map). This unblocks deleting CONFIG_POINTERS (its only remaining consumers are the secrets-schema bin + the transient equivalence test). apollo_config_manager 15/15, apollo_node_config 34/34, apollo_deployments 8/8 green; integration bins compile. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent b42f836 commit 4e8c344

10 files changed

Lines changed: 222 additions & 379 deletions

File tree

crates/apollo_config_manager/src/config_manager_runner_tests.rs

Lines changed: 106 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::fs;
21
use std::sync::Arc;
32
use std::time::Duration;
43

@@ -9,77 +8,138 @@ use apollo_config_manager_types::communication::{
98
SharedConfigManagerClient,
109
};
1110
use apollo_consensus_config::config::ConsensusDynamicConfig;
12-
use apollo_node_config::config_utils::DeploymentBaseAppConfig;
13-
use apollo_node_config::definitions::ConfigPointersMap;
11+
use apollo_node_config::config_utils::normalize_pointer_groups;
1412
use apollo_node_config::node_config::{NodeDynamicConfig, SequencerNodeConfig};
1513
use serde_json::Value;
1614
use starknet_api::core::ContractAddress;
17-
use tempfile::NamedTempFile;
15+
use tempfile::TempDir;
1816
use tokio::sync::mpsc::channel;
1917
use tokio::task::yield_now;
2018
use tokio::time::{interval, timeout};
2119
use tracing_test::traced_test;
2220

2321
use crate::config_manager_runner::ConfigManagerRunner;
2422

25-
// An arbitrary hex-str config entry to be replaced.
26-
const VALIDATOR_ID_CONFIG_ENTRY: &str = "validator_id";
23+
// The nested native path of the validator id within the `SequencerNodeConfig` field hierarchy.
24+
const VALIDATOR_ID_CONFIG_PATH: &[&str] =
25+
&["consensus_manager_config", "consensus_manager_config", "dynamic_config", "validator_id"];
2726
const TEST_TIMEOUT_SECS: u64 = 1;
27+
const BASE_CONFIG_FILE_NAME: &str = "base_config.json";
28+
const SECRETS_CONFIG_FILE_NAME: &str = "secrets_config.json";
29+
30+
// `Sensitive<T>` fields whose derived `Serialize` emits an asymmetric wire shape (a JSON array or
31+
// `null`) that their string-reading `deserialize_with` cannot consume, and whose deserializer maps
32+
// the empty string back to `None`. A whole-config `to_value`/`from_value` round-trip fails on them
33+
// unless they are rewritten to that empty string (see
34+
// `apollo_node_config::config_serde_symmetry_test` and `apollo_config::converters`). The native
35+
// node loader avoids this in production by overlaying real values from the secrets file; this test
36+
// carries no secrets, so it neutralizes them instead.
37+
const NONE_ABLE_SENSITIVE_KEYS: &[&str] = &["secret_key", "url_header_list"];
38+
39+
// `EthereumBaseLayerConfig::ordered_l1_endpoint_urls: Vec<Sensitive<Url>>` shares the same
40+
// serialize-array/deserialize-string asymmetry, but its deserializer reads a (space-separated) URL
41+
// list and `validate_node_config` rejects an empty list, so it has no `None`/empty form to
42+
// substitute. Rewrite it to a single valid URL string so the config both round-trips and validates.
43+
const ENDPOINT_URLS_KEY: &str = "ordered_l1_endpoint_urls";
44+
const PLACEHOLDER_ENDPOINT_URL: &str = "https://localhost:8545";
45+
46+
/// Recursively rewrites the asymmetric `Sensitive` fields in a nested native config map to the
47+
/// string wire shape their deserializers read, so the config round-trips through serde and passes
48+
/// validation.
49+
fn neutralize_sensitive_fields(config: &mut Value) {
50+
match config {
51+
Value::Object(map) => {
52+
for (key, value) in map.iter_mut() {
53+
if NONE_ABLE_SENSITIVE_KEYS.contains(&key.as_str()) {
54+
*value = Value::String(String::new());
55+
} else if key == ENDPOINT_URLS_KEY {
56+
*value = Value::String(PLACEHOLDER_ENDPOINT_URL.to_string());
57+
} else {
58+
neutralize_sensitive_fields(value);
59+
}
60+
}
61+
}
62+
Value::Array(items) => items.iter_mut().for_each(neutralize_sensitive_fields),
63+
_ => {}
64+
}
65+
}
2866

29-
/// Creates a temporary config file with specific test values and returns CLI args pointing to it.
30-
fn create_temp_config_file_and_args() -> (NamedTempFile, Vec<String>, String) {
31-
let config = SequencerNodeConfig::default();
32-
let config_pointers_map = ConfigPointersMap::create_for_testing();
33-
34-
let base_app_config = DeploymentBaseAppConfig::new(config, config_pointers_map);
67+
/// Returns a mutable reference to the leaf `validator_id` value within a nested native config map.
68+
fn validator_id_entry(config: &mut Value) -> &mut Value {
69+
let mut entry = config;
70+
for segment in VALIDATOR_ID_CONFIG_PATH {
71+
entry = entry
72+
.as_object_mut()
73+
.expect("Native config node must be a JSON object")
74+
.get_mut(*segment)
75+
.unwrap_or_else(|| panic!("Missing native config segment {segment:?}"));
76+
}
77+
entry
78+
}
3579

36-
// Create a temporary file
37-
let temp_file = NamedTempFile::new().expect("Failed to create temporary config file");
80+
/// Creates a temporary directory holding a native base config file and an (empty) secrets file,
81+
/// and returns CLI args pointing the native loader at both. The directory handle is returned so the
82+
/// files outlive the test. Also returns the validator id read from the base config.
83+
fn create_temp_config_files_and_args() -> (TempDir, Vec<String>, String) {
84+
let mut config = SequencerNodeConfig::default();
85+
// `SequencerNodeConfig::default()` does not have internally consistent pointer-group values
86+
// (chain_id, fee tokens, etc.); reconcile them so the loaded config passes the cross-component
87+
// equality validation, mirroring what pointer resolution did at load time.
88+
normalize_pointer_groups(&mut config);
89+
let mut base_config =
90+
serde_json::to_value(&config).expect("Should be able to serialize config to value");
91+
neutralize_sensitive_fields(&mut base_config);
92+
93+
let validator_id = validator_id_entry(&mut base_config)
94+
.as_str()
95+
.expect("validator_id must be a string")
96+
.to_string();
3897

39-
base_app_config.dump_config_file(temp_file.path());
98+
let temp_dir = TempDir::new().expect("Failed to create temporary config dir");
99+
let base_config_path = temp_dir.path().join(BASE_CONFIG_FILE_NAME);
100+
let secrets_config_path = temp_dir.path().join(SECRETS_CONFIG_FILE_NAME);
40101

41-
let current_validator_id = base_app_config
42-
.as_value()
43-
.get(VALIDATOR_ID_CONFIG_ENTRY)
44-
.and_then(|v| v.as_str())
45-
.expect("Missing or non-string hex value at VALIDATOR_ID_CONFIG_ENTRY")
46-
.to_string();
102+
let base_content =
103+
serde_json::to_string_pretty(&base_config).expect("Failed to serialize base config");
104+
std::fs::write(&base_config_path, base_content).expect("Failed to write base config file");
105+
// The native loader requires a secrets file overlaid onto the base; the test carries none.
106+
std::fs::write(&secrets_config_path, "{}").expect("Failed to write secrets config file");
47107

48-
// Create cli args pointing to the temp file
108+
// The native loader expects two files: the nested base config and the flat secrets config.
49109
let cli_args = vec![
50110
"test_node".to_string(),
51111
CONFIG_FILE_ARG.to_string(),
52-
temp_file.path().to_string_lossy().to_string(),
112+
base_config_path.to_string_lossy().to_string(),
113+
CONFIG_FILE_ARG.to_string(),
114+
secrets_config_path.to_string_lossy().to_string(),
53115
];
54116

55-
(temp_file, cli_args, current_validator_id)
117+
(temp_dir, cli_args, validator_id)
56118
}
57119

58-
fn update_config_file(temp_file: &NamedTempFile) -> String {
120+
/// Bumps the validator id in the native base config file by one and returns the new value.
121+
fn update_config_file(temp_dir: &TempDir) -> String {
122+
let base_config_path = temp_dir.path().join(BASE_CONFIG_FILE_NAME);
59123
let current_content =
60-
fs::read_to_string(temp_file.path()).expect("Failed to read temp config file");
124+
std::fs::read_to_string(&base_config_path).expect("Failed to read base config file");
61125

62-
// Parse JSON (expects a top-level object/map)
63-
let mut root: Value = serde_json::from_str(&current_content).expect("Config is not valid JSON");
64-
let obj = root.as_object_mut().expect("Config root must be a JSON object");
126+
let mut base_config: Value =
127+
serde_json::from_str(&current_content).expect("Config is not valid JSON");
65128

66-
// Get the hex string at the key VALIDATOR_ID_CONFIG_ENTRY (e.g., "validator_id": "0x00ff")
67-
let current_validator_id = obj
68-
.get(VALIDATOR_ID_CONFIG_ENTRY)
69-
.and_then(|v| v.as_str())
70-
.expect("Missing or non-string hex value at VALIDATOR_ID_CONFIG_ENTRY");
129+
let validator_id_value = validator_id_entry(&mut base_config);
130+
let current_validator_id = validator_id_value.as_str().expect("validator_id must be a string");
71131
assert!(current_validator_id.starts_with("0x"), "Expected a 0x-prefixed hex string");
72132

73-
// Bump by 1 and preserve width
133+
// Bump by 1 and preserve width.
74134
let hex = &current_validator_id[2..]; // drop "0x"
75135
let n = u128::from_str_radix(hex, 16).unwrap() + 1;
76136
let new_validator_id = format!("0x{:0x}", n);
77137

78-
// Update JSON and write back
79-
obj.insert(VALIDATOR_ID_CONFIG_ENTRY.to_string(), Value::String(new_validator_id.clone()));
80-
let updated_content = serde_json::to_string_pretty(&root).expect("Failed to serialize JSON");
81-
fs::write(temp_file.path(), updated_content)
82-
.expect("Failed to write updated config to temp file");
138+
*validator_id_value = Value::String(new_validator_id.clone());
139+
let updated_content =
140+
serde_json::to_string_pretty(&base_config).expect("Failed to serialize JSON");
141+
std::fs::write(&base_config_path, updated_content)
142+
.expect("Failed to write updated config to base config file");
83143

84144
new_validator_id
85145
}
@@ -94,8 +154,8 @@ async fn config_manager_runner_update_config_with_changed_values() {
94154
// Set a config manager config.
95155
let config_manager_config = ConfigManagerConfig::default();
96156

97-
// Create a temporary config file and get the validator id value.
98-
let (temp_file, cli_args, validator_id_value) = create_temp_config_file_and_args();
157+
// Create temporary config files and get the validator id value.
158+
let (temp_dir, cli_args, validator_id_value) = create_temp_config_files_and_args();
99159

100160
let node_dynamic_config = NodeDynamicConfig::default();
101161

@@ -128,7 +188,7 @@ async fn config_manager_runner_update_config_with_changed_values() {
128188
);
129189

130190
// Edit the config file and then trigger a config update, expecting the new validator id.
131-
let new_validator_id = update_config_file(&temp_file);
191+
let new_validator_id = update_config_file(&temp_dir);
132192
let expected_validator_id = ContractAddress::from(hex_to_u128(new_validator_id.as_str()));
133193

134194
let second_update_config_result = config_manager_runner.update_config().await;
@@ -145,8 +205,8 @@ async fn config_manager_runner_update_config_with_changed_values() {
145205

146206
#[tokio::test]
147207
async fn watcher_triggers_update_on_file_change() {
148-
// Prepare temp config file and CLI args.
149-
let (temp_file, cli_args, _) = create_temp_config_file_and_args();
208+
// Prepare temp config files and CLI args.
209+
let (temp_dir, cli_args, _) = create_temp_config_files_and_args();
150210

151211
// Channel to observe that update_config was called.
152212
let (tx, mut rx) = channel(1);
@@ -174,7 +234,7 @@ async fn watcher_triggers_update_on_file_change() {
174234
yield_now().await;
175235

176236
// Modify the config file to trigger an event.
177-
let _ = update_config_file(&temp_file);
237+
let _ = update_config_file(&temp_dir);
178238

179239
// Wait until the update call is observed or timeout.
180240
timeout(Duration::from_secs(TEST_TIMEOUT_SECS), rx.recv())

crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ use apollo_infra_utils::test_utils::TestIdentifier;
55
use apollo_integration_tests::integration_test_manager::IntegrationTestManager;
66
use apollo_integration_tests::integration_test_utils::integration_test_setup;
77
use apollo_integration_tests::utils::NodeDescriptor;
8-
use apollo_node_config::definitions::ConfigPointersMap;
98
use apollo_node_config::node_config::SequencerNodeConfig;
10-
use serde_json::Value;
119
use starknet_api::block::BlockNumber;
1210
use tracing::info;
1311

@@ -142,34 +140,11 @@ fn modify_revert_config_idle_nodes(
142140
node_indices: HashSet<usize>,
143141
revert_up_to_and_including: Option<BlockNumber>,
144142
) {
145-
integration_test_manager.modify_config_pointers_idle_nodes(
146-
node_indices.clone(),
147-
|config_pointers| {
148-
modify_revert_config_pointers(config_pointers, revert_up_to_and_including)
149-
},
150-
);
151-
integration_test_manager.modify_config_idle_nodes(node_indices, |config_pointers| {
152-
modify_revert_config(config_pointers, revert_up_to_and_including)
143+
integration_test_manager.modify_config_idle_nodes(node_indices, |config| {
144+
modify_revert_config(config, revert_up_to_and_including)
153145
});
154146
}
155147

156-
fn modify_revert_config_pointers(
157-
config_pointers: &mut ConfigPointersMap,
158-
revert_up_to_and_including: Option<BlockNumber>,
159-
) {
160-
let should_revert = revert_up_to_and_including.is_some();
161-
config_pointers.change_target_value("revert_config.should_revert", Value::from(should_revert));
162-
163-
// If should revert is false, the revert_up_to_and_including value is irrelevant.
164-
if should_revert {
165-
let revert_up_to_and_including = revert_up_to_and_including.unwrap();
166-
config_pointers.change_target_value(
167-
"revert_config.revert_up_to_and_including",
168-
Value::from(revert_up_to_and_including.0),
169-
);
170-
}
171-
}
172-
173148
fn modify_revert_config(
174149
config: &mut SequencerNodeConfig,
175150
revert_up_to_and_including: Option<BlockNumber>,

crates/apollo_integration_tests/src/executable_setup.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use apollo_monitoring_endpoint::test_utils::MonitoringClient;
55
use apollo_monitoring_endpoint_config::config::MonitoringEndpointConfig;
66
use apollo_node::test_utils::node_runner::NodeRunner;
77
use apollo_node_config::config_utils::DeploymentBaseAppConfig;
8-
use apollo_node_config::definitions::ConfigPointersMap;
98
use apollo_node_config::node_config::SequencerNodeConfig;
109
use tempfile::{tempdir, TempDir};
1110
use tokio::fs::create_dir_all;
@@ -118,14 +117,6 @@ impl ExecutableSetup {
118117
self.dump_config_file_changes();
119118
}
120119

121-
pub fn modify_config_pointers<F>(&mut self, modify_config_pointers_fn: F)
122-
where
123-
F: Fn(&mut ConfigPointersMap),
124-
{
125-
self.base_app_config.modify_config_pointers(modify_config_pointers_fn);
126-
self.dump_config_file_changes();
127-
}
128-
129120
pub fn get_config(&self) -> &SequencerNodeConfig {
130121
self.base_app_config.get_config()
131122
}

crates/apollo_integration_tests/src/flow_test_setup.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ impl FlowSequencerSetup {
307307
};
308308

309309
// Derive the configuration for the sequencer node.
310-
let (mut node_config, _config_pointers_map) = create_node_config(
310+
let mut node_config = create_node_config(
311311
&mut available_ports,
312312
chain_info,
313313
storage_config,

crates/apollo_integration_tests/src/integration_test_manager.rs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use apollo_node_config::component_execution_config::{
2121
ReactiveComponentExecutionConfig,
2222
};
2323
use apollo_node_config::config_utils::DeploymentBaseAppConfig;
24-
use apollo_node_config::definitions::ConfigPointersMap;
2524
use apollo_node_config::node_config::SequencerNodeConfig;
2625
use apollo_storage::storage_reader_server_test_utils::send_storage_reader_http_request;
2726
use apollo_storage::storage_reader_types::{StorageReaderRequest, StorageReaderResponse};
@@ -564,27 +563,6 @@ impl IntegrationTestManager {
564563
});
565564
}
566565

567-
pub fn modify_config_pointers_idle_nodes<F>(
568-
&mut self,
569-
nodes_to_modify_config_pointers: HashSet<usize>,
570-
modify_config_pointers_fn: F,
571-
) where
572-
F: Fn(&mut ConfigPointersMap) + Copy,
573-
{
574-
info!("Modifying specified nodes config pointers.");
575-
576-
nodes_to_modify_config_pointers.into_iter().for_each(|node_index| {
577-
let node_setup = self
578-
.idle_nodes
579-
.get_mut(&node_index)
580-
.unwrap_or_else(|| panic!("Node {node_index} does not exist in idle_nodes."));
581-
node_setup.get_executables_mut().for_each(|executable| {
582-
info!("Modifying {} config pointers.", executable.node_executable_id);
583-
executable.modify_config_pointers(modify_config_pointers_fn);
584-
});
585-
});
586-
}
587-
588566
pub async fn await_revert_all_running_nodes(
589567
&self,
590568
expected_block_number: BlockNumber,
@@ -1407,7 +1385,7 @@ async fn get_sequencer_setup_configs(
14071385
..Default::default()
14081386
};
14091387

1410-
let (config, config_pointers_map) = create_node_config(
1388+
let config = create_node_config(
14111389
&mut config_available_ports,
14121390
chain_info.clone(),
14131391
storage_setup.storage_config.clone(),
@@ -1426,7 +1404,7 @@ async fn get_sequencer_setup_configs(
14261404
!is_proof_flow,
14271405
);
14281406

1429-
let base_app_config = DeploymentBaseAppConfig::new(config, config_pointers_map);
1407+
let base_app_config = DeploymentBaseAppConfig::new(config);
14301408

14311409
let node_executable_id = NodeExecutableId::new(
14321410
node_index,

0 commit comments

Comments
 (0)