From daba04c031156dcbe5f11a0390b5f7535299ebcd Mon Sep 17 00:00:00 2001
From: Loris Moulin <45130584+l0r1s@users.noreply.github.com>
Date: Tue, 3 Oct 2023 12:38:40 +0200
Subject: [PATCH] Feat/genesis overrides (#111)

- Added genesis_overrides fields to RelaychainConfig and ParachainConfig
builders and added logic to merge it into the specs being created
---
 crates/configuration/Cargo.toml               |  1 +
 crates/configuration/src/parachain.rs         | 19 +++++++++
 crates/configuration/src/relaychain.rs        | 19 +++++++++
 .../orchestrator/src/generators/chain_spec.rs | 40 +++++++++++++++++--
 .../src/network_spec/parachain.rs             |  4 ++
 .../src/network_spec/relaychain.rs            |  4 ++
 6 files changed, 83 insertions(+), 4 deletions(-)

diff --git a/crates/configuration/Cargo.toml b/crates/configuration/Cargo.toml
index 56d70d8..b7525f2 100644
--- a/crates/configuration/Cargo.toml
+++ b/crates/configuration/Cargo.toml
@@ -12,3 +12,4 @@ thiserror = { workspace = true }
 anyhow = { workspace = true }
 serde = { workspace = true, features = ["derive"] }
 toml = { workspace = true }
+serde_json = { workspace = true }
diff --git a/crates/configuration/src/parachain.rs b/crates/configuration/src/parachain.rs
index 543b778..8dd9c9b 100644
--- a/crates/configuration/src/parachain.rs
+++ b/crates/configuration/src/parachain.rs
@@ -122,6 +122,7 @@ pub struct ParachainConfig {
     is_cumulus_based: bool,
     #[serde(skip_serializing_if = "std::vec::Vec::is_empty", default)]
     bootnodes_addresses: Vec<Multiaddr>,
+    genesis_overrides: Option<serde_json::Value>,
     #[serde(skip_serializing_if = "std::vec::Vec::is_empty", default)]
     collators: Vec<NodeConfig>,
 }
@@ -197,6 +198,11 @@ impl ParachainConfig {
         self.genesis_state_generator.as_ref()
     }
 
+    /// The genesis overrides as a JSON value.
+    pub fn genesis_overrides(&self) -> Option<&serde_json::Value> {
+        self.genesis_overrides.as_ref()
+    }
+
     /// The location of a pre-existing chain specification for the parachain.
     pub fn chain_spec_path(&self) -> Option<&AssetLocation> {
         self.chain_spec_path.as_ref()
@@ -250,6 +256,7 @@ impl Default for ParachainConfigBuilder<Initial> {
                 genesis_wasm_generator: None,
                 genesis_state_path: None,
                 genesis_state_generator: None,
+                genesis_overrides: None,
                 chain_spec_path: None,
                 is_cumulus_based: true,
                 bootnodes_addresses: vec![],
@@ -540,6 +547,18 @@ impl ParachainConfigBuilder<WithId> {
         }
     }
 
+    /// Set the genesis overrides as a JSON object.
+    pub fn with_genesis_overrides(self, genesis_overrides: impl Into<serde_json::Value>) -> Self {
+        Self::transition(
+            ParachainConfig {
+                genesis_overrides: Some(genesis_overrides.into()),
+                ..self.config
+            },
+            self.validation_context,
+            self.errors,
+        )
+    }
+
     /// Set the location of a pre-existing chain specification for the parachain.
     pub fn with_chain_spec_path(self, location: impl Into<AssetLocation>) -> Self {
         Self::transition(
diff --git a/crates/configuration/src/relaychain.rs b/crates/configuration/src/relaychain.rs
index b087ddc..f226b79 100644
--- a/crates/configuration/src/relaychain.rs
+++ b/crates/configuration/src/relaychain.rs
@@ -27,6 +27,7 @@ pub struct RelaychainConfig {
     max_nominations: Option<u8>,
     #[serde(skip_serializing_if = "std::vec::Vec::is_empty", default)]
     nodes: Vec<NodeConfig>,
+    genesis_overrides: Option<serde_json::Value>,
 }
 
 impl RelaychainConfig {
@@ -75,6 +76,11 @@ impl RelaychainConfig {
         self.max_nominations
     }
 
+    /// The genesis overrides as a JSON value.
+    pub fn genesis_overrides(&self) -> Option<&serde_json::Value> {
+        self.genesis_overrides.as_ref()
+    }
+
     /// The nodes of the relay chain.
     pub fn nodes(&self) -> Vec<&NodeConfig> {
         self.nodes.iter().collect::<Vec<&NodeConfig>>()
@@ -114,6 +120,7 @@ impl Default for RelaychainConfigBuilder<Initial> {
                 chain_spec_path: None,
                 random_nominators_count: None,
                 max_nominations: None,
+                genesis_overrides: None,
                 nodes: vec![],
             },
             validation_context: Default::default(),
@@ -314,6 +321,18 @@ impl RelaychainConfigBuilder<WithChain> {
         )
     }
 
+    /// Set the genesis overrides as a JSON object.
+    pub fn with_genesis_overrides(self, genesis_overrides: impl Into<serde_json::Value>) -> Self {
+        Self::transition(
+            RelaychainConfig {
+                genesis_overrides: Some(genesis_overrides.into()),
+                ..self.config
+            },
+            self.validation_context,
+            self.errors,
+        )
+    }
+
     /// Add a new node using a nested [`NodeConfigBuilder`].
     pub fn with_node(
         self,
diff --git a/crates/orchestrator/src/generators/chain_spec.rs b/crates/orchestrator/src/generators/chain_spec.rs
index f302d65..9497ebf 100644
--- a/crates/orchestrator/src/generators/chain_spec.rs
+++ b/crates/orchestrator/src/generators/chain_spec.rs
@@ -311,7 +311,13 @@ impl ChainSpec {
                 .map_err(GeneratorError::ChainSpecGeneration)?;
 
             // make genesis overrides first.
-            // override_genesis()
+            if let Some(overrides) = &para.genesis_overrides {
+                if let Some(genesis) = chain_spec_json.pointer_mut(&format!("{}/genesis", pointer))
+                {
+                    override_genesis(genesis, overrides);
+                }
+            }
+
             clear_authorities(&pointer, &mut chain_spec_json);
 
             // Get validators to add as authorities
@@ -381,7 +387,12 @@ impl ChainSpec {
                 .map_err(GeneratorError::ChainSpecGeneration)?;
 
             // make genesis overrides first.
-            // override_genesis()
+            if let Some(overrides) = &relaychain.genesis_overrides {
+                if let Some(genesis) = chain_spec_json.pointer_mut(&format!("{}/genesis", pointer))
+                {
+                    override_genesis(genesis, overrides);
+                }
+            }
 
             println!(
                 "{:#?}",
@@ -596,8 +607,29 @@ fn get_runtime_config_pointer(chain_spec_json: &serde_json::Value) -> Result<Str
 }
 
 // Override `genesis` key if present
-fn override_genesis() {
-    todo!()
+fn override_genesis(genesis: &mut serde_json::Value, overrides: &serde_json::Value) {
+    if let (Some(genesis_obj), Some(overrides_obj)) =
+        (genesis.as_object_mut(), overrides.as_object())
+    {
+        for overrides_key in overrides_obj.keys() {
+            // we only want to override keys present in the genesis object
+            if let Some(genesis_value) = genesis_obj.get_mut(overrides_key) {
+                match (&genesis_value, overrides_obj.get(overrides_key)) {
+                    // recurse if genesis value is an object
+                    (serde_json::Value::Object(_), Some(overrides_value))
+                        if overrides_value.is_object() =>
+                    {
+                        override_genesis(genesis_value, overrides_value);
+                    },
+                    // override if genesis value not an object
+                    (_, Some(overrides_value)) => {
+                        *genesis_value = overrides_value.clone();
+                    },
+                    _ => {},
+                }
+            }
+        }
+    }
 }
 
 fn clear_authorities(runtime_config_ptr: &str, chain_spec_json: &mut serde_json::Value) {
diff --git a/crates/orchestrator/src/network_spec/parachain.rs b/crates/orchestrator/src/network_spec/parachain.rs
index d5334df..33e1217 100644
--- a/crates/orchestrator/src/network_spec/parachain.rs
+++ b/crates/orchestrator/src/network_spec/parachain.rs
@@ -57,6 +57,9 @@ pub struct ParachainSpec {
     /// Genesis wasm to register the parachain
     pub(crate) genesis_wasm: ParaArtifact,
 
+    /// Genesis overrides as JSON value.
+    pub(crate) genesis_overrides: Option<serde_json::Value>,
+
     /// Collators to spawn
     pub(crate) collators: Vec<NodeSpec>,
 }
@@ -174,6 +177,7 @@ impl ParachainSpec {
             initial_balance: config.initial_balance(),
             genesis_state,
             genesis_wasm,
+            genesis_overrides: config.genesis_overrides().cloned(),
             collators,
         };
 
diff --git a/crates/orchestrator/src/network_spec/relaychain.rs b/crates/orchestrator/src/network_spec/relaychain.rs
index 1f1fd60..a7adee2 100644
--- a/crates/orchestrator/src/network_spec/relaychain.rs
+++ b/crates/orchestrator/src/network_spec/relaychain.rs
@@ -43,6 +43,9 @@ pub struct RelaychainSpec {
     /// Set the max nominators value (used with PoS networks).
     pub(crate) max_nominations: u8,
 
+    /// Genesis overrides as JSON value.
+    pub(crate) genesis_overrides: Option<serde_json::Value>,
+
     /// Nodes to run.
     pub(crate) nodes: Vec<NodeSpec>,
 }
@@ -107,6 +110,7 @@ impl RelaychainSpec {
             chain_spec,
             random_nominators_count: config.random_nominators_count().unwrap_or(0),
             max_nominations: config.max_nominations().unwrap_or(24),
+            genesis_overrides: config.genesis_overrides().cloned(),
             nodes,
         })
     }
-- 
GitLab