diff --git a/crates/iroha/tests/status_response.rs b/crates/iroha/tests/status_response.rs index 41e4982cff3..b6e1e9526d7 100644 --- a/crates/iroha/tests/status_response.rs +++ b/crates/iroha/tests/status_response.rs @@ -7,7 +7,7 @@ use tokio::task::spawn_blocking; fn status_eq_excluding_uptime_and_queue(lhs: &Status, rhs: &Status) -> bool { lhs.peers == rhs.peers && lhs.blocks == rhs.blocks - && lhs.txs_accepted == rhs.txs_accepted + && lhs.txs_approved == rhs.txs_approved && lhs.txs_rejected == rhs.txs_rejected && lhs.view_changes == rhs.view_changes } diff --git a/crates/iroha_core/src/lib.rs b/crates/iroha_core/src/lib.rs index 29ba08689ff..1019560ed63 100644 --- a/crates/iroha_core/src/lib.rs +++ b/crates/iroha_core/src/lib.rs @@ -38,7 +38,7 @@ pub const TX_RETRIEVAL_INTERVAL: Duration = Duration::from_millis(100); pub type IrohaNetwork = iroha_p2p::NetworkHandle; /// Ids of peers. -pub type PeersIds = UniqueVec; +pub type Peers = UniqueVec; /// Type of `Sender` which should be used for channels of `Event` messages. pub type EventsSender = broadcast::Sender; diff --git a/crates/iroha_core/src/metrics.rs b/crates/iroha_core/src/metrics.rs index e9ccc1829ae..2d080e288e8 100644 --- a/crates/iroha_core/src/metrics.rs +++ b/crates/iroha_core/src/metrics.rs @@ -3,6 +3,7 @@ use std::{num::NonZeroUsize, sync::Arc, time::SystemTime}; use eyre::{Result, WrapErr as _}; +use iroha_data_model::peer::Peer; use iroha_telemetry::metrics::Metrics; use mv::storage::StorageReadOnly; use parking_lot::Mutex; @@ -76,12 +77,12 @@ impl MetricsReporter { }; block_index += 1; let block_txs_rejected = block.errors().count() as u64; - let block_txs_accepted = block.transactions().count() as u64 - block_txs_rejected; + let block_txs_approved = block.transactions().count() as u64 - block_txs_rejected; self.metrics .txs .with_label_values(&["accepted"]) - .inc_by(block_txs_accepted); + .inc_by(block_txs_approved); self.metrics .txs .with_label_values(&["rejected"]) @@ -89,7 +90,7 @@ impl MetricsReporter { self.metrics .txs .with_label_values(&["total"]) - .inc_by(block_txs_accepted + block_txs_rejected); + .inc_by(block_txs_approved + block_txs_rejected); self.metrics.block_height.inc(); } *lastest_block_height = block_index; @@ -147,4 +148,9 @@ impl MetricsReporter { pub fn metrics(&self) -> &Metrics { &self.metrics } + + /// Last known online peers + pub fn online_peers(&self) -> Vec { + self.network.online_peers(|x| x.iter().cloned().collect()) + } } diff --git a/crates/iroha_core/src/smartcontracts/isi/world.rs b/crates/iroha_core/src/smartcontracts/isi/world.rs index 7e2d18c2508..38d44dd6868 100644 --- a/crates/iroha_core/src/smartcontracts/isi/world.rs +++ b/crates/iroha_core/src/smartcontracts/isi/world.rs @@ -39,8 +39,7 @@ pub mod isi { let peer_id = self.object; let world = &mut state_transaction.world; - if let PushResult::Duplicate(duplicate) = world.trusted_peers_ids.push(peer_id.clone()) - { + if let PushResult::Duplicate(duplicate) = world.peers.push(peer_id.clone()) { return Err(RepetitionError { instruction: InstructionType::Register, id: IdBox::PeerId(duplicate), @@ -63,11 +62,11 @@ pub mod isi { ) -> Result<(), Error> { let peer_id = self.object; let world = &mut state_transaction.world; - let Some(index) = world.trusted_peers_ids.iter().position(|id| id == &peer_id) else { + let Some(index) = world.peers.iter().position(|id| id == &peer_id) else { return Err(FindError::Peer(peer_id).into()); }; - world.trusted_peers_ids.remove(index); + world.peers.remove(index); world.emit_events(Some(PeerEvent::Removed(peer_id))); @@ -513,6 +512,7 @@ pub mod query { Ok(state_ro .world() .peers() + .into_iter() .filter(move |peer| filter.applies(peer)) .cloned()) } diff --git a/crates/iroha_core/src/state.rs b/crates/iroha_core/src/state.rs index d77a6c41dc7..e549c393dd6 100644 --- a/crates/iroha_core/src/state.rs +++ b/crates/iroha_core/src/state.rs @@ -56,7 +56,7 @@ use crate::{ }, wasm, Execute, }, - PeersIds, + Peers, }; /// The global entity consisting of `domains`, `triggers` and etc. @@ -65,8 +65,8 @@ use crate::{ pub struct World { /// Iroha on-chain parameters. pub(crate) parameters: Cell, - /// Identifications of discovered trusted peers. - pub(crate) trusted_peers_ids: Cell, + /// Identifications of discovered peers. + pub(crate) peers: Cell, /// Registered domains. pub(crate) domains: Storage, /// Registered accounts. @@ -93,8 +93,8 @@ pub struct World { pub struct WorldBlock<'world> { /// Iroha on-chain parameters. pub parameters: CellBlock<'world, Parameters>, - /// Identifications of discovered trusted peers. - pub(crate) trusted_peers_ids: CellBlock<'world, PeersIds>, + /// Identifications of discovered peers. + pub(crate) peers: CellBlock<'world, Peers>, /// Registered domains. pub(crate) domains: StorageBlock<'world, DomainId, Domain>, /// Registered accounts. @@ -123,8 +123,8 @@ pub struct WorldBlock<'world> { pub struct WorldTransaction<'block, 'world> { /// Iroha on-chain parameters. pub(crate) parameters: CellTransaction<'block, 'world, Parameters>, - /// Identifications of discovered trusted peers. - pub(crate) trusted_peers_ids: CellTransaction<'block, 'world, PeersIds>, + /// Identifications of discovered peers. + pub(crate) peers: CellTransaction<'block, 'world, Peers>, /// Registered domains. pub(crate) domains: StorageTransaction<'block, 'world, DomainId, Domain>, /// Registered accounts. @@ -162,8 +162,8 @@ struct TransactionEventBuffer<'block> { pub struct WorldView<'world> { /// Iroha on-chain parameters. pub(crate) parameters: CellView<'world, Parameters>, - /// Identifications of discovered trusted peers. - pub(crate) trusted_peers_ids: CellView<'world, PeersIds>, + /// Identifications of discovered peers. + pub(crate) peers: CellView<'world, Peers>, /// Registered domains. pub(crate) domains: StorageView<'world, DomainId, Domain>, /// Registered accounts. @@ -303,7 +303,7 @@ impl World { Self::default() } - /// Creates a [`World`] with these [`Domain`]s and trusted [`PeerId`]s. + /// Creates a [`World`] with these [`Domain`]s and [`Peer`]s. pub fn with(domains: D, accounts: A, asset_definitions: Ad) -> Self where D: IntoIterator, @@ -313,7 +313,7 @@ impl World { Self::with_assets(domains, accounts, asset_definitions, []) } - /// Creates a [`World`] with these [`Domain`]s and trusted [`PeerId`]s. + /// Creates a [`World`] with these [`Domain`]s and [`Peer`]s. pub fn with_assets( domains: D, accounts: A, @@ -352,7 +352,7 @@ impl World { pub fn block(&self) -> WorldBlock { WorldBlock { parameters: self.parameters.block(), - trusted_peers_ids: self.trusted_peers_ids.block(), + peers: self.peers.block(), domains: self.domains.block(), accounts: self.accounts.block(), asset_definitions: self.asset_definitions.block(), @@ -371,7 +371,7 @@ impl World { pub fn block_and_revert(&self) -> WorldBlock { WorldBlock { parameters: self.parameters.block_and_revert(), - trusted_peers_ids: self.trusted_peers_ids.block_and_revert(), + peers: self.peers.block_and_revert(), domains: self.domains.block_and_revert(), accounts: self.accounts.block_and_revert(), asset_definitions: self.asset_definitions.block_and_revert(), @@ -390,7 +390,7 @@ impl World { pub fn view(&self) -> WorldView { WorldView { parameters: self.parameters.view(), - trusted_peers_ids: self.trusted_peers_ids.view(), + peers: self.peers.view(), domains: self.domains.view(), accounts: self.accounts.view(), asset_definitions: self.asset_definitions.view(), @@ -409,7 +409,7 @@ impl World { #[allow(missing_docs)] pub trait WorldReadOnly { fn parameters(&self) -> &Parameters; - fn trusted_peers_ids(&self) -> &PeersIds; + fn peers(&self) -> &Peers; fn domains(&self) -> &impl StorageReadOnly; fn accounts(&self) -> &impl StorageReadOnly; fn asset_definitions(&self) -> &impl StorageReadOnly; @@ -635,17 +635,6 @@ pub trait WorldReadOnly { fn asset_total_amount(&self, definition_id: &AssetDefinitionId) -> Result { Ok(self.asset_definition(definition_id)?.total_quantity) } - - /// Get an immutable iterator over the [`PeerId`]s. - fn peers(&self) -> impl ExactSizeIterator { - self.trusted_peers_ids().iter() - } - - /// Returns reference for trusted peer ids - #[inline] - fn peers_ids(&self) -> &PeersIds { - self.trusted_peers_ids() - } } macro_rules! impl_world_ro { @@ -654,8 +643,8 @@ macro_rules! impl_world_ro { fn parameters(&self) -> &Parameters { &self.parameters } - fn trusted_peers_ids(&self) -> &PeersIds { - &self.trusted_peers_ids + fn peers(&self) -> &Peers { + &self.peers } fn domains(&self) -> &impl StorageReadOnly { &self.domains @@ -700,7 +689,7 @@ impl<'world> WorldBlock<'world> { pub fn trasaction(&mut self) -> WorldTransaction<'_, 'world> { WorldTransaction { parameters: self.parameters.transaction(), - trusted_peers_ids: self.trusted_peers_ids.transaction(), + peers: self.peers.transaction(), domains: self.domains.transaction(), accounts: self.accounts.transaction(), asset_definitions: self.asset_definitions.transaction(), @@ -723,7 +712,7 @@ impl<'world> WorldBlock<'world> { // NOTE: intentionally destruct self not to forget commit some fields let Self { parameters, - trusted_peers_ids, + peers, domains, accounts, asset_definitions, @@ -747,7 +736,7 @@ impl<'world> WorldBlock<'world> { asset_definitions.commit(); accounts.commit(); domains.commit(); - trusted_peers_ids.commit(); + peers.commit(); parameters.commit(); } } @@ -758,7 +747,7 @@ impl WorldTransaction<'_, '_> { // NOTE: intentionally destruct self not to forget commit some fields let Self { parameters, - trusted_peers_ids, + peers, domains, accounts, asset_definitions, @@ -781,7 +770,7 @@ impl WorldTransaction<'_, '_> { asset_definitions.apply(); accounts.apply(); domains.apply(); - trusted_peers_ids.apply(); + peers.apply(); parameters.apply(); events_buffer.events_created_in_transaction = 0; } @@ -1864,7 +1853,7 @@ pub(crate) mod deserialize { M: MapAccess<'de>, { let mut parameters = None; - let mut trusted_peers_ids = None; + let mut peers = None; let mut domains = None; let mut accounts = None; let mut asset_definitions = None; @@ -1881,8 +1870,8 @@ pub(crate) mod deserialize { "parameters" => { parameters = Some(map.next_value()?); } - "trusted_peers_ids" => { - trusted_peers_ids = Some(map.next_value()?); + "peers" => { + peers = Some(map.next_value()?); } "domains" => { domains = Some(map.next_value()?); @@ -1925,8 +1914,7 @@ pub(crate) mod deserialize { Ok(World { parameters: parameters .ok_or_else(|| serde::de::Error::missing_field("parameters"))?, - trusted_peers_ids: trusted_peers_ids - .ok_or_else(|| serde::de::Error::missing_field("trusted_peers_ids"))?, + peers: peers.ok_or_else(|| serde::de::Error::missing_field("peers"))?, domains: domains .ok_or_else(|| serde::de::Error::missing_field("domains"))?, accounts: accounts @@ -1955,7 +1943,7 @@ pub(crate) mod deserialize { "World", &[ "parameters", - "trusted_peers_ids", + "peers", "domains", "roles", "account_permissions", diff --git a/crates/iroha_core/src/sumeragi/main_loop.rs b/crates/iroha_core/src/sumeragi/main_loop.rs index efdfd30db89..f94df318ed5 100644 --- a/crates/iroha_core/src/sumeragi/main_loop.rs +++ b/crates/iroha_core/src/sumeragi/main_loop.rs @@ -273,7 +273,7 @@ impl Sumeragi { } // NOTE: By this time genesis block is executed and list of trusted peers is updated - self.topology = Topology::new(state_block.world.trusted_peers_ids.clone()); + self.topology = Topology::new(state_block.world.peers.clone()); self.commit_block(block, state_block); return Ok(()); } @@ -318,7 +318,7 @@ impl Sumeragi { ); // NOTE: By this time genesis block is executed and list of trusted peers is updated - self.topology = Topology::new(state_block.world.trusted_peers_ids.clone()); + self.topology = Topology::new(state_block.world.peers.clone()); let genesis = genesis .commit(&self.topology) @@ -343,7 +343,7 @@ impl Sumeragi { let prev_role = self.role(); self.topology - .block_committed(state_block.world.peers().cloned()); + .block_committed(state_block.world.peers().clone()); let state_events = state_block.apply_without_execution(&block, self.topology.as_ref().to_owned()); diff --git a/crates/iroha_core/src/sumeragi/mod.rs b/crates/iroha_core/src/sumeragi/mod.rs index c3a6f51e711..0da7911713f 100644 --- a/crates/iroha_core/src/sumeragi/mod.rs +++ b/crates/iroha_core/src/sumeragi/mod.rs @@ -118,10 +118,10 @@ impl SumeragiHandle { .expect("INTERNAL BUG: Invalid block stored in Kura"); if block.as_ref().header().is_genesis() { - *topology = Topology::new(state_block.world.trusted_peers_ids.clone()); + *topology = Topology::new(state_block.world.peers.clone()); } - topology.block_committed(state_block.world.peers().cloned()); + topology.block_committed(state_block.world.peers().clone()); state_block .apply_without_execution(&block, topology.as_ref().to_owned()) diff --git a/crates/iroha_schema_gen/src/lib.rs b/crates/iroha_schema_gen/src/lib.rs index 0c13c559cc4..b0fd0fe0b40 100644 --- a/crates/iroha_schema_gen/src/lib.rs +++ b/crates/iroha_schema_gen/src/lib.rs @@ -45,10 +45,9 @@ pub fn build_schemas() -> MetaMap { } schemas! { - // Transaction - SignedTransaction, + Peer, - // Query + response + SignedTransaction, SignedQuery, QueryResponse, @@ -265,6 +264,8 @@ types!( InstructionType, InvalidParameterError, IpfsPath, + Ipv6Addr, + Ipv4Addr, Json, Level, Log, @@ -322,6 +323,7 @@ types!( PeerEvent, PeerEventFilter, PeerEventSet, + Peer, PeerId, PeerPredicateBox, Permission, @@ -406,6 +408,10 @@ types!( SingularQueryOutputBox, SmartContractParameter, SmartContractParameters, + SocketAddr, + SocketAddrHost, + SocketAddrV4, + SocketAddrV6, Sorting, String, StringPredicateBox, @@ -490,6 +496,8 @@ types!( WasmExecutionFail, WasmSmartContract, + [u16; 8], + [u8; 4], [u8; 32], u16, u32, @@ -546,7 +554,12 @@ pub mod complete_data_model { Level, }; pub use iroha_genesis::{GenesisWasmAction, GenesisWasmTrigger, WasmPath}; - pub use iroha_primitives::{const_vec::ConstVec, conststr::ConstString, json::Json}; + pub use iroha_primitives::{ + addr::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrHost, SocketAddrV4, SocketAddrV6}, + const_vec::ConstVec, + conststr::ConstString, + json::Json, + }; pub use iroha_schema::Compact; } diff --git a/crates/iroha_telemetry/src/metrics.rs b/crates/iroha_telemetry/src/metrics.rs index 0bf373ea4df..096f5ae57f8 100644 --- a/crates/iroha_telemetry/src/metrics.rs +++ b/crates/iroha_telemetry/src/metrics.rs @@ -54,9 +54,9 @@ pub struct Status { /// Number of committed blocks (blockchain height) #[codec(compact)] pub blocks: u64, - /// Number of accepted transactions + /// Number of approved transactions #[codec(compact)] - pub txs_accepted: u64, + pub txs_approved: u64, /// Number of rejected transactions #[codec(compact)] pub txs_rejected: u64, @@ -76,7 +76,7 @@ impl> From<&T> for Status { Self { peers: val.connected_peers.get(), blocks: val.block_height.get(), - txs_accepted: val.txs.with_label_values(&["accepted"]).get(), + txs_approved: val.txs.with_label_values(&["accepted"]).get(), txs_rejected: val.txs.with_label_values(&["rejected"]).get(), uptime: Uptime(Duration::from_millis(val.uptime_since_genesis_ms.get())), view_changes: val @@ -249,7 +249,7 @@ mod test { Status { peers: 4, blocks: 5, - txs_accepted: 31, + txs_approved: 31, txs_rejected: 3, uptime: Uptime(Duration::new(5, 937_000_000)), view_changes: 2, @@ -268,7 +268,7 @@ mod test { { "peers": 4, "blocks": 5, - "txs_accepted": 31, + "txs_approved": 31, "txs_rejected": 3, "uptime": { "secs": 5, diff --git a/crates/iroha_torii/src/lib.rs b/crates/iroha_torii/src/lib.rs index 20d3a4f53c7..fbf8f61f00e 100644 --- a/crates/iroha_torii/src/lib.rs +++ b/crates/iroha_torii/src/lib.rs @@ -105,6 +105,13 @@ impl Torii { let kiso = self.kiso.clone(); move || routing::handle_get_configuration(kiso) }), + ) + .route( + uri::API_VERSION, + get({ + let state = self.state.clone(); + move || routing::handle_version(state) + }), ); #[cfg(feature = "telemetry")] @@ -122,6 +129,13 @@ impl Torii { } }), ) + .route( + uri::PEERS, + get({ + let metrics_reporter = self.metrics_reporter.clone(); + move || core::future::ready(routing::handle_peers(&metrics_reporter)) + }), + ) .route( uri::STATUS, get({ @@ -137,13 +151,6 @@ impl Torii { let metrics_reporter = self.metrics_reporter.clone(); move || core::future::ready(routing::handle_metrics(&metrics_reporter)) }), - ) - .route( - uri::API_VERSION, - get({ - let state = self.state.clone(); - move || routing::handle_version(state) - }), ); #[cfg(feature = "schema")] diff --git a/crates/iroha_torii/src/routing.rs b/crates/iroha_torii/src/routing.rs index 5fa43f72c05..f1190cc7e9a 100644 --- a/crates/iroha_torii/src/routing.rs +++ b/crates/iroha_torii/src/routing.rs @@ -246,7 +246,6 @@ pub mod event { } #[iroha_futures::telemetry_future] -#[cfg(feature = "telemetry")] pub async fn handle_version(state: Arc) -> String { use iroha_version::Version; @@ -274,6 +273,13 @@ pub fn handle_metrics(metrics_reporter: &MetricsReporter) -> Result { .map_err(Error::Prometheus) } +#[cfg(feature = "telemetry")] +pub fn handle_peers(metrics_reporter: &MetricsReporter) -> Response { + update_metrics_gracefully(metrics_reporter); + let peers = metrics_reporter.online_peers(); + axum::Json(peers).into_response() +} + #[cfg(feature = "telemetry")] #[allow(clippy::unnecessary_wraps)] pub fn handle_status( diff --git a/crates/iroha_torii_const/src/lib.rs b/crates/iroha_torii_const/src/lib.rs index 0330e4e52bf..1a1b500f025 100644 --- a/crates/iroha_torii_const/src/lib.rs +++ b/crates/iroha_torii_const/src/lib.rs @@ -14,6 +14,8 @@ pub mod uri { pub const CONSENSUS: &str = "/consensus"; /// Health URI is used to handle incoming Healthcheck requests. pub const HEALTH: &str = "/health"; + /// Peers URI is used to find all peers in the network + pub const PEERS: &str = "/peers"; /// The URI used for block synchronization. pub const BLOCK_SYNC: &str = "/block/sync"; /// The web socket uri used to subscribe to block and transactions statuses. diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index dc3c8ea26b3..a3d775a6900 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -228,12 +228,24 @@ } ] }, + "Array": { + "Array": { + "type": "u16", + "len": 8 + } + }, "Array": { "Array": { "type": "u8", "len": 32 } }, + "Array": { + "Array": { + "type": "u8", + "len": 4 + } + }, "Asset": { "Struct": [ { @@ -2364,6 +2376,8 @@ ] }, "IpfsPath": "String", + "Ipv4Addr": "Array", + "Ipv6Addr": "Array", "Json": "String", "Level": { "Enum": [ @@ -2902,6 +2916,18 @@ } ] }, + "Peer": { + "Struct": [ + { + "name": "address", + "type": "SocketAddr" + }, + { + "name": "id", + "type": "PeerId" + } + ] + }, "PeerEvent": { "Enum": [ { @@ -4221,6 +4247,61 @@ } ] }, + "SocketAddr": { + "Enum": [ + { + "tag": "Ipv4", + "discriminant": 0, + "type": "SocketAddrV4" + }, + { + "tag": "Ipv6", + "discriminant": 1, + "type": "SocketAddrV6" + }, + { + "tag": "Host", + "discriminant": 2, + "type": "SocketAddrHost" + } + ] + }, + "SocketAddrHost": { + "Struct": [ + { + "name": "host", + "type": "String" + }, + { + "name": "port", + "type": "u16" + } + ] + }, + "SocketAddrV4": { + "Struct": [ + { + "name": "ip", + "type": "Ipv4Addr" + }, + { + "name": "port", + "type": "u16" + } + ] + }, + "SocketAddrV6": { + "Struct": [ + { + "name": "ip", + "type": "Ipv6Addr" + }, + { + "name": "port", + "type": "u16" + } + ] + }, "SortedMap": { "Map": { "key": "AccountId", diff --git a/pytests/iroha_torii_tests/common/schemas/get_status_response.json b/pytests/iroha_torii_tests/common/schemas/get_status_response.json index efc5ccdccbc..9388361a18a 100644 --- a/pytests/iroha_torii_tests/common/schemas/get_status_response.json +++ b/pytests/iroha_torii_tests/common/schemas/get_status_response.json @@ -8,7 +8,7 @@ "blocks": { "type": "integer" }, - "txs_accepted": { + "txs_approved": { "type": "integer" }, "txs_rejected": { @@ -33,5 +33,5 @@ "type": "integer" } }, - "required": ["peers", "blocks", "txs_accepted", "txs_rejected", "uptime", "view_changes", "queue_size"] + "required": ["peers", "blocks", "txs_approved", "txs_rejected", "uptime", "view_changes", "queue_size"] }