From 35585c696339f679c790c1e52bad6bfa531f86d9 Mon Sep 17 00:00:00 2001
From: Hugo Trentesaux <hugo@trentesaux.fr>
Date: Fri, 25 Oct 2024 11:36:46 +0200
Subject: [PATCH] wip more reading
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

not easy 😢
---
 Cargo.lock                      |   2 +
 Cargo.toml                      |   8 ++-
 node/Cargo.toml                 |  29 ++++++---
 node/src/cli.rs                 |   2 +-
 node/src/command.rs             |   7 +--
 node/src/endpoint_gossip/mod.rs | 107 +++++++++++++++++++++++++-------
 node/src/service.rs             |  61 +++++++++---------
 7 files changed, 148 insertions(+), 68 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 0d42a0448..57cf6dec0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2181,6 +2181,7 @@ dependencies = [
 name = "duniter"
 version = "0.8.0"
 dependencies = [
+ "array-bytes",
  "async-io",
  "bs58 0.5.1",
  "clap",
@@ -2206,6 +2207,7 @@ dependencies = [
  "pallet-transaction-payment-rpc",
  "pallet-transaction-payment-rpc-runtime-api",
  "pallet-treasury",
+ "parity-scale-codec",
  "sc-basic-authorship",
  "sc-chain-spec",
  "sc-cli",
diff --git a/Cargo.toml b/Cargo.toml
index 8dafdaef0..0a61728d9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -64,13 +64,15 @@ bs58 = { version = "0.5.1", default-features = false }
 placeholder = { version = "1.1.4", default-features = false }
 clap = { version = "4.5.3" }
 clap_complete = { version = "4.5.1" }
-reqwest = { version = "0.12.0", default-features = false, features = ["rustls-tls"] }
+reqwest = { version = "0.12.0", default-features = false, features = [
+    "rustls-tls",
+] }
 glob = { version = "0.3.1", default-features = false }
 convert_case = { version = "0.6.0", default-features = false }
 subweight-core = { version = "3.3.1", default-features = false }
 version_check = { version = "0.9.4", default-features = false }
 codec = { package = "parity-scale-codec", version = "3.6.9", default-features = false }
-enum-as-inner = { version = "=0.5.1", default-features = false }                        #https://github.com/bluejekyll/trust-dns/issues/1946
+enum-as-inner = { version = "=0.5.1", default-features = false } #https://github.com/bluejekyll/trust-dns/issues/1946
 futures = { version = "0.3.30", default-features = false }
 tera = { version = "1", default-features = false }
 hex = { version = "0.4.3", default-features = false }
@@ -101,6 +103,7 @@ simple_logger = { version = "4.3.3", default-features = false }
 bincode = { version = "1.3.3", default-features = false }
 dubp-wot = { version = "0.11.1", default-features = false }
 flate2 = { version = "1.0.28", default-features = false }
+array-bytes = { version = "6.2.2", default-features = false }
 
 # Subxt
 subxt = { git = 'https://github.com/duniter/subxt', branch = 'subxt-v0.37.0-duniter-substrate-v1.16.0', default-features = false }
@@ -274,4 +277,3 @@ zeroize = { opt-level = 3 }
 lto = "thin"
 # Substrate runtime requires unwinding.
 panic = "unwind"
-
diff --git a/node/Cargo.toml b/node/Cargo.toml
index 784c75437..dcfedb5d5 100644
--- a/node/Cargo.toml
+++ b/node/Cargo.toml
@@ -48,7 +48,7 @@ runtime-benchmarks = [
 	"sp-runtime/runtime-benchmarks",
 ]
 try-runtime = [
-  "runtime-benchmarks",
+	"runtime-benchmarks",
 	"common-runtime/try-runtime",
 	"dc-distance?/try-runtime",
 	"distance-oracle?/try-runtime",
@@ -125,6 +125,8 @@ num-format = { workspace = true }
 serde = { workspace = true }
 serde_json = { workspace = true }
 serde_yaml = { workspace = true }
+codec = { workspace = true }
+array-bytes = { workspace = true }
 
 # Local
 common-runtime = { workspace = true }
@@ -184,7 +186,7 @@ sp-transaction-storage-proof = { workspace = true, default-features = true }
 substrate-frame-rpc-system = { workspace = true, default-features = true }
 
 [build-dependencies]
-substrate-build-script-utils = { workspace = true, default-features = true}
+substrate-build-script-utils = { workspace = true, default-features = true }
 
 # Dependencies for specific targets
 [target.'cfg(any(target_arch="x86_64", target_arch="aarch64"))'.dependencies]
@@ -194,9 +196,20 @@ sp-trie = { workspace = true, default-features = true }
 
 [package.metadata.deb]
 maintainer-scripts = "../resources/debian"
-systemd-units = [ { unit-name = "duniter-mirror", enable = false },
-                  { unit-name = "duniter-smith", enable = false },
-                  { unit-name = "distance-oracle", enable = false },
-                  ]
-assets = [ ["../resources/debian/env_file", "/etc/duniter/env_file", "0640"],
-           ["../target/release/duniter", "/usr/bin/duniter2", "755"]]
+systemd-units = [
+	{ unit-name = "duniter-mirror", enable = false },
+	{ unit-name = "duniter-smith", enable = false },
+	{ unit-name = "distance-oracle", enable = false },
+]
+assets = [
+	[
+		"../resources/debian/env_file",
+		"/etc/duniter/env_file",
+		"0640",
+	],
+	[
+		"../target/release/duniter",
+		"/usr/bin/duniter2",
+		"755",
+	],
+]
diff --git a/node/src/cli.rs b/node/src/cli.rs
index 647845b5f..6b63b941d 100644
--- a/node/src/cli.rs
+++ b/node/src/cli.rs
@@ -35,7 +35,7 @@ pub struct Cli {
 }
 
 /// add options specific to duniter client
-#[derive(Debug, Clone, clap::Parser)]
+#[derive(Debug, Default, Clone, clap::Parser)]
 pub struct DuniterConfigExtension {
     /// Public RPC endpoint to gossip on the network and make available in the apps.
     #[arg(long)]
diff --git a/node/src/command.rs b/node/src/command.rs
index 9bac52396..9b424b059 100644
--- a/node/src/command.rs
+++ b/node/src/command.rs
@@ -22,7 +22,7 @@ pub mod utils;
 
 use crate::{
     chain_spec,
-    cli::{Cli, Subcommand},
+    cli::{Cli, DuniterConfigExtension, Subcommand},
     service,
     service::{runtime_executor::Executor, RuntimeType},
 };
@@ -364,8 +364,7 @@ pub fn run() -> sc_cli::Result<()> {
         }
         None => {
             let runner = cli.create_runner(&cli.run)?;
-            // TODO add endpoint config here
-            let config_extension: DuniterConfigExtension = ();
+            let duniter_options: DuniterConfigExtension = cli.duniter_options;
             runner.run_node_until_exit(|mut config| async move {
                 // Force offchain worker and offchain indexing if we have the role Authority
                 if config.role.is_authority() {
@@ -378,7 +377,7 @@ pub fn run() -> sc_cli::Result<()> {
                         service::runtime_executor::runtime::RuntimeApi,
                         Executor,
                         sc_network::Litep2pNetworkBackend,
-                    >(config, cli.sealing, config_extension)
+                    >(config, cli.sealing, duniter_options)
                     .map_err(sc_cli::Error::Service)
                 }
             })
diff --git a/node/src/endpoint_gossip/mod.rs b/node/src/endpoint_gossip/mod.rs
index 682463363..5a684e2f1 100644
--- a/node/src/endpoint_gossip/mod.rs
+++ b/node/src/endpoint_gossip/mod.rs
@@ -1,12 +1,22 @@
+use codec::{Decode, DecodeAll, Encode};
+use futures::prelude::*;
 use sc_chain_spec::ChainSpec;
-use sc_network::types::ProtocolName;
+use sc_network::{types::ProtocolName, NotificationService};
 
 // endpoint gossip is a single protocol used to gossip different kinds of endpoints like
 // - rpc endpoints
 // - squid indexer endpoints
 // ...
 
-pub(crate) const NAME: &str = "/endpoint_gossip/1";
+pub const NAME: &str = "/endpoint_gossip/1";
+
+#[derive(Debug, Encode, Decode)]
+enum EndpointMsg {
+    /// RPC endpoint of Duniter
+    RpcEndpoint(String),
+    /// GraphQL endpoint of Squid
+    SquidEndpoint(String),
+}
 
 /// Name of the notifications protocol used by endpoint gossip.
 // Prefix by fork id to avoid gossiping endpoints of wrong network
@@ -22,18 +32,17 @@ pub fn protocol_name<Hash: AsRef<[u8]>>(
     format!("{}{}", chain_prefix, NAME).into()
 }
 
-/// Returns the configuration value to put in
-/// [`sc_network::config::FullNetworkConfiguration`].
-pub fn peers_set_config<B: BlockT, N: NetworkBackend<B, <B as BlockT>::Hash>>(
+// returns config from protocol name
+pub fn set_config(
     protocol_name: ProtocolName,
-    metrics: sc_network::service::NotificationMetrics,
-    peer_store_handle: Arc<dyn sc_network::peer_store::PeerStoreProvider>,
-) -> (N::NotificationProtocolConfig, Box<dyn NotificationService>) {
-    use communication::grandpa_protocol_name;
-    N::notification_config(
+) -> (
+    sc_network::config::NonDefaultSetConfig,
+    Box<dyn NotificationService>,
+) {
+    sc_network::config::NonDefaultSetConfig::new(
         protocol_name,
         vec![],
-        // Inspired by GRANDPA notifications which are ~256kiB
+        // Copied from GRANDPA notifications which are ~256kiB
         1024 * 1024,
         None,
         sc_network::config::SetConfig {
@@ -42,19 +51,69 @@ pub fn peers_set_config<B: BlockT, N: NetworkBackend<B, <B as BlockT>::Hash>>(
             reserved_nodes: Vec::new(),
             non_reserved_mode: sc_network::config::NonReservedPeerMode::Deny,
         },
-        metrics,
-        peer_store_handle,
     )
 }
 
-// /// Create notification protocol configuration and an associated `NotificationService`
-// /// for the protocol.
-// fn notification_config(
-// 	protocol_name: ProtocolName,
-// 	fallback_names: Vec<ProtocolName>,
-// 	max_notification_size: u64,
-// 	handshake: Option<NotificationHandshake>,
-// 	set_config: SetConfig,
-// 	metrics: NotificationMetrics,
-// 	peerstore_handle: Arc<dyn PeerStoreProvider>,
-// ) -> (Self::NotificationProtocolConfig, Box<dyn NotificationService>);
+// copied from grandpa config
+// /substrate/client/consensus/grandpa/src/lib.rs:212
+struct EndpointGossipConfig {
+    /// The expected duration for a message to be gossiped across the network.
+    gossip_duration: std::time::Duration,
+    /// Period (in blocks) to share endpoints again
+    pub share_period: u32,
+    /// Some local identifier of the endpoint.
+    pub name: Option<String>,
+    /// Chain specific endpoint protocol name
+    protocol_name: ProtocolName,
+}
+
+struct EndpointGossipParams<Network> {
+    config: EndpointGossipConfig,
+    network: Network,
+    notification_service: Box<dyn NotificationService>,
+    offchain_endpoint_tester: (),
+}
+
+fn run_gossip_worker<Network>(params: EndpointGossipParams<Network>) {
+    let topic = "XXX";
+
+    // TODO network has no gossip engine, it is created in network bridge
+    // to gossip a message
+    params
+        .network
+        .gossip_engine
+        .lock()
+        .gossip_message(topic, notification.message.clone(), false);
+
+    // to process incoming messages
+    let stream = gossip_engine
+        .clone()
+        .lock()
+        .messages_for(topic)
+        .filter_map(|notification| {
+            let decoded = EndpointMsg::decode_all(&mut &notification.message[..]);
+            if let Err(ref e) = decoded {
+                println!(
+                    "Skipping malformed commit message {:?}: {}",
+                    notification, e
+                );
+            }
+            future::ready(decoded.map(move |d| (notification, d)).ok())
+        })
+        .filter_map(move |(notification, msg)| {
+            future::ready(match msg {
+                EndpointMsg::RpcEndpoint(msg) => {
+                    println!("rpc {msg}");
+                    Some(())
+                }
+                EndpointMsg::SquidEndpoint(msg) => {
+                    println!("rpc {msg}");
+                    Some(())
+                }
+                _ => {
+                    println!("Skipping unknown message type");
+                    None
+                }
+            })
+        });
+}
diff --git a/node/src/service.rs b/node/src/service.rs
index d6b23bc4e..131c41aa5 100644
--- a/node/src/service.rs
+++ b/node/src/service.rs
@@ -127,6 +127,7 @@ pub fn new_chain_ops(
     } = new_partial::<runtime_executor::runtime::RuntimeApi, runtime_executor::Executor>(
         config,
         manual_consensus,
+        Default::default(),
     )?;
     Ok((
         Arc::new(Client::Client(client)),
@@ -147,7 +148,7 @@ type FullGrandpaBlockImport<RuntimeApi, Executor> = sc_consensus_grandpa::Grandp
 pub fn new_partial<RuntimeApi, Executor>(
     config: &Configuration,
     consensus_manual: bool,
-    config_extension: DuniterConfigExtension,
+    duniter_config: crate::cli::DuniterConfigExtension,
 ) -> Result<
     sc_service::PartialComponents<
         FullClient<RuntimeApi, Executor>,
@@ -304,6 +305,7 @@ pub fn new_full<
 >(
     config: Configuration,
     sealing: crate::cli::Sealing,
+    duniter_options: crate::cli::DuniterConfigExtension,
 ) -> Result<TaskManager, ServiceError>
 where
     RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi, Executor>>
@@ -323,7 +325,11 @@ where
         select_chain,
         transaction_pool,
         other: (block_import, babe_link, babe_worker_handle, grandpa_link, mut telemetry),
-    } = new_partial::<RuntimeApi, Executor>(&config, sealing.is_manual_consensus())?;
+    } = new_partial::<RuntimeApi, Executor>(
+        &config,
+        sealing.is_manual_consensus(),
+        duniter_options,
+    )?;
 
     // genesis hash used in protocol names
     let genesis_hash = client
@@ -352,42 +358,21 @@ where
         );
     net_config.add_notification_protocol(grandpa_protocol_config);
 
-    // endpoint gossip
-    // only active for non-authority (to save workload)
-    // if !role.is_authority() {
-    // configure protocol
+    // endpoint gossip network config
     let endpoint_gossip_protocol_name =
-        endpoint_gossip::protocol_name(&genesis_hash, &config.chain_spec);
+        crate::endpoint_gossip::protocol_name(&genesis_hash, &config.chain_spec);
     let (endpoint_gossip_protocol_config, endpoint_gossip_notification_service) =
-        endpoint_gossip::peers_set_config::<_, N>(
-            endpoint_gossip_protocol_name.clone(),
-            metrics.clone(),
-            peer_store_handle,
-        );
+        crate::endpoint_gossip::set_config(endpoint_gossip_protocol_name.clone());
     net_config.add_notification_protocol(endpoint_gossip_protocol_config);
-    let endpoint_gossip_config = ();
-
-    let endpoint_gossip_params = EndpointGossipParams {
-        config: endpoint_gossip_config,
-        network,
-        notification_service: endpoint_gossip_notification_service,
-        // offchain storage
-        offchain_endpoint_tester: (),
-    };
-    // spawn task
-    task_manager.spawn_handle().spawn(
-        "endpoint-gossip",
-        None,
-        run_gossip_worker(endpoint_gossip_params)?,
-    );
-    // }
 
+    // warp sync network provider
     let warp_sync = Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new(
         backend.clone(),
         grandpa_link.shared_authority_set().clone(),
         Vec::default(),
     ));
 
+    // build network service from params
     let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) =
         sc_service::build_network(sc_service::BuildNetworkParams {
             config: &config,
@@ -402,6 +387,7 @@ where
             metrics,
         })?;
 
+    // aliases
     let role = config.role;
     let force_authoring = config.force_authoring;
     let backoff_authoring_blocks: Option<()> = None;
@@ -671,6 +657,7 @@ where
         None
     };
 
+    // init grandpa config
     let grandpa_config = sc_consensus_grandpa::Config {
         gossip_duration: Duration::from_millis(333),
         justification_generation_period: GRANDPA_JUSTIFICATION_PERIOD,
@@ -713,6 +700,24 @@ where
         );
     }
 
+    // start endpoint gossip task
+    // only active for non-authority (to save workload)
+    // if !role.is_authority() {
+    let endpoint_gossip_params = crate::endpoint_gossip::EndpointGossipParams {
+        config: endpoint_gossip_config,
+        network,
+        notification_service: endpoint_gossip_notification_service,
+        // offchain storage
+        offchain_endpoint_tester: (),
+    };
+    // spawn endpoint gossip task
+    task_manager.spawn_handle().spawn(
+        "endpoint-gossip",
+        None,
+        crate::endpoint_gossip::run_gossip_worker(endpoint_gossip_params)?,
+    );
+    // }
+
     network_starter.start_network();
 
     log::info!("***** Duniter has fully started *****");
-- 
GitLab