From 61d833568c9ec431ea6ea8b27f1e2da96e0c6680 Mon Sep 17 00:00:00 2001 From: Hugo Trentesaux <hugo@trentesaux.fr> Date: Tue, 6 Jun 2023 10:13:26 +0200 Subject: [PATCH] add genesis hash and current block checks --- doc/example.md | 11 ++++++++- res/indexer-queries.graphql | 6 +++++ src/data.rs | 8 +++++++ src/indexer.rs | 46 +++++++++++++++++++++++++++++++++---- src/main.rs | 44 +++++++++++++++++++++++++++++++++-- 5 files changed, 107 insertions(+), 8 deletions(-) diff --git a/doc/example.md b/doc/example.md index 5d9b716..2c36bae 100644 --- a/doc/example.md +++ b/doc/example.md @@ -26,6 +26,8 @@ with derivations: ## Commands ```sh +# get duniter current block +gcli current-block # get balance of test1 account gcli --address 5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa get-balance # get information about test1 identity (needs indexer) @@ -36,7 +38,14 @@ gcli --secret "pipe paddle ketchup filter life ice feel embody glide quantum rid ## Indexer commands -These commands uniquely relate with indexer +You can check first that indexer is on the same network as Duniter node: + +```sh +# check if indexer is on the same chain as duniter +gcli check-indexer-against-blockchain +``` + +The following commands uniquely relate with indexer. ```sh # show latest indexer indexed block diff --git a/res/indexer-queries.graphql b/res/indexer-queries.graphql index edf068e..570a7cd 100644 --- a/res/indexer-queries.graphql +++ b/res/indexer-queries.graphql @@ -15,3 +15,9 @@ query LatestBlock { value } } + +query GenesisHash { + block(where: {number: {_eq: 0}}) { + hash + } +} diff --git a/src/data.rs b/src/data.rs index 80ee1e0..64c63be 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,4 +1,5 @@ use crate::*; +use indexer::Indexer; // data derived from command arguments @@ -24,6 +25,8 @@ pub struct Data { pub token_symbol: String, // genesis hash pub genesis_hash: Hash, + // indexer genesis hash + pub indexer_genesis_hash: Hash, } /// system properties defined in client specs @@ -146,6 +149,11 @@ impl Data { .unwrap(); Ok(self) } + /// get indexer genesis hash + pub async fn fetch_indexer_genesis_hash(mut self) -> Result<Self, anyhow::Error> { + self.indexer_genesis_hash = self.indexer().fetch_genesis_hash().await?; + Ok(self) + } /// get properties pub async fn fetch_system_properties(mut self) -> Result<Self, anyhow::Error> { let system_properties = self.client().rpc().system_properties().await?; diff --git a/src/indexer.rs b/src/indexer.rs index d02b1d9..e8e8de2 100644 --- a/src/indexer.rs +++ b/src/indexer.rs @@ -28,6 +28,13 @@ pub struct IdentityPubkeyByName; )] pub struct LatestBlock; +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "res/indexer-schema.json", + query_path = "res/indexer-queries.graphql" +)] +pub struct GenesisHash; + #[derive(Clone, Debug)] pub struct Indexer { pub gql_client: reqwest::Client, @@ -61,7 +68,7 @@ impl Indexer { .and_then(|data| data.identity_by_pk.map(|idty| idty.pubkey))) } - /// fetch latest block + /// fetch latest block number pub async fn fetch_latest_block(&self) -> Result<u64, anyhow::Error> { Ok(post_graphql::<LatestBlock, _>( &self.gql_client, @@ -80,29 +87,58 @@ impl Indexer { .as_u64() .unwrap()) // must be a Number of blocks } + + /// fetch genesis hash + pub async fn fetch_genesis_hash(&self) -> Result<Hash, anyhow::Error> { + Ok(post_graphql::<GenesisHash, _>( + &self.gql_client, + self.gql_url.clone(), + genesis_hash::Variables {}, + ) + .await? + .data + .unwrap() // must have a data field + .block + .first() + .unwrap() // must have one and only one block matching request + .hash + .clone() + .parse::<Hash>() + .unwrap()) + } } #[derive(Clone, Default, Debug, clap::Parser)] -pub enum IndexerSubcommand { +pub enum Subcommand { #[default] /// Show indexer endpoint ShowEndpoint, /// Fetch latest indexed block LatestBlock, + /// Fetch genesis block hash + GenesisHash, } -pub async fn handle_command(data: Data, command: IndexerSubcommand) -> anyhow::Result<()> { +pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<()> { + // build indexer because it is needed for all subcommands let data = data.build_indexer()?; + // match subcommand match command { - IndexerSubcommand::ShowEndpoint => { + Subcommand::ShowEndpoint => { println!("indexer endpoint: {}", data.indexer().gql_url); } - IndexerSubcommand::LatestBlock => { + Subcommand::LatestBlock => { println!( "latest indexed block is: {}", data.indexer().fetch_latest_block().await? ); } + Subcommand::GenesisHash => { + println!( + "hash of genesis block is: {}", + data.indexer().fetch_genesis_hash().await? + ); + } }; Ok(()) diff --git a/src/main.rs b/src/main.rs index a656192..ca457a1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ mod keys; use clap::Parser; use codec::Encode; use data::*; -use indexer::*; use keys::*; use serde::Deserialize; use sp_core::{sr25519::Pair, Pair as _, H256}; @@ -251,9 +250,13 @@ pub enum Subcommand { UpdateKeys, /// Get information about runtime RuntimeInfo, + /// Check current block + CurrentBlock, + /// Check that indexer and node are on the same network + CheckIndexerAgainstBlockchain, /// Indexer subcommands #[clap(subcommand)] - Indexer(IndexerSubcommand), + Indexer(indexer::Subcommand), } #[tokio::main(flavor = "current_thread")] @@ -567,6 +570,43 @@ async fn main() -> Result<(), GcliError> { data = data.build_client().await.fetch_system_properties().await?; commands::runtime::runtime_info(data).await; } + Subcommand::CurrentBlock => { + data = data.build_client().await; + println!( + "current block: {}", + data.client() + .storage() + .fetch(&runtime::storage().system().number(), None) + .await? + .unwrap() + ); + } + Subcommand::CheckIndexerAgainstBlockchain => { + data = data + .build_client() + .await + .build_indexer()? + .fetch_genesis_hash() + .await? + .fetch_indexer_genesis_hash() + .await?; + if data.genesis_hash == data.indexer_genesis_hash { + println!( + "{} and {} have the same genesis hash: {}", + data.args.url, + data.indexer().gql_url, + data.genesis_hash + ); + } else { + println!( + "âš ï¸ {} ({}) and {} ({}) do not share same genesis", + data.args.url, + data.genesis_hash, + data.indexer().gql_url, + data.indexer_genesis_hash + ); + } + } Subcommand::Indexer(subcommand) => indexer::handle_command(data, subcommand).await?, } -- GitLab