From fcfe9f0e48c24064aaf188e6d732bcd660873677 Mon Sep 17 00:00:00 2001
From: librelois <c@elo.tf>
Date: Sat, 15 Jan 2022 16:35:30 +0100
Subject: [PATCH] chore: add compilation feature for each runtime

---
 Cargo.toml                   |   4 --
 node/Cargo.toml              |  19 +++--
 node/src/chain_spec.rs       |   3 +
 node/src/chain_spec/gtest.rs |   4 +-
 node/src/command.rs          | 131 +++++++++++++++++++++++------------
 node/src/service.rs          | 100 ++++++++++++++------------
 node/src/service/client.rs   |   9 +++
 7 files changed, 170 insertions(+), 100 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 26ec9b382..f896880d7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,10 +8,6 @@ members = [
     'pallets/identity',
     'pallets/ud-accounts-storage',
     'pallets/universal-dividend',
-    'runtime/common',
-    'runtime/gdev',
-    'runtime/gtest',
-    'runtime/g1'
 ]
 
 # The list of dependencies below (which can be both direct and indirect dependencies) are crates
diff --git a/node/Cargo.toml b/node/Cargo.toml
index 878d85357..fe76594fb 100644
--- a/node/Cargo.toml
+++ b/node/Cargo.toml
@@ -16,7 +16,18 @@ targets = ['x86_64-unknown-linux-gnu']
 name = 'duniter'
 
 [features]
-runtime-benchmarks = ['gdev-runtime/runtime-benchmarks']
+default = ["gdev"]
+g1 = ["g1-runtime"]
+gdev = ["gdev-runtime"]
+gtest = ["gtest-runtime"]
+runtime-benchmarks = [
+	'g1-runtime',
+	'g1-runtime/runtime-benchmarks',
+	'gdev-runtime',
+	'gdev-runtime/runtime-benchmarks',
+	'gtest-runtime',
+	'gtest-runtime/runtime-benchmarks',
+]
 
 [build-dependencies]
 substrate-build-script-utils = { git = 'https://github.com/librelois/substrate.git', branch = 'duniter-monthly-2022-01' }
@@ -28,9 +39,9 @@ sp-keyring = { git = "https://github.com/librelois/substrate.git", branch = "dun
 
 # local dependencies
 common-runtime = { path = '../runtime/common' }
-g1-runtime = { path = '../runtime/g1' }
-gdev-runtime = { path = '../runtime/gdev' }
-gtest-runtime = { path = '../runtime/gtest' }
+g1-runtime = { path = '../runtime/g1', optional = true }
+gdev-runtime = { path = '../runtime/gdev', optional = true }
+gtest-runtime = { path = '../runtime/gtest', optional = true }
 pallet-certification = { path = '../pallets/certification' }
 
 # crates.io dependencies
diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs
index 243830090..e414858c2 100644
--- a/node/src/chain_spec.rs
+++ b/node/src/chain_spec.rs
@@ -14,8 +14,11 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
 
+#[cfg(feature = "g1")]
 pub mod g1;
+#[cfg(feature = "gdev")]
 pub mod gdev;
+#[cfg(feature = "gtest")]
 pub mod gtest;
 
 use common_runtime::{AccountId, IdtyIndex, Signature};
diff --git a/node/src/chain_spec/gtest.rs b/node/src/chain_spec/gtest.rs
index b03b4b0d4..15fae450a 100644
--- a/node/src/chain_spec/gtest.rs
+++ b/node/src/chain_spec/gtest.rs
@@ -117,7 +117,7 @@ fn devnet_genesis(
         strong_cert: StrongCertConfig {
             certs_by_issuer: clique_wot(
                 initial_identities.len(),
-                gdev_runtime::parameters::ValidityPeriod::get(),
+                gtest_runtime::parameters::ValidityPeriod::get(),
             ),
         },
         ud_accounts_storage: UdAccountsStorageConfig {
@@ -310,7 +310,7 @@ fn testnet_genesis(
         strong_cert: StrongCertConfig {
             certs_by_issuer: clique_wot(
                 initial_identities.len(),
-                gdev_runtime::parameters::ValidityPeriod::get(),
+                gtest_runtime::parameters::ValidityPeriod::get(),
             ),
         },
         ud_accounts_storage: UdAccountsStorageConfig {
diff --git a/node/src/command.rs b/node/src/command.rs
index afd99c53c..2b4eaeaed 100644
--- a/node/src/command.rs
+++ b/node/src/command.rs
@@ -16,9 +16,14 @@
 // limitations under the License.
 
 use crate::cli::{Cli, Subcommand};
-use crate::service::{G1Executor, GDevExecutor, GTestExecutor, IdentifyVariant};
+#[cfg(feature = "g1")]
+use crate::service::G1Executor;
+#[cfg(feature = "gdev")]
+use crate::service::GDevExecutor;
+#[cfg(feature = "gtest")]
+use crate::service::GTestExecutor;
+use crate::service::IdentifyVariant;
 use crate::{chain_spec, service};
-use gdev_runtime::Block;
 use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli};
 
 impl SubstrateCli for Cli {
@@ -48,9 +53,13 @@ impl SubstrateCli for Cli {
 
     fn load_spec(&self, id: &str) -> Result<Box<dyn sc_service::ChainSpec>, String> {
         Ok(match id {
+            #[cfg(feature = "gdev")]
             "dev" | "gdev" => Box::new(chain_spec::gdev::development_chain_spec()?),
+            #[cfg(feature = "gtest")]
             "gtest_dev" => Box::new(chain_spec::gtest::development_chain_spec()?),
+            #[cfg(feature = "gtest")]
             "local" | "gtest_local" => Box::new(chain_spec::gtest::local_testnet_config(2)?),
+            #[cfg(feature = "gtest")]
             "local4" | "gtest_local4" => Box::new(chain_spec::gtest::local_testnet_config(4)?),
             // Specs provided as json specify which runtime to use in their file name. For example,
             // `g1-custom.json` uses the g1 runtime.
@@ -65,28 +74,48 @@ impl SubstrateCli for Cli {
                         .unwrap_or(false)
                 };
 
-                if starts_with("g1") {
-                    Box::new(chain_spec::g1::ChainSpec::from_json_file(path)?)
+                enum RuntimeType {
+                    G1,
+                    GDev,
+                    GTest,
+                }
+
+                let runtime_type = if starts_with("g1") {
+                    RuntimeType::G1
                 } else if starts_with("gdem") || starts_with("gtest") {
-                    Box::new(chain_spec::gtest::ChainSpec::from_json_file(path)?)
+                    RuntimeType::GDev
                 } else if starts_with("gdev") {
-                    Box::new(chain_spec::gdev::ChainSpec::from_json_file(path)?)
+                    RuntimeType::GTest
                 } else {
                     panic!("unknown runtime")
+                };
+
+                match runtime_type {
+                    #[cfg(feature = "g1")]
+                    RuntimeType::G1 => Box::new(chain_spec::g1::ChainSpec::from_json_file(path)?),
+                    #[cfg(feature = "gdev")]
+                    RuntimeType::GDev => {
+                        Box::new(chain_spec::gdev::ChainSpec::from_json_file(path)?)
+                    }
+                    #[cfg(feature = "gtest")]
+                    RuntimeType::GTest => {
+                        Box::new(chain_spec::gtest::ChainSpec::from_json_file(path)?)
+                    }
+                    _ => panic!("unknown runtime"),
                 }
             }
         })
     }
 
     fn native_runtime_version(spec: &Box<dyn ChainSpec>) -> &'static RuntimeVersion {
-        if spec.is_main() {
-            todo!() //return &g1_runtime::VERSION;
-        } else if spec.is_test() {
-            &gtest_runtime::VERSION
-        } else if spec.is_dev() {
-            &gdev_runtime::VERSION
-        } else {
-            panic!("unknown runtime")
+        match spec {
+            #[cfg(feature = "g1")]
+            spec if spec.is_main() => &g1_runtime::VERSION,
+            #[cfg(feature = "gtest")]
+            spec if spec.is_test() => &gtest_runtime::VERSION,
+            #[cfg(feature = "gdev")]
+            spec if spec.is_dev() => &gdev_runtime::VERSION,
+            _ => panic!("unknown runtime"),
         }
     }
 }
@@ -101,23 +130,23 @@ pub fn run() -> sc_cli::Result<()> {
             let runner = cli.create_runner(cmd)?;
             runner.sync_run(|config| {
                 if cmd.shared_params.dev {
-                    if config.chain_spec.is_main() {
-                        cmd.run(
+                    match &config.chain_spec {
+                        #[cfg(feature = "g1")]
+                        chain_spec if chain_spec.is_main() => cmd.run(
                             Box::new(chain_spec::g1::development_chain_spec()?),
                             config.network,
-                        )
-                    } else if config.chain_spec.is_test() {
-                        cmd.run(
+                        ),
+                        #[cfg(feature = "gtest")]
+                        chain_spec if chain_spec.is_test() => cmd.run(
                             Box::new(chain_spec::gtest::development_chain_spec()?),
                             config.network,
-                        )
-                    } else if config.chain_spec.is_dev() {
-                        cmd.run(
+                        ),
+                        #[cfg(feature = "gdev")]
+                        chain_spec if chain_spec.is_dev() => cmd.run(
                             Box::new(chain_spec::gdev::development_chain_spec()?),
                             config.network,
-                        )
-                    } else {
-                        panic!("unknown runtime")
+                        ),
+                        _ => panic!("unknown runtime"),
                     }
                 } else {
                     cmd.run(config.chain_spec, config.network)
@@ -168,14 +197,18 @@ pub fn run() -> sc_cli::Result<()> {
                 let runner = cli.create_runner(cmd)?;
                 let chain_spec = &runner.config().chain_spec;
 
-                if chain_spec.is_main() {
-                    runner.sync_run(|config| cmd.run::<Block, G1Executor>(config))
-                } else if chain_spec.is_test() {
-                    runner.sync_run(|config| cmd.run::<Block, GTestExecutor>(config))
-                } else if chain_spec.is_dev() {
-                    runner.sync_run(|config| cmd.run::<Block, GDevExecutor>(config))
-                } else {
-                    unreachable!()
+                match chain_spec {
+                    #[cfg(feature = "g1")]
+                    chain_spec if chain_spec.is_main() => {
+                        runner.sync_run(|config| cmd.run::<g1_runtime::Block, G1Executor>(config))
+                    }
+                    #[cfg(feature = "gtest")]
+                    chain_spec if chain_spec.is_test() => runner
+                        .sync_run(|config| cmd.run::<gtest_runtime::Block, GTestExecutor>(config)),
+                    #[cfg(feature = "gdev")]
+                    chain_spec if chain_spec.is_dev() => runner
+                        .sync_run(|config| cmd.run::<gdev_runtime::Block, GDevExecutor>(config)),
+                    _ => Err(sc_cli::Error::Application("unknown runtime".into())),
                 }
             } else {
                 Err("Benchmarking wasn't enabled when building the node. \
@@ -186,20 +219,26 @@ pub fn run() -> sc_cli::Result<()> {
         None => {
             let runner = cli.create_runner(&cli.run)?;
             runner.run_node_until_exit(|config| async move {
-                if config.chain_spec.is_main() {
-                    service::new_full::<gtest_runtime::RuntimeApi, G1Executor>(config, None)
-                        .map_err(sc_cli::Error::Service)
-                } else if config.chain_spec.is_test() {
-                    service::new_full::<gtest_runtime::RuntimeApi, GTestExecutor>(config, None)
+                match &config.chain_spec {
+                    #[cfg(feature = "g1")]
+                    chain_spec if chain_spec.is_main() => {
+                        service::new_full::<g1_runtime::RuntimeApi, G1Executor>(config, None)
+                            .map_err(sc_cli::Error::Service)
+                    }
+                    #[cfg(feature = "gtest")]
+                    chain_spec if chain_spec.is_test() => {
+                        service::new_full::<gtest_runtime::RuntimeApi, GTestExecutor>(config, None)
+                            .map_err(sc_cli::Error::Service)
+                    }
+                    #[cfg(feature = "gdev")]
+                    chain_spec if chain_spec.is_dev() => {
+                        service::new_full::<gdev_runtime::RuntimeApi, GDevExecutor>(
+                            config,
+                            Some(cli.sealing),
+                        )
                         .map_err(sc_cli::Error::Service)
-                } else if config.chain_spec.is_dev() {
-                    service::new_full::<gdev_runtime::RuntimeApi, GDevExecutor>(
-                        config,
-                        Some(cli.sealing),
-                    )
-                    .map_err(sc_cli::Error::Service)
-                } else {
-                    Err(sc_cli::Error::Application("unknown runtime".into()))
+                    }
+                    _ => Err(sc_cli::Error::Application("unknown runtime".into())),
                 }
             })
         }
diff --git a/node/src/service.rs b/node/src/service.rs
index bde26bb6b..c40e7e0d1 100644
--- a/node/src/service.rs
+++ b/node/src/service.rs
@@ -38,7 +38,9 @@ type FullClient<RuntimeApi, Executor> =
 type FullBackend = sc_service::TFullBackend<Block>;
 type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
 
+#[cfg(feature = "gdev")]
 pub struct GDevExecutor;
+#[cfg(feature = "gdev")]
 impl sc_executor::NativeExecutionDispatch for GDevExecutor {
     /// Only enable the benchmarking host functions when we actually want to benchmark.
     #[cfg(feature = "runtime-benchmarks")]
@@ -56,7 +58,9 @@ impl sc_executor::NativeExecutionDispatch for GDevExecutor {
     }
 }
 
+#[cfg(feature = "gtest")]
 pub struct GTestExecutor;
+#[cfg(feature = "gtest")]
 impl sc_executor::NativeExecutionDispatch for GTestExecutor {
     /// Only enable the benchmarking host functions when we actually want to benchmark.
     #[cfg(feature = "runtime-benchmarks")]
@@ -74,7 +78,9 @@ impl sc_executor::NativeExecutionDispatch for GTestExecutor {
     }
 }
 
+#[cfg(feature = "g1")]
 pub struct G1Executor;
+#[cfg(feature = "g1")]
 impl sc_executor::NativeExecutionDispatch for G1Executor {
     /// Only enable the benchmarking host functions when we actually want to benchmark.
     #[cfg(feature = "runtime-benchmarks")]
@@ -132,50 +138,56 @@ pub fn new_chain_ops(
     ),
     ServiceError,
 > {
-    if config.chain_spec.is_main() {
-        let PartialComponents {
-            client,
-            backend,
-            import_queue,
-            task_manager,
-            ..
-        } = new_partial::<g1_runtime::RuntimeApi, G1Executor>(config, false)?;
-        Ok((
-            Arc::new(Client::G1(client)),
-            backend,
-            import_queue,
-            task_manager,
-        ))
-    } else if config.chain_spec.is_test() {
-        let PartialComponents {
-            client,
-            backend,
-            import_queue,
-            task_manager,
-            ..
-        } = new_partial::<gtest_runtime::RuntimeApi, GTestExecutor>(config, false)?;
-        Ok((
-            Arc::new(Client::GTest(client)),
-            backend,
-            import_queue,
-            task_manager,
-        ))
-    } else if config.chain_spec.is_dev() {
-        let PartialComponents {
-            client,
-            backend,
-            import_queue,
-            task_manager,
-            ..
-        } = new_partial::<gdev_runtime::RuntimeApi, GDevExecutor>(config, true)?;
-        Ok((
-            Arc::new(Client::GDev(client)),
-            backend,
-            import_queue,
-            task_manager,
-        ))
-    } else {
-        unreachable!()
+    match &config.chain_spec {
+        #[cfg(feature = "g1")]
+        chain_spec if chain_spec.is_main() => {
+            let PartialComponents {
+                client,
+                backend,
+                import_queue,
+                task_manager,
+                ..
+            } = new_partial::<g1_runtime::RuntimeApi, G1Executor>(config, false)?;
+            Ok((
+                Arc::new(Client::G1(client)),
+                backend,
+                import_queue,
+                task_manager,
+            ))
+        }
+        #[cfg(feature = "gtest")]
+        chain_spec if chain_spec.is_test() => {
+            let PartialComponents {
+                client,
+                backend,
+                import_queue,
+                task_manager,
+                ..
+            } = new_partial::<gtest_runtime::RuntimeApi, GTestExecutor>(config, false)?;
+            Ok((
+                Arc::new(Client::GTest(client)),
+                backend,
+                import_queue,
+                task_manager,
+            ))
+        }
+        #[cfg(feature = "gdev")]
+        chain_spec if chain_spec.is_dev() => {
+            let PartialComponents {
+                client,
+                backend,
+                import_queue,
+                task_manager,
+                ..
+            } = new_partial::<gdev_runtime::RuntimeApi, GDevExecutor>(config, true)?;
+            Ok((
+                Arc::new(Client::GDev(client)),
+                backend,
+                import_queue,
+                task_manager,
+            ))
+        }
+        _ => panic!("unknown runtime"),
     }
 }
 
diff --git a/node/src/service/client.rs b/node/src/service/client.rs
index 8015cd2f3..6abfbc56a 100644
--- a/node/src/service/client.rs
+++ b/node/src/service/client.rs
@@ -29,17 +29,22 @@ use std::sync::Arc;
 /// A client instance.
 #[derive(Clone)]
 pub enum Client {
+    #[cfg(feature = "g1")]
     G1(Arc<super::FullClient<g1_runtime::RuntimeApi, super::G1Executor>>),
+    #[cfg(feature = "gtest")]
     GTest(Arc<super::FullClient<gtest_runtime::RuntimeApi, super::GTestExecutor>>),
+    #[cfg(feature = "gdev")]
     GDev(Arc<super::FullClient<gdev_runtime::RuntimeApi, super::GDevExecutor>>),
 }
 
+#[cfg(feature = "g1")]
 impl From<Arc<super::FullClient<g1_runtime::RuntimeApi, super::G1Executor>>> for Client {
     fn from(client: Arc<super::FullClient<g1_runtime::RuntimeApi, super::G1Executor>>) -> Self {
         Self::G1(client)
     }
 }
 
+#[cfg(feature = "gtest")]
 impl From<Arc<super::FullClient<gtest_runtime::RuntimeApi, super::GTestExecutor>>> for Client {
     fn from(
         client: Arc<super::FullClient<gtest_runtime::RuntimeApi, super::GTestExecutor>>,
@@ -48,6 +53,7 @@ impl From<Arc<super::FullClient<gtest_runtime::RuntimeApi, super::GTestExecutor>
     }
 }
 
+#[cfg(feature = "gdev")]
 impl From<Arc<super::FullClient<gdev_runtime::RuntimeApi, super::GDevExecutor>>> for Client {
     fn from(client: Arc<super::FullClient<gdev_runtime::RuntimeApi, super::GDevExecutor>>) -> Self {
         Self::GDev(client)
@@ -57,8 +63,11 @@ impl From<Arc<super::FullClient<gdev_runtime::RuntimeApi, super::GDevExecutor>>>
 macro_rules! match_client {
 	($self:ident, $method:ident($($param:ident),*)) => {
 		match $self {
+			#[cfg(feature = "g1")]
 			Self::G1(client) => client.$method($($param),*),
+			#[cfg(feature = "gtest")]
 			Self::GTest(client) => client.$method($($param),*),
+			#[cfg(feature = "gdev")]
 			Self::GDev(client) => client.$method($($param),*),
 		}
 	};
-- 
GitLab