Commit a965d55a authored by Pascal Engélibert's avatar Pascal Engélibert 🚴
Browse files

[feat] gva: heads and peers

parent 51716d54
Pipeline #11822 passed with stages
in 25 minutes and 39 seconds
......@@ -80,6 +80,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "anyhow"
version = "1.0.34"
......@@ -688,7 +697,7 @@ version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"ansi_term 0.11.0",
"atty",
"bitflags 1.2.1",
"strsim 0.8.0",
......@@ -934,6 +943,16 @@ dependencies = [
"memchr",
]
[[package]]
name = "ctor"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "ctrlc"
version = "3.1.7"
......@@ -1001,6 +1020,12 @@ dependencies = [
"syn",
]
[[package]]
name = "diff"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
[[package]]
name = "difference"
version = "2.0.0"
......@@ -1379,6 +1404,7 @@ dependencies = [
"futures",
"log",
"mockall",
"pretty_assertions",
"resiter",
"serde",
"serde_json",
......@@ -2653,6 +2679,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "output_vt100"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
dependencies = [
"winapi",
]
[[package]]
name = "parking"
version = "2.0.0"
......@@ -2867,6 +2902,18 @@ dependencies = [
"treeline",
]
[[package]]
name = "pretty_assertions"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f297542c27a7df8d45de2b0e620308ab883ad232d06c14b76ac3e144bda50184"
dependencies = [
"ansi_term 0.12.1",
"ctor",
"diff",
"output_vt100",
]
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
......
......@@ -24,10 +24,10 @@
pub mod block;
pub mod current_frame;
pub mod dunp_v1;
pub mod endpoints;
pub mod find_inputs;
pub mod idty;
pub mod network;
pub mod pagination;
pub mod txs_history;
pub mod uds_of_pubkey;
......@@ -154,6 +154,10 @@ pub trait DbsReader {
bc_db: &BcV2DbRo<FileBackend>,
pubkey: PublicKey,
) -> KvResult<Option<duniter_dbs::IdtyDbV2>>;
fn peers_and_heads<DB: 'static + DunpV1DbReadable>(
&self,
dunp_db: &DB,
) -> KvResult<Vec<(duniter_dbs::PeerCardDbV1, Vec<duniter_dbs::DunpHeadDbV1>)>>;
fn unspent_uds_of_pubkey(
&self,
bc_db: &BcV2DbRo<FileBackend>,
......@@ -302,6 +306,13 @@ impl DbsReader for DbsReaderImpl {
self.idty_(bc_db, pubkey)
}
fn peers_and_heads<DB: 'static + DunpV1DbReadable>(
&self,
dunp_db: &DB,
) -> KvResult<Vec<(duniter_dbs::PeerCardDbV1, Vec<duniter_dbs::DunpHeadDbV1>)>> {
self.peers_and_heads_(dunp_db)
}
fn unspent_uds_of_pubkey(
&self,
bc_db: &BcV2DbRo<FileBackend>,
......
......@@ -14,15 +14,38 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::*;
use dubp::crypto::keys::PublicKey as _;
use duniter_dbs::databases::dunp_v1::DunpV1DbReadable;
use duniter_dbs::PeerCardDbV1;
use duniter_dbs::{DunpHeadDbV1, PeerCardDbV1};
#[allow(clippy::unnecessary_wraps)]
impl DbsReaderImpl {
pub(super) fn peers_and_heads<DB: DunpV1DbReadable>(
pub(super) fn peers_and_heads_<DB: DunpV1DbReadable>(
&self,
_dunp_db: &DB,
) -> KvResult<Vec<PeerCardDbV1>> {
todo!()
dunp_db: &DB,
) -> KvResult<Vec<(PeerCardDbV1, Vec<DunpHeadDbV1>)>> {
Ok(dunp_db.peers_old().iter(.., |it| {
it.values()
.filter_map(|peer_res| {
if let Ok(peer) = peer_res {
if let Ok(pubkey) = PublicKey::from_base58(&peer.pubkey) {
let k_min = duniter_dbs::DunpNodeIdV1Db::new(0, pubkey);
let k_max = duniter_dbs::DunpNodeIdV1Db::new(u32::MAX, pubkey);
Some((
peer,
dunp_db.heads_old().iter(k_min..k_max, |it| {
it.values().filter_map(|head| head.ok()).collect()
}),
))
} else {
None
}
} else {
None
}
})
.collect()
}))
}
}
......@@ -37,11 +60,43 @@ mod tests {
let db_reader = DbsReaderImpl::mem();
let pk = PublicKey::default();
dunp_db
.peers_old_write()
.upsert(PubKeyKeyV2(pk), PeerCardDbV1::default())?;
dunp_db.peers_old_write().upsert(
PubKeyKeyV2(pk),
PeerCardDbV1 {
pubkey: pk.to_string(),
..Default::default()
},
)?;
dunp_db.heads_old_write().upsert(
duniter_dbs::DunpNodeIdV1Db::new(42, pk),
DunpHeadDbV1::default(),
)?;
dunp_db.heads_old_write().upsert(
duniter_dbs::DunpNodeIdV1Db::new(43, pk),
DunpHeadDbV1 {
pubkey: PublicKey::from_base58("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
.expect("invalid pubkey"),
..Default::default()
},
)?;
assert_eq!(db_reader.peers_and_heads(&dunp_db)?, vec![]);
assert_eq!(
db_reader.peers_and_heads(&dunp_db)?,
vec![(
PeerCardDbV1 {
pubkey: pk.to_string(),
..Default::default()
},
vec![
DunpHeadDbV1::default(),
DunpHeadDbV1 {
pubkey: PublicKey::from_base58("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
.expect("invalid pubkey"),
..Default::default()
}
]
)]
);
Ok(())
}
......
......@@ -31,6 +31,7 @@ duniter-dbs = { path = "../../../duniter-dbs", features = ["mem"] }
duniter-gva-dbs-reader = { path = "../dbs-reader", features = ["mock"] }
duniter-global = { path = "../../../duniter-global", features = ["mock"] }
mockall = "0.9.1"
pretty_assertions = "0.7"
serde_json = "1.0.53"
tokio = { version = "1.2", features = ["macros", "rt-multi-thread", "time"] }
unwrap = "1.2.1"
......@@ -15,6 +15,7 @@
pub mod block_gva;
pub mod idty_gva;
pub mod network;
pub mod tx_gva;
pub mod ud_gva;
pub mod utxos_gva;
......@@ -37,31 +38,6 @@ pub(crate) struct EdgeTx {
pub(crate) direction: TxDirection,
}
#[derive(Default, async_graphql::SimpleObject)]
#[graphql(name = "Peer")]
pub struct PeerCardGva {
pub version: u32,
pub currency: String,
pub pubkey: String,
pub blockstamp: String,
pub endpoints: Vec<String>,
pub status: String,
pub signature: String,
}
impl From<duniter_dbs::PeerCardDbV1> for PeerCardGva {
fn from(peer: duniter_dbs::PeerCardDbV1) -> Self {
Self {
version: peer.version,
currency: peer.currency,
pubkey: peer.pubkey,
blockstamp: peer.blockstamp,
endpoints: peer.endpoints,
status: peer.status,
signature: peer.signature,
}
}
}
pub(crate) enum RawTxOrChanges {
FinalTx(String),
Changes(Vec<String>),
......
// Copyright (C) 2020 Éloïs SANCHEZ.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#[derive(Default, async_graphql::SimpleObject)]
#[graphql(name = "Peer")]
pub struct PeerCardGva {
pub version: u32,
pub currency: String,
pub pubkey: String,
pub blockstamp: String,
pub endpoints: Vec<String>,
pub status: String,
pub signature: String,
}
impl From<duniter_dbs::PeerCardDbV1> for PeerCardGva {
fn from(peer: duniter_dbs::PeerCardDbV1) -> Self {
Self {
version: peer.version,
currency: peer.currency,
pubkey: peer.pubkey,
blockstamp: peer.blockstamp,
endpoints: peer.endpoints,
status: peer.status,
signature: peer.signature,
}
}
}
#[derive(Default, async_graphql::SimpleObject)]
#[graphql(name = "Head")]
pub struct HeadGva {
pub api: String,
pub pubkey: String,
pub blockstamp: String,
pub software: String,
pub software_version: String,
pub pow_prefix: u32,
pub free_member_room: u32,
pub free_mirror_room: u32,
pub signature: String,
}
impl From<duniter_dbs::DunpHeadDbV1> for HeadGva {
fn from(head: duniter_dbs::DunpHeadDbV1) -> Self {
Self {
api: head.api,
pubkey: head.pubkey.to_string(),
blockstamp: head.blockstamp.to_string(),
software: head.software,
software_version: head.software_version,
pow_prefix: head.pow_prefix,
free_member_room: head.free_member_room,
free_mirror_room: head.free_member_room,
signature: head.signature.to_string(),
}
}
}
#[derive(async_graphql::SimpleObject)]
pub(crate) struct PeerWithHeads {
pub peer: PeerCardGva,
pub heads: Vec<HeadGva>,
}
......@@ -37,11 +37,12 @@ pub use schema::{build_schema_with_data, get_schema_definition, GvaSchema, GvaSc
use crate::entities::{
block_gva::{Block, BlockMeta},
idty_gva::Identity,
network::{HeadGva, PeerCardGva, PeerWithHeads},
tx_gva::TxGva,
ud_gva::{CurrentUdGva, RevalUdGva, UdGva},
utxos_gva::UtxosGva,
AggregateSum, AmountWithBase, EdgeTx, PeerCardGva, RawTxOrChanges, Sum, TxDirection,
TxsHistoryMempool, UtxoGva, UtxoTimedGva,
AggregateSum, AmountWithBase, EdgeTx, RawTxOrChanges, Sum, TxDirection, TxsHistoryMempool,
UtxoGva, UtxoTimedGva,
};
use crate::inputs::{TxIssuer, TxRecipient, UdsFilter};
use crate::inputs_validators::TxCommentValidator;
......
......@@ -21,7 +21,7 @@ pub mod endpoints;
pub mod first_utxos_of_scripts;
pub mod gen_tx;
pub mod idty;
pub mod peers_and_heads;
pub mod network;
pub mod txs_history;
pub mod uds;
pub mod utxos_of_script;
......@@ -39,6 +39,7 @@ pub struct QueryRoot(
queries::first_utxos_of_scripts::FirstUtxosQuery,
queries::gen_tx::GenTxsQuery,
queries::idty::IdtyQuery,
queries::network::NetworkQuery,
queries::txs_history::TxsHistoryBlockchainQuery,
queries::txs_history::TxsHistoryMempoolQuery,
queries::uds::UdsQuery,
......
......@@ -15,25 +15,79 @@
use crate::*;
#[derive(Default, async_graphql::SimpleObject)]
pub(crate) struct NetworkQuery {
network: NetworkQueryInner,
}
#[derive(Default)]
pub(crate) struct NetworkQueryInner;
#[async_graphql::Object]
impl NetworkQueryInner {
/// Get peers and heads
async fn nodes(
&self,
ctx: &async_graphql::Context<'_>,
) -> async_graphql::Result<Vec<PeerWithHeads>> {
let data = ctx.data::<GvaSchemaData>()?;
let db_reader = data.dbs_reader();
Ok(data
.dbs_pool
.execute(move |dbs| db_reader.peers_and_heads(&dbs.dunp_db))
.await??
.into_iter()
.map(|(peer, heads)| PeerWithHeads {
peer: PeerCardGva::from(peer),
heads: heads.into_iter().map(HeadGva::from).collect(),
})
.collect())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::*;
use duniter_dbs::databases::dunp_v1::DunpV1Db;
use pretty_assertions::assert_eq;
#[test]
fn test_peers_and_heads() {
#[tokio::test]
async fn test_peers_and_heads() -> anyhow::Result<()> {
let mut dbs_reader = MockDbsReader::new();
dbs_reader
.expect_function()
.withf(|_, param| param == expected)
.expect_peers_and_heads::<DunpV1Db<FileBackend>>()
.times(1)
.returning(|_, _| todo!());
.returning(|_| {
Ok(vec![(
duniter_dbs::PeerCardDbV1::default(),
vec![duniter_dbs::DunpHeadDbV1::default()],
)])
});
let schema = create_schema(MockAsyncAccessor::new(), dbs_reader)?;
assert_eq!(
exec_graphql_request(&schema, r#"{ }"#).await?,
exec_graphql_request(
&schema,
r#"{ network { nodes { peer { blockstamp }, heads { blockstamp } } } }"#
)
.await?,
serde_json::json!({
"data": {
"field": {
"bool": true,
"network": {
"nodes": [
{
"heads": [
{
"blockstamp": "0-0000000000000000000000000000000000000000000000000000000000000000"
}
],
"peer": {
"blockstamp": ""
}
}
],
}
}
})
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment