From 7d5a60b115c256744c3746e3a803f6b007c32df8 Mon Sep 17 00:00:00 2001
From: librelois <c@elo.tf>
Date: Mon, 7 Dec 2020 17:01:08 +0100
Subject: [PATCH 1/4] [ref] duniter-dbs: move dbs def in module databases

---
 rust-bins/duniter-dbex/src/main.rs            |  9 ++++--
 rust-bins/duniter-dbex/src/migrate.rs         |  2 +-
 rust-libs/duniter-dbs-read-ops/src/lib.rs     |  2 +-
 rust-libs/duniter-dbs-write-ops/src/bc.rs     |  6 ++--
 .../src/bc/identities.rs                      |  2 +-
 rust-libs/duniter-dbs-write-ops/src/bc/txs.rs |  2 +-
 rust-libs/duniter-dbs-write-ops/src/bc/uds.rs |  2 +-
 rust-libs/duniter-dbs-write-ops/src/lib.rs    | 10 ++++--
 rust-libs/duniter-dbs-write-ops/src/txs_mp.rs |  2 +-
 rust-libs/duniter-dbs/src/databases.rs        | 20 ++++++++++++
 .../duniter-dbs/src/{ => databases}/bc_v1.rs  |  0
 .../duniter-dbs/src/{ => databases}/bc_v2.rs  |  0
 .../duniter-dbs/src/{ => databases}/cm_v1.rs  |  0
 .../duniter-dbs/src/{ => databases}/gva_v1.rs |  0
 .../src/{ => databases}/txs_mp_v2.rs          |  0
 rust-libs/duniter-dbs/src/lib.rs              | 31 ++++++++-----------
 rust-libs/duniter-dbs/src/open_dbs.rs         | 29 +++++++++++------
 rust-libs/duniter-dbs/tests/test_explorer.rs  |  5 ++-
 .../duniter-dbs/tests/test_read_write.rs      |  4 +--
 rust-libs/duniter-mempools/src/lib.rs         |  5 ++-
 rust-libs/duniter-module/src/lib.rs           |  2 +-
 rust-libs/duniter-server/src/lib.rs           | 18 +++++++----
 .../modules/gva/db-writer/src/identities.rs   |  2 +-
 rust-libs/modules/gva/db-writer/src/lib.rs    |  9 +++---
 rust-libs/modules/gva/db-writer/src/tx.rs     |  4 +--
 rust-libs/modules/gva/db-writer/src/utxos.rs  |  8 ++---
 .../modules/gva/dbs-reader/src/find_inputs.rs | 12 ++++---
 rust-libs/modules/gva/dbs-reader/src/lib.rs   | 15 +++++----
 .../gva/dbs-reader/src/uds_of_pubkey.rs       | 13 +++++---
 rust-libs/modules/gva/dbs-reader/src/utxos.rs |  9 +++---
 rust-libs/modules/gva/src/lib.rs              |  8 ++---
 rust-libs/modules/gva/src/queries.rs          |  2 +-
 rust-libs/modules/gva/src/queries/uds.rs      |  4 +--
 .../gva/src/queries/utxos_of_script.rs        |  2 +-
 rust-libs/modules/gva/src/subscriptions.rs    |  2 +-
 35 files changed, 147 insertions(+), 94 deletions(-)
 create mode 100644 rust-libs/duniter-dbs/src/databases.rs
 rename rust-libs/duniter-dbs/src/{ => databases}/bc_v1.rs (100%)
 rename rust-libs/duniter-dbs/src/{ => databases}/bc_v2.rs (100%)
 rename rust-libs/duniter-dbs/src/{ => databases}/cm_v1.rs (100%)
 rename rust-libs/duniter-dbs/src/{ => databases}/gva_v1.rs (100%)
 rename rust-libs/duniter-dbs/src/{ => databases}/txs_mp_v2.rs (100%)

diff --git a/rust-bins/duniter-dbex/src/main.rs b/rust-bins/duniter-dbex/src/main.rs
index bc2f22c07..ddd314b8b 100644
--- a/rust-bins/duniter-dbex/src/main.rs
+++ b/rust-bins/duniter-dbex/src/main.rs
@@ -31,15 +31,18 @@ use self::cli::{Database, Opt, OutputFormat, SubCommand};
 use self::stringify_json_value::stringify_json_value;
 use anyhow::anyhow;
 use comfy_table::Table;
-use duniter_dbs::bc_v2::{BcV2Db, BcV2DbWritable};
+use duniter_dbs::databases::bc_v2::{BcV2Db, BcV2DbWritable};
+use duniter_dbs::databases::{
+    bc_v1::{BcV1Db, BcV1DbWritable},
+    gva_v1::{GvaV1Db, GvaV1DbWritable},
+    txs_mp_v2::{TxsMpV2Db, TxsMpV2DbWritable},
+};
 use duniter_dbs::kv_typed::backend::sled;
 use duniter_dbs::kv_typed::prelude::*;
 use duniter_dbs::prelude::*;
 use duniter_dbs::regex::Regex;
 use duniter_dbs::serde_json::{Map, Value};
 use duniter_dbs::smallvec::{smallvec, SmallVec};
-use duniter_dbs::{BcV1Db, GvaV1Db, TxsMpV2Db};
-use duniter_dbs::{BcV1DbWritable, GvaV1DbWritable, TxsMpV2DbWritable};
 use rayon::prelude::*;
 use std::{
     collections::{HashMap, HashSet},
diff --git a/rust-bins/duniter-dbex/src/migrate.rs b/rust-bins/duniter-dbex/src/migrate.rs
index 1678bdeb2..b04f30782 100644
--- a/rust-bins/duniter-dbex/src/migrate.rs
+++ b/rust-bins/duniter-dbex/src/migrate.rs
@@ -18,7 +18,7 @@ use dubp::{
     block::parser::parse_json_block_from_serde_value, block::parser::ParseJsonBlockError,
     block::prelude::DubpBlockTrait, block::DubpBlock, common::prelude::BlockNumber,
 };
-use duniter_dbs::{BcV1DbReadable, FileBackend};
+use duniter_dbs::{databases::bc_v1::BcV1DbReadable, FileBackend};
 use fast_threadpool::{ThreadPool, ThreadPoolConfig};
 use std::{ops::Deref, path::PathBuf};
 
diff --git a/rust-libs/duniter-dbs-read-ops/src/lib.rs b/rust-libs/duniter-dbs-read-ops/src/lib.rs
index c123d2671..60dfe0d03 100644
--- a/rust-libs/duniter-dbs-read-ops/src/lib.rs
+++ b/rust-libs/duniter-dbs-read-ops/src/lib.rs
@@ -23,7 +23,7 @@
 )]
 
 use dubp::crypto::hashs::Hash;
-use duniter_dbs::{bc_v2::BcV2DbReadable, HashKeyV2};
+use duniter_dbs::{databases::bc_v2::BcV2DbReadable, HashKeyV2};
 use duniter_dbs::{kv_typed::prelude::*, BlockMetaV2};
 
 pub fn get_current_block_meta<BcDb: BcV2DbReadable>(bc_db: &BcDb) -> KvResult<Option<BlockMetaV2>> {
diff --git a/rust-libs/duniter-dbs-write-ops/src/bc.rs b/rust-libs/duniter-dbs-write-ops/src/bc.rs
index 47d573c5d..6ab6ca807 100644
--- a/rust-libs/duniter-dbs-write-ops/src/bc.rs
+++ b/rust-libs/duniter-dbs-write-ops/src/bc.rs
@@ -18,10 +18,10 @@ mod txs;
 mod uds;
 
 use crate::*;
-use duniter_dbs::bc_v2::BcV2DbWritable;
+use duniter_dbs::databases::bc_v2::BcV2DbWritable;
 
 pub fn apply_block<B: Backend>(
-    bc_db: &duniter_dbs::bc_v2::BcV2Db<B>,
+    bc_db: &duniter_dbs::databases::bc_v2::BcV2Db<B>,
     block: &DubpBlockV10,
 ) -> KvResult<BlockMetaV2> {
     //log::info!("apply_block #{}", block.number().0);
@@ -84,7 +84,7 @@ pub fn apply_block<B: Backend>(
 }
 
 pub fn revert_block<B: Backend>(
-    bc_db: &duniter_dbs::bc_v2::BcV2Db<B>,
+    bc_db: &duniter_dbs::databases::bc_v2::BcV2Db<B>,
     block: &DubpBlockV10,
 ) -> KvResult<Option<BlockMetaV2>> {
     (
diff --git a/rust-libs/duniter-dbs-write-ops/src/bc/identities.rs b/rust-libs/duniter-dbs-write-ops/src/bc/identities.rs
index 848529a8e..024930874 100644
--- a/rust-libs/duniter-dbs-write-ops/src/bc/identities.rs
+++ b/rust-libs/duniter-dbs-write-ops/src/bc/identities.rs
@@ -14,7 +14,7 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 use crate::*;
-use duniter_dbs::bc_v2::IdentitiesEvent;
+use duniter_dbs::databases::bc_v2::IdentitiesEvent;
 use duniter_dbs::IdtyDbV2;
 
 pub(crate) fn update_identities<B: Backend>(
diff --git a/rust-libs/duniter-dbs-write-ops/src/bc/txs.rs b/rust-libs/duniter-dbs-write-ops/src/bc/txs.rs
index e00e4f88d..87b36acc7 100644
--- a/rust-libs/duniter-dbs-write-ops/src/bc/txs.rs
+++ b/rust-libs/duniter-dbs-write-ops/src/bc/txs.rs
@@ -15,7 +15,7 @@
 
 use crate::*;
 use duniter_dbs::{
-    bc_v2::{TxsHashsEvent, UdsEvent},
+    databases::bc_v2::{TxsHashsEvent, UdsEvent},
     UdIdV2,
 };
 
diff --git a/rust-libs/duniter-dbs-write-ops/src/bc/uds.rs b/rust-libs/duniter-dbs-write-ops/src/bc/uds.rs
index 2dde737f9..e8323f9bf 100644
--- a/rust-libs/duniter-dbs-write-ops/src/bc/uds.rs
+++ b/rust-libs/duniter-dbs-write-ops/src/bc/uds.rs
@@ -15,7 +15,7 @@
 
 use crate::*;
 use duniter_dbs::{
-    bc_v2::{IdentitiesEvent, UdsEvent, UdsRevalEvent},
+    databases::bc_v2::{IdentitiesEvent, UdsEvent, UdsRevalEvent},
     UdIdV2,
 };
 
diff --git a/rust-libs/duniter-dbs-write-ops/src/lib.rs b/rust-libs/duniter-dbs-write-ops/src/lib.rs
index 04edc631a..607d90124 100644
--- a/rust-libs/duniter-dbs-write-ops/src/lib.rs
+++ b/rust-libs/duniter-dbs-write-ops/src/lib.rs
@@ -37,9 +37,13 @@ use dubp::documents::{
 };
 use dubp::wallet::prelude::*;
 use duniter_dbs::{
-    bc_v2::BcV2Db, kv_typed::prelude::*, BlockMetaV2, DuniterDbs, FileBackend, HashKeyV2,
-    PendingTxDbV2, PubKeyKeyV2, PubKeyValV2, SourceAmountValV2, TxsMpV2Db, TxsMpV2DbReadable,
-    TxsMpV2DbWritable, UtxoValV2, WalletConditionsV2,
+    databases::{
+        bc_v2::BcV2Db,
+        txs_mp_v2::{TxsMpV2Db, TxsMpV2DbReadable, TxsMpV2DbWritable},
+    },
+    kv_typed::prelude::*,
+    BlockMetaV2, DuniterDbs, FileBackend, HashKeyV2, PendingTxDbV2, PubKeyKeyV2, PubKeyValV2,
+    SourceAmountValV2, UtxoValV2, WalletConditionsV2,
 };
 use resiter::filter_map::FilterMap;
 use resiter::flatten::Flatten;
diff --git a/rust-libs/duniter-dbs-write-ops/src/txs_mp.rs b/rust-libs/duniter-dbs-write-ops/src/txs_mp.rs
index c47a52dd2..7f9e51395 100644
--- a/rust-libs/duniter-dbs-write-ops/src/txs_mp.rs
+++ b/rust-libs/duniter-dbs-write-ops/src/txs_mp.rs
@@ -41,7 +41,7 @@ pub fn add_pending_tx<
     B: Backend,
     F: FnOnce(
         &TransactionDocumentV10,
-        &TxColRw<B::Col, duniter_dbs::txs_mp_v2::TxsEvent>,
+        &TxColRw<B::Col, duniter_dbs::databases::txs_mp_v2::TxsEvent>,
     ) -> KvResult<()>,
 >(
     control: F,
diff --git a/rust-libs/duniter-dbs/src/databases.rs b/rust-libs/duniter-dbs/src/databases.rs
new file mode 100644
index 000000000..e45967840
--- /dev/null
+++ b/rust-libs/duniter-dbs/src/databases.rs
@@ -0,0 +1,20 @@
+//  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/>.
+
+pub mod bc_v1;
+pub mod bc_v2;
+pub mod cm_v1;
+pub mod gva_v1;
+pub mod txs_mp_v2;
diff --git a/rust-libs/duniter-dbs/src/bc_v1.rs b/rust-libs/duniter-dbs/src/databases/bc_v1.rs
similarity index 100%
rename from rust-libs/duniter-dbs/src/bc_v1.rs
rename to rust-libs/duniter-dbs/src/databases/bc_v1.rs
diff --git a/rust-libs/duniter-dbs/src/bc_v2.rs b/rust-libs/duniter-dbs/src/databases/bc_v2.rs
similarity index 100%
rename from rust-libs/duniter-dbs/src/bc_v2.rs
rename to rust-libs/duniter-dbs/src/databases/bc_v2.rs
diff --git a/rust-libs/duniter-dbs/src/cm_v1.rs b/rust-libs/duniter-dbs/src/databases/cm_v1.rs
similarity index 100%
rename from rust-libs/duniter-dbs/src/cm_v1.rs
rename to rust-libs/duniter-dbs/src/databases/cm_v1.rs
diff --git a/rust-libs/duniter-dbs/src/gva_v1.rs b/rust-libs/duniter-dbs/src/databases/gva_v1.rs
similarity index 100%
rename from rust-libs/duniter-dbs/src/gva_v1.rs
rename to rust-libs/duniter-dbs/src/databases/gva_v1.rs
diff --git a/rust-libs/duniter-dbs/src/txs_mp_v2.rs b/rust-libs/duniter-dbs/src/databases/txs_mp_v2.rs
similarity index 100%
rename from rust-libs/duniter-dbs/src/txs_mp_v2.rs
rename to rust-libs/duniter-dbs/src/databases/txs_mp_v2.rs
diff --git a/rust-libs/duniter-dbs/src/lib.rs b/rust-libs/duniter-dbs/src/lib.rs
index 4ff45f436..f96cd1885 100644
--- a/rust-libs/duniter-dbs/src/lib.rs
+++ b/rust-libs/duniter-dbs/src/lib.rs
@@ -22,13 +22,9 @@
     unused_import_braces
 )]
 
-mod bc_v1;
-pub mod bc_v2;
-pub mod cm_v1;
-pub mod gva_v1;
+pub mod databases;
 mod keys;
 mod open_dbs;
-pub mod txs_mp_v2;
 mod values;
 
 // Re-export dependencies
@@ -56,8 +52,6 @@ pub use crate::open_dbs::open_dbs;
 
 // Export profession types
 pub use crate::keys::utxo_id::UtxoIdDbV2;
-pub use bc_v1::{BcV1Db, BcV1DbReadable, BcV1DbRo, BcV1DbWritable, MainBlocksEvent, UidsEvent};
-pub use gva_v1::{GvaV1Db, GvaV1DbReadable, GvaV1DbRo, GvaV1DbWritable};
 pub use keys::all::AllKeyV1;
 pub use keys::block_number::BlockNumberKeyV1;
 pub use keys::blockstamp::BlockstampKeyV1;
@@ -70,7 +64,6 @@ pub use keys::ud_id::UdIdV2;
 pub use keys::uid::UidKeyV1;
 pub use keys::utxo_id::GvaUtxoIdDbV1;
 pub use keys::wallet_conditions::{WalletConditionsV1, WalletConditionsV2};
-pub use txs_mp_v2::{TxsMpV2Db, TxsMpV2DbReadable, TxsMpV2DbRo, TxsMpV2DbWritable};
 pub use values::block_db::{BlockDbEnum, BlockDbV1, TransactionInBlockDbV1};
 pub use values::block_head_db::BlockHeadDbV1;
 pub use values::block_meta::BlockMetaV2;
@@ -121,21 +114,23 @@ pub type FileBackend = kv_typed::backend::memory::Mem;
 
 #[derive(Clone, Debug)]
 pub struct DuniterDbs<B: Backend> {
-    pub bc_db_ro: bc_v2::BcV2DbRo<B>,
-    pub cm_db: cm_v1::CmV1Db<MemSingleton>,
-    pub gva_db: GvaV1Db<B>,
-    pub txs_mp_db: TxsMpV2Db<B>,
+    pub bc_db_ro: databases::bc_v2::BcV2DbRo<B>,
+    pub cm_db: databases::cm_v1::CmV1Db<MemSingleton>,
+    pub gva_db: databases::gva_v1::GvaV1Db<B>,
+    pub txs_mp_db: databases::txs_mp_v2::TxsMpV2Db<B>,
 }
 
 impl DuniterDbs<Mem> {
     pub fn mem() -> KvResult<Self> {
-        use bc_v2::BcV2DbWritable as _;
-        use cm_v1::CmV1DbWritable as _;
+        use databases::bc_v2::BcV2DbWritable as _;
+        use databases::cm_v1::CmV1DbWritable as _;
+        use databases::gva_v1::GvaV1DbWritable as _;
+        use databases::txs_mp_v2::TxsMpV2DbWritable as _;
         Ok(DuniterDbs {
-            bc_db_ro: bc_v2::BcV2Db::<Mem>::open(MemConf::default())?.get_ro_handler(),
-            cm_db: cm_v1::CmV1Db::<MemSingleton>::open(MemSingletonConf::default())?,
-            gva_db: GvaV1Db::<Mem>::open(MemConf::default())?,
-            txs_mp_db: TxsMpV2Db::<Mem>::open(MemConf::default())?,
+            bc_db_ro: databases::bc_v2::BcV2Db::<Mem>::open(MemConf::default())?.get_ro_handler(),
+            cm_db: databases::cm_v1::CmV1Db::<MemSingleton>::open(MemSingletonConf::default())?,
+            gva_db: databases::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?,
+            txs_mp_db: databases::txs_mp_v2::TxsMpV2Db::<Mem>::open(MemConf::default())?,
         })
     }
 }
diff --git a/rust-libs/duniter-dbs/src/open_dbs.rs b/rust-libs/duniter-dbs/src/open_dbs.rs
index 001a06718..0c4795e50 100644
--- a/rust-libs/duniter-dbs/src/open_dbs.rs
+++ b/rust-libs/duniter-dbs/src/open_dbs.rs
@@ -13,23 +13,32 @@
 // 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/>.
 
-use crate::bc_v2::BcV2DbWritable as _;
-use crate::cm_v1::CmV1DbWritable as _;
+use crate::databases::bc_v2::BcV2DbWritable as _;
+use crate::databases::cm_v1::CmV1DbWritable as _;
+use crate::databases::gva_v1::GvaV1DbWritable as _;
+use crate::databases::txs_mp_v2::TxsMpV2DbWritable as _;
 use crate::*;
 
 pub fn open_dbs<B: BackendConf>(
     home_path_opt: Option<&Path>,
-) -> (crate::bc_v2::BcV2Db<B>, DuniterDbs<B>) {
-    let bc_db = crate::bc_v2::BcV2Db::<B>::open(B::gen_backend_conf("bc_v2", home_path_opt))
-        .expect("fail to open BcV2 DB");
+) -> (crate::databases::bc_v2::BcV2Db<B>, DuniterDbs<B>) {
+    let bc_db =
+        crate::databases::bc_v2::BcV2Db::<B>::open(B::gen_backend_conf("bc_v2", home_path_opt))
+            .expect("fail to open BcV2 DB");
     let dbs = DuniterDbs {
         bc_db_ro: bc_db.get_ro_handler(),
-        cm_db: crate::cm_v1::CmV1Db::<MemSingleton>::open(MemSingletonConf::default())
+        cm_db: crate::databases::cm_v1::CmV1Db::<MemSingleton>::open(MemSingletonConf::default())
             .expect("fail to open CmV1 DB"),
-        gva_db: GvaV1Db::<B>::open(B::gen_backend_conf("gva_v1", home_path_opt))
-            .expect("fail to open Gva DB"),
-        txs_mp_db: TxsMpV2Db::<B>::open(B::gen_backend_conf("txs_mp_v2", home_path_opt))
-            .expect("fail to open TxsMp DB"),
+        gva_db: crate::databases::gva_v1::GvaV1Db::<B>::open(B::gen_backend_conf(
+            "gva_v1",
+            home_path_opt,
+        ))
+        .expect("fail to open Gva DB"),
+        txs_mp_db: crate::databases::txs_mp_v2::TxsMpV2Db::<B>::open(B::gen_backend_conf(
+            "txs_mp_v2",
+            home_path_opt,
+        ))
+        .expect("fail to open TxsMp DB"),
     };
     (bc_db, dbs)
 }
diff --git a/rust-libs/duniter-dbs/tests/test_explorer.rs b/rust-libs/duniter-dbs/tests/test_explorer.rs
index cbfdb4c5c..76e0b7a9c 100644
--- a/rust-libs/duniter-dbs/tests/test_explorer.rs
+++ b/rust-libs/duniter-dbs/tests/test_explorer.rs
@@ -22,7 +22,10 @@ mod explorer {
     use duniter_dbs::kv_typed::regex;
     use duniter_dbs::prelude::*;
     use duniter_dbs::smallvec::smallvec;
-    use duniter_dbs::{BcV1Db, BcV1DbWritable, PublicKeySingletonDbV1, UidKeyV1};
+    use duniter_dbs::{
+        databases::bc_v1::{BcV1Db, BcV1DbWritable},
+        PublicKeySingletonDbV1, UidKeyV1,
+    };
     use std::{num::NonZeroUsize, str::FromStr};
     use tempdir::TempDir;
     use unwrap::unwrap;
diff --git a/rust-libs/duniter-dbs/tests/test_read_write.rs b/rust-libs/duniter-dbs/tests/test_read_write.rs
index b1af6b37b..e08ac88e8 100644
--- a/rust-libs/duniter-dbs/tests/test_read_write.rs
+++ b/rust-libs/duniter-dbs/tests/test_read_write.rs
@@ -18,8 +18,8 @@ use dubp::common::crypto::keys::PublicKey as _;
 use dubp::common::prelude::*;
 use duniter_dbs::kv_typed::prelude::*;
 use duniter_dbs::{
-    BcV1Db, BcV1DbReadable, BcV1DbWritable, BlockDbV1, BlockNumberKeyV1, MainBlocksEvent,
-    PublicKeySingletonDbV1, UidKeyV1,
+    databases::bc_v1::{BcV1Db, BcV1DbReadable, BcV1DbWritable, MainBlocksEvent},
+    BlockDbV1, BlockNumberKeyV1, PublicKeySingletonDbV1, UidKeyV1,
 };
 use kv_typed::channel::TryRecvError;
 use std::str::FromStr;
diff --git a/rust-libs/duniter-mempools/src/lib.rs b/rust-libs/duniter-mempools/src/lib.rs
index 63ecd1943..2851b5416 100644
--- a/rust-libs/duniter-mempools/src/lib.rs
+++ b/rust-libs/duniter-mempools/src/lib.rs
@@ -28,7 +28,10 @@ use dubp::common::crypto::keys::ed25519::PublicKey;
 use dubp::documents::prelude::*;
 use dubp::documents::transaction::TransactionDocumentV10;
 use duniter_dbs::kv_typed::prelude::*;
-use duniter_dbs::{bc_v2::BcV2DbReadable, TxsMpV2Db, TxsMpV2DbReadable};
+use duniter_dbs::{
+    databases::bc_v2::BcV2DbReadable,
+    databases::txs_mp_v2::{TxsMpV2Db, TxsMpV2DbReadable},
+};
 use thiserror::Error;
 
 #[derive(Clone, Copy, Debug, Default)]
diff --git a/rust-libs/duniter-module/src/lib.rs b/rust-libs/duniter-module/src/lib.rs
index e16aa988d..1ad5b71c1 100644
--- a/rust-libs/duniter-module/src/lib.rs
+++ b/rust-libs/duniter-module/src/lib.rs
@@ -150,7 +150,7 @@ macro_rules! plug_duniter_modules {
                     ..Default::default()
                 };
 
-                use duniter_dbs::cm_v1::CmV1DbWritable as _;
+                use duniter_dbs::databases::cm_v1::CmV1DbWritable as _;
                 use duniter_dbs::kv_typed::prelude::DbCollectionRw as _;
                 dbs_pool.execute(|dbs| dbs.cm_db.self_peer_old_write().upsert((), self_peer)).await?.context("fail to save self peer card")?;
 
diff --git a/rust-libs/duniter-server/src/lib.rs b/rust-libs/duniter-server/src/lib.rs
index f926dd293..8b340dac3 100644
--- a/rust-libs/duniter-server/src/lib.rs
+++ b/rust-libs/duniter-server/src/lib.rs
@@ -33,10 +33,15 @@ use dubp::documents::{prelude::*, transaction::TransactionDocumentV10};
 use dubp::{
     block::prelude::*, common::crypto::hashs::Hash, documents_parser::prelude::FromStringObject,
 };
-use duniter_dbs::bc_v2::BcV2Db;
-use duniter_dbs::cm_v1::{CmV1DbReadable, CmV1DbWritable};
 use duniter_dbs::{
-    kv_typed::prelude::*, GvaV1DbReadable, HashKeyV2, PendingTxDbV2, TxsMpV2DbReadable,
+    databases::{
+        bc_v2::BcV2Db,
+        cm_v1::{CmV1DbReadable, CmV1DbWritable},
+        gva_v1::GvaV1DbReadable,
+        txs_mp_v2::TxsMpV2DbReadable,
+    },
+    kv_typed::prelude::*,
+    HashKeyV2, PendingTxDbV2,
 };
 use duniter_dbs::{prelude::*, BlockMetaV2, FileBackend};
 use duniter_gva_dbs_reader::txs_history::TxsHistory;
@@ -57,7 +62,8 @@ pub struct DuniterServer {
     conf: DuniterConf,
     current: Option<BlockMetaV2>,
     dbs_pool: fast_threadpool::ThreadPoolSyncHandler<DuniterDbs<FileBackend>>,
-    pending_txs_subscriber: flume::Receiver<Arc<Events<duniter_dbs::txs_mp_v2::TxsEvent>>>,
+    pending_txs_subscriber:
+        flume::Receiver<Arc<Events<duniter_dbs::databases::txs_mp_v2::TxsEvent>>>,
     txs_mempool: TxsMempool,
 }
 
@@ -178,10 +184,10 @@ impl DuniterServer {
             use std::ops::Deref as _;
             for event in events.deref() {
                 match event {
-                    duniter_dbs::txs_mp_v2::TxsEvent::Upsert { key, value } => {
+                    duniter_dbs::databases::txs_mp_v2::TxsEvent::Upsert { key, value } => {
                         new_pending_txs.insert(key.0, value.0.clone());
                     }
-                    duniter_dbs::txs_mp_v2::TxsEvent::Remove { key } => {
+                    duniter_dbs::databases::txs_mp_v2::TxsEvent::Remove { key } => {
                         new_pending_txs.remove(&key.0);
                     }
                     _ => (),
diff --git a/rust-libs/modules/gva/db-writer/src/identities.rs b/rust-libs/modules/gva/db-writer/src/identities.rs
index e6b55563b..4815d39a9 100644
--- a/rust-libs/modules/gva/db-writer/src/identities.rs
+++ b/rust-libs/modules/gva/db-writer/src/identities.rs
@@ -14,7 +14,7 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 use crate::*;
-use duniter_dbs::gva_v1::GvaIdentitiesEvent;
+use duniter_dbs::databases::gva_v1::GvaIdentitiesEvent;
 
 pub(crate) fn update_identities<B: Backend>(
     block: &DubpBlockV10,
diff --git a/rust-libs/modules/gva/db-writer/src/lib.rs b/rust-libs/modules/gva/db-writer/src/lib.rs
index 6346c5bb4..2c6a309d8 100644
--- a/rust-libs/modules/gva/db-writer/src/lib.rs
+++ b/rust-libs/modules/gva/db-writer/src/lib.rs
@@ -33,10 +33,11 @@ use dubp::documents::{
     prelude::*, transaction::TransactionDocumentTrait, transaction::TransactionDocumentV10,
 };
 use dubp::wallet::prelude::*;
-use duniter_dbs::gva_v1::*;
+use duniter_dbs::databases::gva_v1::*;
 use duniter_dbs::{
-    kv_typed::prelude::*, GvaV1Db, GvaV1DbReadable, GvaV1DbWritable, HashKeyV2, PubKeyKeyV2,
-    SourceAmountValV2, TxDbV2, WalletConditionsV2,
+    databases::gva_v1::{GvaV1Db, GvaV1DbReadable, GvaV1DbWritable},
+    kv_typed::prelude::*,
+    HashKeyV2, PubKeyKeyV2, SourceAmountValV2, TxDbV2, WalletConditionsV2,
 };
 use resiter::filter::Filter;
 use std::collections::HashMap;
@@ -214,7 +215,7 @@ mod tests {
 
     #[test]
     fn test_gva_apply_block() -> anyhow::Result<()> {
-        let gva_db = duniter_dbs::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?;
+        let gva_db = duniter_dbs::databases::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?;
 
         let s1 = WalletScriptV10::single_sig(PublicKey::from_base58(
             "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx",
diff --git a/rust-libs/modules/gva/db-writer/src/tx.rs b/rust-libs/modules/gva/db-writer/src/tx.rs
index 733145857..2a5e1836b 100644
--- a/rust-libs/modules/gva/db-writer/src/tx.rs
+++ b/rust-libs/modules/gva/db-writer/src/tx.rs
@@ -14,7 +14,7 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 use crate::*;
-use duniter_dbs::gva_v1::BalancesEvent;
+use duniter_dbs::databases::gva_v1::BalancesEvent;
 
 pub(crate) type ScriptsHash = HashMap<WalletScriptV10, Hash>;
 
@@ -323,7 +323,7 @@ mod tests {
         let o1_amount = ud0_amount - SourceAmount::with_base0(600);
         let o2_amount = ud0_amount - SourceAmount::with_base0(400);
 
-        let gva_db = duniter_dbs::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?;
+        let gva_db = duniter_dbs::databases::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?;
 
         let b0 = BlockMetaV2 {
             dividend: Some(ud0_amount),
diff --git a/rust-libs/modules/gva/db-writer/src/utxos.rs b/rust-libs/modules/gva/db-writer/src/utxos.rs
index 950808ee3..b04ac63f3 100644
--- a/rust-libs/modules/gva/db-writer/src/utxos.rs
+++ b/rust-libs/modules/gva/db-writer/src/utxos.rs
@@ -17,8 +17,8 @@ use crate::*;
 use duniter_dbs::GvaUtxoIdDbV1;
 
 pub(crate) fn write_utxo_v10<'s, B: Backend>(
-    scripts_by_pubkey: &mut TxColRw<B::Col, duniter_dbs::gva_v1::ScriptsByPubkeyEvent>,
-    gva_utxos: &mut TxColRw<B::Col, duniter_dbs::gva_v1::GvaUtxosEvent>,
+    scripts_by_pubkey: &mut TxColRw<B::Col, duniter_dbs::databases::gva_v1::ScriptsByPubkeyEvent>,
+    gva_utxos: &mut TxColRw<B::Col, duniter_dbs::databases::gva_v1::GvaUtxosEvent>,
     utxo: UtxoV10<'s>,
     utxo_script_hash: Hash,
 ) -> KvResult<()> {
@@ -49,8 +49,8 @@ pub(crate) fn write_utxo_v10<'s, B: Backend>(
 }
 
 pub(crate) fn remove_utxo_v10<B: Backend>(
-    scripts_by_pubkey: &mut TxColRw<B::Col, duniter_dbs::gva_v1::ScriptsByPubkeyEvent>,
-    gva_utxos: &mut TxColRw<B::Col, duniter_dbs::gva_v1::GvaUtxosEvent>,
+    scripts_by_pubkey: &mut TxColRw<B::Col, duniter_dbs::databases::gva_v1::ScriptsByPubkeyEvent>,
+    gva_utxos: &mut TxColRw<B::Col, duniter_dbs::databases::gva_v1::GvaUtxosEvent>,
     utxo_id: UtxoIdV10,
     utxo_script: &WalletScriptV10,
     utxo_script_hash: Hash,
diff --git a/rust-libs/modules/gva/dbs-reader/src/find_inputs.rs b/rust-libs/modules/gva/dbs-reader/src/find_inputs.rs
index 2719a5ede..084dbb648 100644
--- a/rust-libs/modules/gva/dbs-reader/src/find_inputs.rs
+++ b/rust-libs/modules/gva/dbs-reader/src/find_inputs.rs
@@ -137,18 +137,20 @@ impl DbsReader {
 mod tests {
     use super::*;
     use duniter_dbs::{
-        bc_v2::BcV2DbWritable, gva_v1::GvaV1DbWritable, txs_mp_v2::TxsMpV2DbWritable, BlockMetaV2,
-        GvaUtxoIdDbV1, SourceAmountValV2, UdIdV2, UtxoIdDbV2, UtxoValV2, WalletConditionsV2,
+        databases::{bc_v2::BcV2DbWritable, gva_v1::GvaV1DbWritable, txs_mp_v2::TxsMpV2DbWritable},
+        BlockMetaV2, GvaUtxoIdDbV1, SourceAmountValV2, UdIdV2, UtxoIdDbV2, UtxoValV2,
+        WalletConditionsV2,
     };
 
     const UD0: i64 = 10;
 
     #[test]
     fn test_find_inputs() -> anyhow::Result<()> {
-        let bc_db = duniter_dbs::bc_v2::BcV2Db::<Mem>::open(MemConf::default())?;
-        let gva_db = duniter_dbs::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?;
+        let bc_db = duniter_dbs::databases::bc_v2::BcV2Db::<Mem>::open(MemConf::default())?;
+        let gva_db = duniter_dbs::databases::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?;
         let db_reader = create_dbs_reader(unsafe { std::mem::transmute(&gva_db.get_ro_handler()) });
-        let txs_mp_db = duniter_dbs::txs_mp_v2::TxsMpV2Db::<Mem>::open(MemConf::default())?;
+        let txs_mp_db =
+            duniter_dbs::databases::txs_mp_v2::TxsMpV2Db::<Mem>::open(MemConf::default())?;
 
         let b0 = BlockMetaV2 {
             dividend: Some(SourceAmount::with_base0(UD0)),
diff --git a/rust-libs/modules/gva/dbs-reader/src/lib.rs b/rust-libs/modules/gva/dbs-reader/src/lib.rs
index 99676f705..820de44e0 100644
--- a/rust-libs/modules/gva/dbs-reader/src/lib.rs
+++ b/rust-libs/modules/gva/dbs-reader/src/lib.rs
@@ -35,11 +35,14 @@ use dubp::common::crypto::hashs::Hash;
 use dubp::common::crypto::keys::ed25519::PublicKey;
 use dubp::documents::transaction::TransactionDocumentV10;
 use dubp::{common::prelude::BlockNumber, wallet::prelude::*};
-use duniter_dbs::bc_v2::{BcV2DbReadable, BcV2DbRo};
-use duniter_dbs::{gva_v1::GvaV1DbRo, FileBackend};
+use duniter_dbs::databases::{
+    bc_v2::{BcV2DbReadable, BcV2DbRo},
+    gva_v1::{GvaV1DbReadable, GvaV1DbRo},
+    txs_mp_v2::TxsMpV2DbReadable,
+};
+use duniter_dbs::FileBackend;
 use duniter_dbs::{
-    kv_typed::prelude::*, GvaV1DbReadable, HashKeyV2, PubKeyKeyV2, SourceAmountValV2, TxDbV2,
-    TxsMpV2DbReadable, UtxoIdDbV2,
+    kv_typed::prelude::*, HashKeyV2, PubKeyKeyV2, SourceAmountValV2, TxDbV2, UtxoIdDbV2,
 };
 use resiter::filter::Filter;
 use resiter::filter_map::FilterMap;
@@ -88,8 +91,8 @@ impl DbsReader {
 #[cfg(test)]
 impl DbsReader {
     pub(crate) fn mem() -> Self {
-        use duniter_dbs::gva_v1::GvaV1DbWritable;
-        let gva_db = duniter_dbs::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())
+        use duniter_dbs::databases::gva_v1::GvaV1DbWritable;
+        let gva_db = duniter_dbs::databases::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())
             .expect("fail to create memory gva db");
         create_dbs_reader(unsafe { std::mem::transmute(&gva_db.get_ro_handler()) })
     }
diff --git a/rust-libs/modules/gva/dbs-reader/src/uds_of_pubkey.rs b/rust-libs/modules/gva/dbs-reader/src/uds_of_pubkey.rs
index 1033e7206..4c9eb8107 100644
--- a/rust-libs/modules/gva/dbs-reader/src/uds_of_pubkey.rs
+++ b/rust-libs/modules/gva/dbs-reader/src/uds_of_pubkey.rs
@@ -16,7 +16,7 @@
 use crate::*;
 use duniter_dbs::smallvec::SmallVec;
 use duniter_dbs::{
-    bc_v2::{UdsEvent, UdsRevalEvent},
+    databases::bc_v2::{UdsEvent, UdsRevalEvent},
     GvaIdtyDbV1, UdIdV2,
 };
 
@@ -472,7 +472,10 @@ mod tests {
 
     use super::*;
     use duniter_dbs::smallvec::smallvec as svec;
-    use duniter_dbs::{bc_v2::BcV2DbWritable, GvaV1DbWritable, SourceAmountValV2, UdIdV2};
+    use duniter_dbs::{
+        databases::{bc_v2::BcV2DbWritable, gva_v1::GvaV1DbWritable},
+        SourceAmountValV2, UdIdV2,
+    };
     use std::iter::FromIterator;
 
     #[test]
@@ -533,9 +536,9 @@ mod tests {
             first_ud: Some(BlockNumber(29)),
         };
 
-        let bc_db = duniter_dbs::bc_v2::BcV2Db::<Mem>::open(MemConf::default())?;
+        let bc_db = duniter_dbs::databases::bc_v2::BcV2Db::<Mem>::open(MemConf::default())?;
         let bc_db_ro = bc_db.get_ro_handler();
-        let gva_db = duniter_dbs::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?;
+        let gva_db = duniter_dbs::databases::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?;
         let db_reader = create_dbs_reader(unsafe { std::mem::transmute(&gva_db.get_ro_handler()) });
         bc_db
             .uds_reval_write()
@@ -701,7 +704,7 @@ mod tests {
     #[test]
     fn test_unspent_uds_of_pubkey() -> KvResult<()> {
         let pk = PublicKey::default();
-        let bc_db = duniter_dbs::bc_v2::BcV2Db::<Mem>::open(MemConf::default())?;
+        let bc_db = duniter_dbs::databases::bc_v2::BcV2Db::<Mem>::open(MemConf::default())?;
         let dbs_reader = DbsReader::mem();
 
         bc_db
diff --git a/rust-libs/modules/gva/dbs-reader/src/utxos.rs b/rust-libs/modules/gva/dbs-reader/src/utxos.rs
index 7f316c243..e4339143e 100644
--- a/rust-libs/modules/gva/dbs-reader/src/utxos.rs
+++ b/rust-libs/modules/gva/dbs-reader/src/utxos.rs
@@ -306,16 +306,17 @@ where
 mod tests {
 
     use super::*;
-    use duniter_dbs::GvaV1DbWritable;
-    use duniter_dbs::TxsMpV2DbWritable;
+    use duniter_dbs::databases::gva_v1::GvaV1DbWritable;
+    use duniter_dbs::databases::txs_mp_v2::TxsMpV2DbWritable;
 
     #[test]
     fn test_find_script_utxos() -> anyhow::Result<()> {
         let script = WalletScriptV10::single_sig(PublicKey::default());
 
-        let gva_db = duniter_dbs::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?;
+        let gva_db = duniter_dbs::databases::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?;
         let db_reader = create_dbs_reader(unsafe { std::mem::transmute(&gva_db.get_ro_handler()) });
-        let txs_mp_db = duniter_dbs::txs_mp_v2::TxsMpV2Db::<Mem>::open(MemConf::default())?;
+        let txs_mp_db =
+            duniter_dbs::databases::txs_mp_v2::TxsMpV2Db::<Mem>::open(MemConf::default())?;
 
         gva_db.gva_utxos_write().upsert(
             GvaUtxoIdDbV1::new(script.clone(), 0, Hash::default(), 0),
diff --git a/rust-libs/modules/gva/src/lib.rs b/rust-libs/modules/gva/src/lib.rs
index 9a855f4df..0b1cb6612 100644
--- a/rust-libs/modules/gva/src/lib.rs
+++ b/rust-libs/modules/gva/src/lib.rs
@@ -57,9 +57,9 @@ use dubp::documents::prelude::*;
 use dubp::documents::transaction::{TransactionDocumentTrait, TransactionDocumentV10};
 use dubp::documents_parser::prelude::*;
 use dubp::wallet::prelude::*;
-use duniter_dbs::gva_v1::GvaV1DbRo;
+use duniter_dbs::databases::{gva_v1::GvaV1DbRo, txs_mp_v2::TxsMpV2DbReadable};
 use duniter_dbs::prelude::*;
-use duniter_dbs::{kv_typed::prelude::*, FileBackend, TxDbV2, TxsMpV2DbReadable};
+use duniter_dbs::{kv_typed::prelude::*, FileBackend, TxDbV2};
 #[cfg(not(test))]
 use duniter_gva_dbs_reader::create_dbs_reader;
 #[cfg(not(test))]
@@ -217,7 +217,7 @@ impl GvaModule {
     async fn get_gva_db_ro(
         dbs_pool: &fast_threadpool::ThreadPoolAsyncHandler<DuniterDbs<FileBackend>>,
     ) -> &'static GvaV1DbRo<FileBackend> {
-        use duniter_dbs::gva_v1::GvaV1DbWritable as _;
+        use duniter_dbs::databases::gva_v1::GvaV1DbWritable as _;
         dbs_pool
             .execute(|dbs| GVA_DB_RO.get_or_init(|| dbs.gva_db.get_ro_handler()))
             .await
@@ -356,7 +356,7 @@ mod tests {
     use super::*;
     use dubp::documents::transaction::TransactionInputV10;
     use duniter_conf::DuniterConf;
-    use duniter_dbs::bc_v2::*;
+    use duniter_dbs::databases::bc_v2::*;
     use duniter_dbs::SourceAmountValV2;
     use duniter_gva_dbs_reader::pagination::*;
     use duniter_mempools::Mempools;
diff --git a/rust-libs/modules/gva/src/queries.rs b/rust-libs/modules/gva/src/queries.rs
index 17146d979..2d240cdf3 100644
--- a/rust-libs/modules/gva/src/queries.rs
+++ b/rust-libs/modules/gva/src/queries.rs
@@ -20,7 +20,7 @@ pub mod uds;
 pub mod utxos_of_script;
 
 use crate::*;
-use duniter_dbs::cm_v1::CmV1DbReadable as _;
+use duniter_dbs::databases::cm_v1::CmV1DbReadable as _;
 
 #[derive(async_graphql::MergedObject, Default)]
 pub struct QueryRoot(
diff --git a/rust-libs/modules/gva/src/queries/uds.rs b/rust-libs/modules/gva/src/queries/uds.rs
index 2d2443ab2..a52a2ad4c 100644
--- a/rust-libs/modules/gva/src/queries/uds.rs
+++ b/rust-libs/modules/gva/src/queries/uds.rs
@@ -15,7 +15,7 @@
 
 use crate::*;
 use async_graphql::connection::*;
-use duniter_dbs::bc_v2::BcV2DbReadable;
+use duniter_dbs::databases::bc_v2::BcV2DbReadable;
 use duniter_gva_dbs_reader::{uds_of_pubkey::UdsWithSum, PagedData};
 
 #[derive(Default)]
@@ -160,7 +160,7 @@ mod tests {
     #[tokio::test]
     async fn query_current_ud() -> anyhow::Result<()> {
         let mut dbs_reader = MockDbsReader::new();
-        use duniter_dbs::bc_v2::BcV2DbRo;
+        use duniter_dbs::databases::bc_v2::BcV2DbRo;
         dbs_reader
             .expect_get_current_ud::<BcV2DbRo<FileBackend>>()
             .times(1)
diff --git a/rust-libs/modules/gva/src/queries/utxos_of_script.rs b/rust-libs/modules/gva/src/queries/utxos_of_script.rs
index 00edaae9a..cccaa8124 100644
--- a/rust-libs/modules/gva/src/queries/utxos_of_script.rs
+++ b/rust-libs/modules/gva/src/queries/utxos_of_script.rs
@@ -15,7 +15,7 @@
 
 use crate::*;
 use async_graphql::connection::*;
-use duniter_dbs::GvaV1DbReadable;
+use duniter_dbs::databases::gva_v1::GvaV1DbReadable;
 use duniter_gva_dbs_reader::{
     utxos::{UtxoCursor, UtxosWithSum},
     PagedData,
diff --git a/rust-libs/modules/gva/src/subscriptions.rs b/rust-libs/modules/gva/src/subscriptions.rs
index 7dd697b27..391c4f582 100644
--- a/rust-libs/modules/gva/src/subscriptions.rs
+++ b/rust-libs/modules/gva/src/subscriptions.rs
@@ -36,7 +36,7 @@ impl SubscriptionRoot {
         r.into_stream().filter_map(|events| {
             let mut txs = Vec::new();
             for event in events.deref() {
-                if let duniter_dbs::txs_mp_v2::TxsEvent::Upsert {
+                if let duniter_dbs::databases::txs_mp_v2::TxsEvent::Upsert {
                     value: ref pending_tx,
                     ..
                 } = event
-- 
GitLab


From fb64bae454bde5ace21ecb7a0eec67fd0d36aa9d Mon Sep 17 00:00:00 2001
From: librelois <c@elo.tf>
Date: Mon, 7 Dec 2020 16:38:24 +0100
Subject: [PATCH 2/4] [feat] store peers and heads in rust dbs

---
 app/lib/dal/fileDAL.ts                        |   3 +
 app/modules/ws2p/lib/WS2PCluster.ts           |   5 +-
 neon/native/server.d.ts                       | 107 ++++---
 neon/native/src/server.rs                     | 266 +++++++++++-------
 rust-libs/duniter-dbs/src/databases.rs        |   1 +
 rust-libs/duniter-dbs/src/databases/cm_v1.rs  |   2 +-
 .../duniter-dbs/src/databases/dunp_v1.rs      |  21 ++
 rust-libs/duniter-dbs/src/keys.rs             |   1 +
 .../duniter-dbs/src/keys/dunp_node_id.rs      |  95 +++++++
 rust-libs/duniter-dbs/src/lib.rs              |   9 +-
 rust-libs/duniter-dbs/src/open_dbs.rs         |   8 +-
 rust-libs/duniter-dbs/src/values.rs           |   1 +
 rust-libs/duniter-dbs/src/values/dunp_head.rs | 127 +++++++++
 rust-libs/duniter-server/src/lib.rs           | 112 +++++---
 test/dal/basic-dal-tests.ts                   |  12 +-
 15 files changed, 587 insertions(+), 183 deletions(-)
 create mode 100644 rust-libs/duniter-dbs/src/databases/dunp_v1.rs
 create mode 100644 rust-libs/duniter-dbs/src/keys/dunp_node_id.rs
 create mode 100644 rust-libs/duniter-dbs/src/values/dunp_head.rs

diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts
index f9d66fe7f..423c07f66 100644
--- a/app/lib/dal/fileDAL.ts
+++ b/app/lib/dal/fileDAL.ts
@@ -1183,6 +1183,7 @@ export class FileDAL implements ServerDAO {
   }
 
   async removePeerByPubkey(pubkey: string) {
+    this.rustServer.removePeerByPubkey(pubkey);
     return this.peerDAL.removePeerByPubkey(pubkey);
   }
 
@@ -1473,6 +1474,7 @@ export class FileDAL implements ServerDAO {
   }
 
   savePeer(peer: DBPeer) {
+    this.rustServer.savePeer(PeerDTO.fromDBPeer(peer));
     return this.peerDAL.savePeer(peer);
   }
 
@@ -1602,6 +1604,7 @@ export class FileDAL implements ServerDAO {
   }
 
   async resetPeers() {
+    this.rustServer.removeAllPeers();
     await this.peerDAL.removeAll();
     return await this.close();
   }
diff --git a/app/modules/ws2p/lib/WS2PCluster.ts b/app/modules/ws2p/lib/WS2PCluster.ts
index bb49f3b0e..080150134 100644
--- a/app/modules/ws2p/lib/WS2PCluster.ts
+++ b/app/modules/ws2p/lib/WS2PCluster.ts
@@ -25,7 +25,7 @@ import { PeerDTO, WS2PEndpoint } from "../../../lib/dto/PeerDTO";
 import { GlobalFifoPromise } from "../../../service/GlobalFifoPromise";
 import { OtherConstants } from "../../../lib/other_constants";
 import { Key } from "../../../lib/common-libs/crypto/keyring";
-import { verify } from "../../../../neon/lib";
+import { RustServer, verify } from "../../../../neon/lib";
 import { WS2PServerMessageHandler } from "./interface/WS2PServerMessageHandler";
 import { WS2PMessageHandler } from "./impl/WS2PMessageHandler";
 import { CommonConstants } from "../../../lib/common-libs/constants";
@@ -238,6 +238,9 @@ export class WS2PCluster {
       }
     }, WS2PConstants.HEADS_SPREAD_TIMEOUT);
 
+    // Send HEADs to rust server
+    this.server.dal.rustServer.receiveNewHeads(this.newHeads);
+
     this.server.push({
       ws2p: "heads",
       added: this.newHeads,
diff --git a/neon/native/server.d.ts b/neon/native/server.d.ts
index 39f626d27..c65a605b1 100644
--- a/neon/native/server.d.ts
+++ b/neon/native/server.d.ts
@@ -2,12 +2,36 @@
 
 import { TransactionDTOV10 } from './transaction';
 
-export class RustServerConf {
-    command: string | null
-    currency: string
-    gva: GvaConf | undefined
-    selfKeypair: string | null
-    txsMempoolSize: number
+export class BlockDTOV10 {
+    version: number;
+    number: number;
+    currency: string;
+    hash: string;
+    inner_hash: string;
+    previousHash: string;
+    issuer: string;
+    previousIssuer: string;
+    dividend: number | null;
+    time: number;
+    powMin: number;
+    unitbase: number;
+    membersCount: number;
+    issuersCount: number;
+    issuersFrame: number;
+    issuersFrameVar: number;
+    identities: string[];
+    joiners: string[];
+    actives: string[];
+    leavers: string[];
+    revoked: string[];
+    excluded: string[];
+    certifications: string[];
+    transactions: TransactionDTOV10[];
+    medianTime: number;
+    nonce: number;
+    parameters: string | null;
+    signature: string;
+    monetaryMass: number;
 }
 
 export class GvaConf {
@@ -24,6 +48,12 @@ export class GvaConf {
     whitelist?: string[];
 }
 
+export class HeadWS2Pv1 {
+    messageV2?: string;
+    sigV2?: string;
+    step?: number;
+}
+
 export class PeerCard {
     version: number
     currency: string
@@ -51,6 +81,14 @@ export class RustDbTx {
     writtenTime: number;
 }
 
+export class RustServerConf {
+    command: string | null
+    currency: string
+    gva: GvaConf | undefined
+    selfKeypair: string | null
+    txsMempoolSize: number
+}
+
 export class TxsHistory {
     sent: RustDbTx[];
     received: RustDbTx[];
@@ -58,54 +96,35 @@ export class TxsHistory {
     pending: TransactionDTOV10[];
 }
 
-export class BlockDTOV10 {
-    version: number;
-    number: number;
-    currency: string;
-    hash: string;
-    inner_hash: string;
-    previousHash: string;
-    issuer: string;
-    previousIssuer: string;
-    dividend: number | null;
-    time: number;
-    powMin: number;
-    unitbase: number;
-    membersCount: number;
-    issuersCount: number;
-    issuersFrame: number;
-    issuersFrameVar: number;
-    identities: string[];
-    joiners: string[];
-    actives: string[];
-    leavers: string[];
-    revoked: string[];
-    excluded: string[];
-    certifications: string[];
-    transactions: TransactionDTOV10[];
-    medianTime: number;
-    nonce: number;
-    parameters: string | null;
-    signature: string;
-    monetaryMass: number;
-}
-
 export class RustServer {
     constructor(conf: RustServerConf, home: string | null);
 
+    // Indexing blockchain
+    revertBlock(block: BlockDTOV10): void;
+    applyBlock(block: BlockDTOV10): void;
+    applyChunkOfBlocks(blocks: BlockDTOV10[]): void;
+    
+    // Rust Endpoints (GVA, etc)
+    getSelfEndpoints(): string[];
+
+    // Txs mempool
     acceptNewTx(tx: TransactionDTOV10, serverPubkey: string): boolean;
     addPendingTx(tx: TransactionDTOV10): void;
     getMempoolTxsFreeRooms(): number;
     getNewPendingTxs(): TransactionDTOV10[];
-    getSelfEndpoints(): string[];
-    getTransactionsHistory(pubkey: string): TxsHistory;
     getTransactionsPending(versionMin: number, medianTime: number): TransactionDTOV10[];
-    getTxByHash(hash: string): TransactionDTOV10 | null;
     removeAllPendingTxs(): void;
     removePendingTxByHash(hash: string): void;
-    revertBlock(block: BlockDTOV10): void;
-    applyBlock(block: BlockDTOV10): void;
-    applyChunkOfBlocks(blocks: BlockDTOV10[]): void;
     trimExpiredNonWrittenTxs(limitTime: number): void;
+
+    // Transactions history (for BMA only)
+    getTransactionsHistory(pubkey: string): TxsHistory;
+    getTxByHash(hash: string): TransactionDTOV10 | null;
+    
+    // WS2Pv1: HEADs and peers
+    receiveNewHeads(heads: HeadWS2Pv1[]): void;
+    removeAllPeers(): void; 
+    removePeerByPubkey(pubkey: string): void;
+    savePeer(peer: PeerCard): void;
     updateSelfPeer(peer: PeerCard): void;
 }
diff --git a/neon/native/src/server.rs b/neon/native/src/server.rs
index 769318dd0..70a46f68d 100644
--- a/neon/native/src/server.rs
+++ b/neon/native/src/server.rs
@@ -82,22 +82,50 @@ declare_types! {
                 }.map(|server| RustServer { server })
             )
         }
-        method acceptNewTx(mut cx) {
-            let tx_js = cx.argument::<JsValue>(0)?;
-            let server_pubkey_str = cx.argument::<JsString>(1)?.value();
 
-            let tx_str: TransactionDocumentV10Stringified = neon_serde::from_value(&mut cx, tx_js)?;
-            let tx = into_neon_res(&mut cx, TransactionDocumentV10::from_string_object(&tx_str))?;
-            let server_pubkey = into_neon_res(&mut cx, PublicKey::from_base58(&server_pubkey_str))?;
+        // Indexing blockchain
+        method revertBlock(mut cx) {
+            let block_js = cx.argument::<JsValue>(0)?;
 
-            let this = cx.this();
+            let block_stringified: dubp::block::DubpBlockV10Stringified = neon_serde::from_value(&mut cx, block_js)?;
+
+            let mut this = cx.this();
             let res = {
                 let guard = cx.lock();
-                let server = this.borrow(&guard);
-                server.server.accept_new_tx(tx, server_pubkey)
-            }.map(|accepted| cx.boolean(accepted).upcast());
+                let mut server = this.borrow_mut(&guard);
+                server.server.revert_block(block_stringified)
+            }.map(|()| cx.undefined().upcast());
+            into_neon_res(&mut cx, res)
+        }
+        method applyBlock(mut cx) {
+            let block_js = cx.argument::<JsValue>(0)?;
+
+            let block_stringified: dubp::block::DubpBlockV10Stringified = neon_serde::from_value(&mut cx, block_js)?;
+
+            let mut this = cx.this();
+            let res = {
+                let guard = cx.lock();
+                let mut server = this.borrow_mut(&guard);
+                server.server.apply_block(block_stringified)
+            }.map(|()| cx.undefined().upcast());
             into_neon_res(&mut cx, res)
         }
+        method applyChunkOfBlocks(mut cx) {
+            let blocks_js = cx.argument::<JsValue>(0)?;
+
+            let blocks_stringified: Vec<dubp::block::DubpBlockV10Stringified> = neon_serde::from_value(&mut cx, blocks_js)?;
+
+            let mut this = cx.this();
+            let res = {
+                let guard = cx.lock();
+                let mut server = this.borrow_mut(&guard);
+                server.server.apply_chunk_of_blocks(blocks_stringified)
+            }.map(|()| cx.undefined().upcast());
+            into_neon_res(&mut cx, res)
+        }
+
+
+        // Rust Endpoints (GVA, etc)
         method getSelfEndpoints(mut cx) {
             let this = cx.this();
             let res = {
@@ -114,54 +142,46 @@ declare_types! {
             });
             into_neon_res(&mut cx, res)
         }
-        method getTxByHash(mut cx) {
-            let hash_str = cx.argument::<JsString>(0)?.value();
-            let hash = into_neon_res(&mut cx, Hash::from_hex(&hash_str))?;
+
+
+        // Txs mempool
+        method acceptNewTx(mut cx) {
+            let tx_js = cx.argument::<JsValue>(0)?;
+            let server_pubkey_str = cx.argument::<JsString>(1)?.value();
+
+            let tx_str: TransactionDocumentV10Stringified = neon_serde::from_value(&mut cx, tx_js)?;
+            let tx = into_neon_res(&mut cx, TransactionDocumentV10::from_string_object(&tx_str))?;
+            let server_pubkey = into_neon_res(&mut cx, PublicKey::from_base58(&server_pubkey_str))?;
 
             let this = cx.this();
             let res = {
                 let guard = cx.lock();
                 let server = this.borrow(&guard);
-                server.server.get_tx_by_hash(hash)
-            };
-            match res {
-                Ok(tx_opt) => if let Some((tx, written_block_opt)) = tx_opt {
-                    let tx_js = neon_serde::to_value(&mut cx, &tx.to_string_object())?;
-                    if let Some(written_block) = written_block_opt {
-                        let written_block =  cx.number(written_block.0);
-                        let tx_js = tx_js.downcast_or_throw::<JsObject, _>(&mut cx)?;
-                        tx_js.set(&mut cx, "writtenBlock", written_block)?;
-                    }
-                    Ok(tx_js.upcast())
-                } else {
-                    Ok(cx.null().upcast())
-                },
-                Err(e) => cx.throw_error(format!("{}", e)),
-            }
+                server.server.accept_new_tx(tx, server_pubkey)
+            }.map(|accepted| cx.boolean(accepted).upcast());
+            into_neon_res(&mut cx, res)
         }
-        method removePendingTxByHash(mut cx) {
-            let hash_str = cx.argument::<JsString>(0)?.value();
-            let hash = into_neon_res(&mut cx, Hash::from_hex(&hash_str))?;
+        method addPendingTx(mut cx) {
+            let tx_js = cx.argument::<JsValue>(0)?;
+
+            let tx_str: TransactionDocumentV10Stringified = neon_serde::from_value(&mut cx, tx_js)?;
+            let tx = into_neon_res(&mut cx, TransactionDocumentV10::from_string_object(&tx_str))?;
 
             let this = cx.this();
             let res = {
                 let guard = cx.lock();
                 let server = this.borrow(&guard);
-                server.server.remove_pending_tx_by_hash(hash)
-            }.map(|()| cx.undefined().upcast());
+                server.server.add_pending_tx_force(tx)
+            }.map(|_| cx.undefined().upcast());
             into_neon_res(&mut cx, res)
         }
-        method revertBlock(mut cx) {
-            let block_js = cx.argument::<JsValue>(0)?;
-
-            let block_stringified: dubp::block::DubpBlockV10Stringified = neon_serde::from_value(&mut cx, block_js)?;
-
-            let mut this = cx.this();
+        method getMempoolTxsFreeRooms(mut cx) {
+            let this = cx.this();
             let res = {
                 let guard = cx.lock();
-                let mut server = this.borrow_mut(&guard);
-                server.server.revert_block(block_stringified)
-            }.map(|()| cx.undefined().upcast());
+                let server = this.borrow(&guard);
+                server.server.get_mempool_txs_free_rooms()
+            }.map(|free_rooms| cx.number(free_rooms as f64).upcast());
             into_neon_res(&mut cx, res)
         }
         method getNewPendingTxs(mut cx) {
@@ -197,57 +217,40 @@ declare_types! {
                 Err(e) => cx.throw_error(format!("{}", e)),
             }
         }
-        method trimExpiredNonWrittenTxs(mut cx) {
-            let limit_time = cx.argument::<JsNumber>(0)?.value() as i64;
-
+        method removeAllPendingTxs(mut cx) {
             let this = cx.this();
             let res = {
                 let guard = cx.lock();
                 let server = this.borrow(&guard);
-                server.server.trim_expired_non_written_txs(limit_time)
-            }.map(|()| cx.undefined().upcast());
-            into_neon_res(&mut cx, res)
-        }
-        method applyBlock(mut cx) {
-            let block_js = cx.argument::<JsValue>(0)?;
-
-            let block_stringified: dubp::block::DubpBlockV10Stringified = neon_serde::from_value(&mut cx, block_js)?;
-
-            let mut this = cx.this();
-            let res = {
-                let guard = cx.lock();
-                let mut server = this.borrow_mut(&guard);
-                server.server.apply_block(block_stringified)
+                server.server.remove_all_pending_txs()
             }.map(|()| cx.undefined().upcast());
             into_neon_res(&mut cx, res)
         }
-        method applyChunkOfBlocks(mut cx) {
-            let blocks_js = cx.argument::<JsValue>(0)?;
-
-            let blocks_stringified: Vec<dubp::block::DubpBlockV10Stringified> = neon_serde::from_value(&mut cx, blocks_js)?;
+        method removePendingTxByHash(mut cx) {
+            let hash_str = cx.argument::<JsString>(0)?.value();
+            let hash = into_neon_res(&mut cx, Hash::from_hex(&hash_str))?;
 
-            let mut this = cx.this();
+            let this = cx.this();
             let res = {
                 let guard = cx.lock();
-                let mut server = this.borrow_mut(&guard);
-                server.server.apply_chunk_of_blocks(blocks_stringified)
+                let server = this.borrow(&guard);
+                server.server.remove_pending_tx_by_hash(hash)
             }.map(|()| cx.undefined().upcast());
             into_neon_res(&mut cx, res)
         }
-        method addPendingTx(mut cx) {
-            let tx_js = cx.argument::<JsValue>(0)?;
-
-            let tx_str: TransactionDocumentV10Stringified = neon_serde::from_value(&mut cx, tx_js)?;
-            let tx = into_neon_res(&mut cx, TransactionDocumentV10::from_string_object(&tx_str))?;
+        method trimExpiredNonWrittenTxs(mut cx) {
+            let limit_time = cx.argument::<JsNumber>(0)?.value() as i64;
 
             let this = cx.this();
             let res = {
                 let guard = cx.lock();
                 let server = this.borrow(&guard);
-                server.server.add_pending_tx_force(tx)
-            }.map(|_| cx.undefined().upcast());
+                server.server.trim_expired_non_written_txs(limit_time)
+            }.map(|()| cx.undefined().upcast());
             into_neon_res(&mut cx, res)
         }
+
+        // Transactions history (for BMA only)
         method getTransactionsHistory(mut cx) {
             let pubkey_str = cx.argument::<JsString>(0)?.value();
             let pubkey = into_neon_res(&mut cx, PublicKey::from_base58(&pubkey_str))?;
@@ -281,21 +284,82 @@ declare_types! {
                 Err(e) => cx.throw_error(format!("{}", e)),
             }
         }
-        method getMempoolTxsFreeRooms(mut cx) {
+        method getTxByHash(mut cx) {
+            let hash_str = cx.argument::<JsString>(0)?.value();
+            let hash = into_neon_res(&mut cx, Hash::from_hex(&hash_str))?;
+
             let this = cx.this();
             let res = {
                 let guard = cx.lock();
                 let server = this.borrow(&guard);
-                server.server.get_mempool_txs_free_rooms()
-            }.map(|free_rooms| cx.number(free_rooms as f64).upcast());
+                server.server.get_tx_by_hash(hash)
+            };
+            match res {
+                Ok(tx_opt) => if let Some((tx, written_block_opt)) = tx_opt {
+                    let tx_js = neon_serde::to_value(&mut cx, &tx.to_string_object())?;
+                    if let Some(written_block) = written_block_opt {
+                        let written_block =  cx.number(written_block.0);
+                        let tx_js = tx_js.downcast_or_throw::<JsObject, _>(&mut cx)?;
+                        tx_js.set(&mut cx, "writtenBlock", written_block)?;
+                    }
+                    Ok(tx_js.upcast())
+                } else {
+                    Ok(cx.null().upcast())
+                },
+                Err(e) => cx.throw_error(format!("{}", e)),
+            }
+        }
+
+        // WS2Pv1: HEADs and peers
+        method receiveNewHeads(mut cx) {
+            let heads_js = cx.argument::<JsValue>(0)?;
+
+            let heads_stringified: Vec<HeadWS2Pv1ConfStringified> = neon_serde::from_value(&mut cx, heads_js)?;
+
+            use duniter_server::{DunpNodeIdV1Db, DunpHeadDbV1, KvResult};
+            let heads = into_neon_res(&mut cx, heads_stringified.into_iter().map(|HeadWS2Pv1ConfStringified { message_v2, sig_v2, .. }| {
+                DunpHeadDbV1::from_stringified(&message_v2.unwrap_or_default(), &sig_v2.unwrap_or_default())
+            }).collect::<KvResult<Vec<(DunpNodeIdV1Db, DunpHeadDbV1)>>>())?;
+
+            let this = cx.this();
+            let res = {
+                let guard = cx.lock();
+                let server = this.borrow(&guard);
+                server.server.receive_new_heads(heads)
+            }.map(|()| cx.undefined().upcast());
             into_neon_res(&mut cx, res)
         }
-        method removeAllPendingTxs(mut cx) {
+        method removeAllPeers(mut cx) {
             let this = cx.this();
             let res = {
                 let guard = cx.lock();
                 let server = this.borrow(&guard);
-                server.server.remove_all_pending_txs()
+                server.server.remove_all_peers()
+            }.map(|()| cx.undefined().upcast());
+            into_neon_res(&mut cx, res)
+        }
+        method removePeerByPubkey(mut cx) {
+            let pubkey_str = cx.argument::<JsString>(0)?.value();
+            let pubkey = into_neon_res(&mut cx, PublicKey::from_base58(&pubkey_str))?;
+
+            let this = cx.this();
+            let res = {
+                let guard = cx.lock();
+                let server = this.borrow(&guard);
+                server.server.remove_peer_by_pubkey(pubkey)
+            }.map(|()| cx.undefined().upcast());
+            into_neon_res(&mut cx, res)
+        }
+        method savePeer(mut cx) {
+            let peer_js = cx.argument::<JsValue>(0)?;
+
+            let peer_stringified: PeerCardStringified = neon_serde::from_value(&mut cx, peer_js)?;
+
+            let this = cx.this();
+            let res = {
+                let guard = cx.lock();
+                let server = this.borrow(&guard);
+                server.server.save_peer(peer_stringified)
             }.map(|()| cx.undefined().upcast());
             into_neon_res(&mut cx, res)
         }
@@ -315,24 +379,6 @@ declare_types! {
     }
 }
 
-#[derive(Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-struct RustServerConfStringified {
-    command_name: Option<String>,
-    currency: String,
-    gva: Option<GvaConf>,
-    self_keypair: Option<String>,
-    txs_mempool_size: u32,
-}
-
-#[derive(Deserialize, Serialize)]
-struct TxsHistoryStringified {
-    sent: Vec<DbTx>,
-    received: Vec<DbTx>,
-    sending: Vec<TransactionDocumentV10Stringified>,
-    pending: Vec<TransactionDocumentV10Stringified>,
-}
-
 #[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct DbTx {
@@ -375,3 +421,29 @@ impl DbTx {
         }
     }
 }
+
+#[derive(Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct HeadWS2Pv1ConfStringified {
+    message_v2: Option<String>,
+    sig_v2: Option<String>,
+    step: Option<usize>,
+}
+
+#[derive(Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct RustServerConfStringified {
+    command_name: Option<String>,
+    currency: String,
+    gva: Option<GvaConf>,
+    self_keypair: Option<String>,
+    txs_mempool_size: u32,
+}
+
+#[derive(Deserialize, Serialize)]
+struct TxsHistoryStringified {
+    sent: Vec<DbTx>,
+    received: Vec<DbTx>,
+    sending: Vec<TransactionDocumentV10Stringified>,
+    pending: Vec<TransactionDocumentV10Stringified>,
+}
diff --git a/rust-libs/duniter-dbs/src/databases.rs b/rust-libs/duniter-dbs/src/databases.rs
index e45967840..1c49eafdf 100644
--- a/rust-libs/duniter-dbs/src/databases.rs
+++ b/rust-libs/duniter-dbs/src/databases.rs
@@ -16,5 +16,6 @@
 pub mod bc_v1;
 pub mod bc_v2;
 pub mod cm_v1;
+pub mod dunp_v1;
 pub mod gva_v1;
 pub mod txs_mp_v2;
diff --git a/rust-libs/duniter-dbs/src/databases/cm_v1.rs b/rust-libs/duniter-dbs/src/databases/cm_v1.rs
index f94dc2176..9771aff31 100644
--- a/rust-libs/duniter-dbs/src/databases/cm_v1.rs
+++ b/rust-libs/duniter-dbs/src/databases/cm_v1.rs
@@ -18,7 +18,7 @@ use crate::*;
 db_schema!(
     CmV1,
     [
-        //["self_pubkey", self_pubkey, (), PubKeyValV2,],
         ["self_peer_old", SelfPeerOld, (), PeerCardDbV1],
+        ["dunp_heads_old", DunpHeadsOld, DunpNodeIdV1Db, DunpHeadDbV1],
     ]
 );
diff --git a/rust-libs/duniter-dbs/src/databases/dunp_v1.rs b/rust-libs/duniter-dbs/src/databases/dunp_v1.rs
new file mode 100644
index 000000000..86e4b320a
--- /dev/null
+++ b/rust-libs/duniter-dbs/src/databases/dunp_v1.rs
@@ -0,0 +1,21 @@
+//  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/>.
+
+use crate::*;
+
+db_schema!(
+    DunpV1,
+    [["peers_old", PeersOld, PubKeyKeyV2, PeerCardDbV1],]
+);
diff --git a/rust-libs/duniter-dbs/src/keys.rs b/rust-libs/duniter-dbs/src/keys.rs
index 70afba42b..b5d2db16b 100644
--- a/rust-libs/duniter-dbs/src/keys.rs
+++ b/rust-libs/duniter-dbs/src/keys.rs
@@ -16,6 +16,7 @@
 pub mod all;
 pub mod block_number;
 pub mod blockstamp;
+pub mod dunp_node_id;
 pub mod hash;
 pub mod pubkey;
 pub mod pubkey_and_sig;
diff --git a/rust-libs/duniter-dbs/src/keys/dunp_node_id.rs b/rust-libs/duniter-dbs/src/keys/dunp_node_id.rs
new file mode 100644
index 000000000..e1edbb969
--- /dev/null
+++ b/rust-libs/duniter-dbs/src/keys/dunp_node_id.rs
@@ -0,0 +1,95 @@
+//  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/>.
+
+use crate::*;
+use std::fmt::Display;
+use uninit::prelude::*;
+
+#[derive(
+    Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, zerocopy::AsBytes, zerocopy::FromBytes,
+)]
+#[repr(transparent)]
+pub struct DunpNodeIdV1Db([u8; 37]); // uuid ++ pubkey
+
+impl DunpNodeIdV1Db {
+    pub fn new(uuid: u32, pubkey: PublicKey) -> Self {
+        let mut buffer = uninit_array![u8; 37];
+        let (uuid_buffer, pubkey_buffer) = buffer.as_out().split_at_out(4);
+
+        uuid_buffer.copy_from_slice(&uuid.to_be_bytes()[..]);
+        pubkey_buffer.copy_from_slice(pubkey.as_ref());
+
+        Self(unsafe { std::mem::transmute(buffer) })
+    }
+    pub fn get_uuid(&self) -> u32 {
+        let mut buffer = uninit_array![u8; 4];
+
+        buffer.as_out().copy_from_slice(&self.0[..4]);
+
+        u32::from_be_bytes(unsafe { std::mem::transmute(buffer) })
+    }
+    pub fn get_pubkey(&self) -> PublicKey {
+        let mut buffer = uninit_array![u8; 33];
+
+        buffer.as_out().copy_from_slice(&self.0[4..]);
+        let bytes: [u8; 33] = unsafe { std::mem::transmute(buffer) };
+
+        PublicKey::try_from(&bytes[..]).unwrap_or_else(|_| unreachable!())
+    }
+}
+
+impl Default for DunpNodeIdV1Db {
+    fn default() -> Self {
+        DunpNodeIdV1Db([0u8; 37])
+    }
+}
+
+impl Display for DunpNodeIdV1Db {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{:x}-{}", self.get_uuid(), self.get_pubkey())
+    }
+}
+
+impl KeyAsBytes for DunpNodeIdV1Db {
+    fn as_bytes<T, F: FnMut(&[u8]) -> T>(&self, mut f: F) -> T {
+        f(self.0.as_ref())
+    }
+}
+
+impl kv_typed::prelude::FromBytes for DunpNodeIdV1Db {
+    type Err = StringErr;
+
+    fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, Self::Err> {
+        let layout = zerocopy::LayoutVerified::<_, DunpNodeIdV1Db>::new(bytes)
+            .ok_or_else(|| StringErr("corrupted db".to_owned()))?;
+        Ok(*layout)
+    }
+}
+
+impl ToDumpString for DunpNodeIdV1Db {
+    fn to_dump_string(&self) -> String {
+        todo!()
+    }
+}
+
+#[cfg(feature = "explorer")]
+impl ExplorableKey for DunpNodeIdV1Db {
+    fn from_explorer_str(_: &str) -> std::result::Result<Self, StringErr> {
+        unimplemented!()
+    }
+    fn to_explorer_string(&self) -> KvResult<String> {
+        Ok(self.to_string())
+    }
+}
diff --git a/rust-libs/duniter-dbs/src/lib.rs b/rust-libs/duniter-dbs/src/lib.rs
index f96cd1885..a9e2d3dd4 100644
--- a/rust-libs/duniter-dbs/src/lib.rs
+++ b/rust-libs/duniter-dbs/src/lib.rs
@@ -55,6 +55,7 @@ pub use crate::keys::utxo_id::UtxoIdDbV2;
 pub use keys::all::AllKeyV1;
 pub use keys::block_number::BlockNumberKeyV1;
 pub use keys::blockstamp::BlockstampKeyV1;
+pub use keys::dunp_node_id::DunpNodeIdV1Db;
 pub use keys::hash::{HashKeyV1, HashKeyV2};
 pub use keys::pubkey::{PubKeyKeyV1, PubKeyKeyV2};
 pub use keys::pubkey_and_sig::PubKeyAndSigV1;
@@ -69,6 +70,7 @@ pub use values::block_head_db::BlockHeadDbV1;
 pub use values::block_meta::BlockMetaV2;
 pub use values::block_number_array_db::BlockNumberArrayV1;
 pub use values::cindex_db::CIndexDbV1;
+pub use values::dunp_head::DunpHeadDbV1;
 pub use values::gva_idty_db::GvaIdtyDbV1;
 pub use values::idty_db::IdtyDbV2;
 pub use values::iindex_db::IIndexDbV1;
@@ -115,7 +117,8 @@ pub type FileBackend = kv_typed::backend::memory::Mem;
 #[derive(Clone, Debug)]
 pub struct DuniterDbs<B: Backend> {
     pub bc_db_ro: databases::bc_v2::BcV2DbRo<B>,
-    pub cm_db: databases::cm_v1::CmV1Db<MemSingleton>,
+    pub cm_db: databases::cm_v1::CmV1Db<Mem>,
+    pub dunp_db: databases::dunp_v1::DunpV1Db<B>,
     pub gva_db: databases::gva_v1::GvaV1Db<B>,
     pub txs_mp_db: databases::txs_mp_v2::TxsMpV2Db<B>,
 }
@@ -124,11 +127,13 @@ impl DuniterDbs<Mem> {
     pub fn mem() -> KvResult<Self> {
         use databases::bc_v2::BcV2DbWritable as _;
         use databases::cm_v1::CmV1DbWritable as _;
+        use databases::dunp_v1::DunpV1DbWritable as _;
         use databases::gva_v1::GvaV1DbWritable as _;
         use databases::txs_mp_v2::TxsMpV2DbWritable as _;
         Ok(DuniterDbs {
             bc_db_ro: databases::bc_v2::BcV2Db::<Mem>::open(MemConf::default())?.get_ro_handler(),
-            cm_db: databases::cm_v1::CmV1Db::<MemSingleton>::open(MemSingletonConf::default())?,
+            cm_db: databases::cm_v1::CmV1Db::<Mem>::open(MemConf::default())?,
+            dunp_db: databases::dunp_v1::DunpV1Db::<Mem>::open(MemConf::default())?,
             gva_db: databases::gva_v1::GvaV1Db::<Mem>::open(MemConf::default())?,
             txs_mp_db: databases::txs_mp_v2::TxsMpV2Db::<Mem>::open(MemConf::default())?,
         })
diff --git a/rust-libs/duniter-dbs/src/open_dbs.rs b/rust-libs/duniter-dbs/src/open_dbs.rs
index 0c4795e50..014d5aaf6 100644
--- a/rust-libs/duniter-dbs/src/open_dbs.rs
+++ b/rust-libs/duniter-dbs/src/open_dbs.rs
@@ -15,6 +15,7 @@
 
 use crate::databases::bc_v2::BcV2DbWritable as _;
 use crate::databases::cm_v1::CmV1DbWritable as _;
+use crate::databases::dunp_v1::DunpV1DbWritable as _;
 use crate::databases::gva_v1::GvaV1DbWritable as _;
 use crate::databases::txs_mp_v2::TxsMpV2DbWritable as _;
 use crate::*;
@@ -27,8 +28,13 @@ pub fn open_dbs<B: BackendConf>(
             .expect("fail to open BcV2 DB");
     let dbs = DuniterDbs {
         bc_db_ro: bc_db.get_ro_handler(),
-        cm_db: crate::databases::cm_v1::CmV1Db::<MemSingleton>::open(MemSingletonConf::default())
+        cm_db: crate::databases::cm_v1::CmV1Db::<Mem>::open(MemConf::default())
             .expect("fail to open CmV1 DB"),
+        dunp_db: crate::databases::dunp_v1::DunpV1Db::<B>::open(B::gen_backend_conf(
+            "dunp_v1",
+            home_path_opt,
+        ))
+        .expect("fail to open Dunp DB"),
         gva_db: crate::databases::gva_v1::GvaV1Db::<B>::open(B::gen_backend_conf(
             "gva_v1",
             home_path_opt,
diff --git a/rust-libs/duniter-dbs/src/values.rs b/rust-libs/duniter-dbs/src/values.rs
index a0bc4209b..27a5ce4fa 100644
--- a/rust-libs/duniter-dbs/src/values.rs
+++ b/rust-libs/duniter-dbs/src/values.rs
@@ -18,6 +18,7 @@ pub mod block_head_db;
 pub mod block_meta;
 pub mod block_number_array_db;
 pub mod cindex_db;
+pub mod dunp_head;
 pub mod gva_idty_db;
 pub mod idty_db;
 pub mod iindex_db;
diff --git a/rust-libs/duniter-dbs/src/values/dunp_head.rs b/rust-libs/duniter-dbs/src/values/dunp_head.rs
new file mode 100644
index 000000000..2ab352e9b
--- /dev/null
+++ b/rust-libs/duniter-dbs/src/values/dunp_head.rs
@@ -0,0 +1,127 @@
+//  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/>.
+
+use crate::*;
+
+#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
+pub struct DunpHeadDbV1 {
+    pub api: String,
+    pub pubkey: PublicKey,
+    pub blockstamp: Blockstamp,
+    pub software: String,
+    pub software_version: String,
+    pub pow_prefix: u32,
+    pub free_member_room: u32,
+    pub free_mirror_room: u32,
+    pub signature: Signature,
+}
+
+impl DunpHeadDbV1 {
+    pub fn from_stringified(message_v2: &str, signature: &str) -> KvResult<(DunpNodeIdV1Db, Self)> {
+        let signature =
+            Signature::from_base64(signature).map_err(|e| KvError::DeserError(e.to_string()))?;
+
+        let strs: SmallVec<[&str; 11]> = message_v2.split(':').collect();
+        if strs.len() < 11 {
+            return Err(KvError::DeserError(
+                "DunpHeadDbV1::from_stringified(): invalid message_v2".to_owned(),
+            ));
+        }
+
+        let uuid =
+            u32::from_str_radix(strs[5], 16).map_err(|e| KvError::DeserError(e.to_string()))?;
+        let pubkey =
+            PublicKey::from_base58(strs[3]).map_err(|e| KvError::DeserError(e.to_string()))?;
+        let blockstamp =
+            Blockstamp::from_str(strs[4]).map_err(|e| KvError::DeserError(e.to_string()))?;
+
+        Ok((
+            DunpNodeIdV1Db::new(uuid, pubkey),
+            DunpHeadDbV1 {
+                api: strs[0].to_owned(),
+                pubkey,
+                blockstamp,
+                software: strs[6].to_owned(),
+                software_version: strs[7].to_owned(),
+                pow_prefix: u32::from_str(strs[8])
+                    .map_err(|e| KvError::DeserError(e.to_string()))?,
+                free_member_room: u32::from_str(strs[9])
+                    .map_err(|e| KvError::DeserError(e.to_string()))?,
+                free_mirror_room: u32::from_str(strs[10])
+                    .map_err(|e| KvError::DeserError(e.to_string()))?,
+                signature,
+            },
+        ))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_dunp_head_from_stringified() -> KvResult<()> {
+        let message = "WS2POCAIC:HEAD:2:GX1nYVburxeaVP1SCNuhVKwNy6M2h6wPamHhyoSF4Ccn:379783-0000001BB2B88D077605C1330CA60AA222624FAA3BA60566D6CA51A9122376F7:882a5ad1:duniter:1.8.1:1:1:1";
+        let sig = "qBvJ7JZ4i8tKeItmZ/lurzr5O2/jKnB1reoIjEIl5x6sqbAhVsVsHut85yQoP30tURGfVX5FwMhCuC4DvCSFCg==";
+        let (node_id, head) = DunpHeadDbV1::from_stringified(message, sig)?;
+
+        assert_eq!(&format!("{:x}", node_id.get_uuid()), "882a5ad1");
+        assert_eq!(
+            &node_id.get_pubkey().to_string(),
+            "GX1nYVburxeaVP1SCNuhVKwNy6M2h6wPamHhyoSF4Ccn"
+        );
+        assert_eq!(&head.api, "WS2POCAIC");
+        assert_eq!(
+            &head.pubkey.to_string(),
+            "GX1nYVburxeaVP1SCNuhVKwNy6M2h6wPamHhyoSF4Ccn"
+        );
+        assert_eq!(
+            &head.blockstamp.to_string(),
+            "379783-0000001BB2B88D077605C1330CA60AA222624FAA3BA60566D6CA51A9122376F7"
+        );
+        Ok(())
+    }
+}
+
+impl ValueAsBytes for DunpHeadDbV1 {
+    fn as_bytes<T, F: FnMut(&[u8]) -> KvResult<T>>(&self, mut f: F) -> KvResult<T> {
+        let bytes = bincode::serialize(self).map_err(|e| KvError::DeserError(format!("{}", e)))?;
+        f(bytes.as_ref())
+    }
+}
+
+impl kv_typed::prelude::FromBytes for DunpHeadDbV1 {
+    type Err = StringErr;
+
+    fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, Self::Err> {
+        Ok(bincode::deserialize(&bytes).map_err(|e| StringErr(format!("{}: '{:?}'", e, bytes)))?)
+    }
+}
+
+impl ToDumpString for DunpHeadDbV1 {
+    fn to_dump_string(&self) -> String {
+        todo!()
+    }
+}
+
+#[cfg(feature = "explorer")]
+impl ExplorableValue for DunpHeadDbV1 {
+    fn from_explorer_str(_source: &str) -> std::result::Result<Self, StringErr> {
+        unimplemented!()
+    }
+    fn to_explorer_json(&self) -> KvResult<serde_json::Value> {
+        serde_json::to_value(self).map_err(|e| KvError::DeserError(format!("{}", e)))
+    }
+}
diff --git a/rust-libs/duniter-server/src/lib.rs b/rust-libs/duniter-server/src/lib.rs
index 8b340dac3..ac936bfed 100644
--- a/rust-libs/duniter-server/src/lib.rs
+++ b/rust-libs/duniter-server/src/lib.rs
@@ -23,7 +23,7 @@
 )]
 
 pub use duniter_conf::DuniterConf;
-pub use duniter_dbs::smallvec;
+pub use duniter_dbs::{kv_typed::prelude::KvResult, smallvec, DunpHeadDbV1, DunpNodeIdV1Db};
 pub use duniter_gva::{GvaConf, GvaModule, PeerCardStringified};
 
 use anyhow::Context;
@@ -41,7 +41,7 @@ use duniter_dbs::{
         txs_mp_v2::TxsMpV2DbReadable,
     },
     kv_typed::prelude::*,
-    HashKeyV2, PendingTxDbV2,
+    HashKeyV2, PendingTxDbV2, PubKeyKeyV2,
 };
 use duniter_dbs::{prelude::*, BlockMetaV2, FileBackend};
 use duniter_gva_dbs_reader::txs_history::TxsHistory;
@@ -250,7 +250,52 @@ impl DuniterServer {
             .execute(move |dbs| txs_mempool.add_pending_tx_force(&dbs.txs_mp_db, &tx))
             .expect("dbs pool disconnected")
     }
-
+    pub fn apply_block(&mut self, block: DubpBlockV10Stringified) -> KvResult<()> {
+        let block = Arc::new(
+            DubpBlockV10::from_string_object(&block)
+                .map_err(|e| KvError::DeserError(format!("{}", e)))?,
+        );
+        self.current = Some(duniter_dbs_write_ops::apply_block::apply_block(
+            &self.bc_db,
+            block.clone(),
+            self.current,
+            &self.dbs_pool,
+            false,
+        )?);
+        apply_block_modules(block, &self.conf, &self.dbs_pool, None)
+    }
+    pub fn apply_chunk_of_blocks(&mut self, blocks: Vec<DubpBlockV10Stringified>) -> KvResult<()> {
+        log::debug!("apply_chunk(#{})", blocks[0].number);
+        let blocks = Arc::from(
+            blocks
+                .into_iter()
+                .map(|block| DubpBlockV10::from_string_object(&block))
+                .collect::<Result<Vec<_>, _>>()
+                .map_err(|e| KvError::DeserError(format!("{}", e)))?,
+        );
+        self.current = Some(duniter_dbs_write_ops::apply_block::apply_chunk(
+            &self.bc_db,
+            self.current,
+            &self.dbs_pool,
+            blocks.clone(),
+        )?);
+        apply_chunk_of_blocks_modules(blocks, &self.conf, &self.dbs_pool, None)
+    }
+    pub fn receive_new_heads(
+        &self,
+        heads: Vec<(duniter_dbs::DunpNodeIdV1Db, duniter_dbs::DunpHeadDbV1)>,
+    ) -> KvResult<()> {
+        self.dbs_pool
+            .execute(move |dbs| {
+                for (dunp_node_id, dunp_head) in heads {
+                    dbs.cm_db
+                        .dunp_heads_old_write()
+                        .upsert(dunp_node_id, dunp_head)?
+                }
+                Ok::<(), KvError>(())
+            })
+            .expect("dbs pool disconnected")
+    }
     pub fn remove_all_pending_txs(&self) -> KvResult<()> {
         self.dbs_pool
             .execute(move |dbs| {
@@ -284,36 +329,39 @@ impl DuniterServer {
         txs_mp_job_handle.join().expect("dbs pool disconnected")?;
         revert_block_modules(block, &self.conf, &self.dbs_pool, None)
     }
-    pub fn apply_block(&mut self, block: DubpBlockV10Stringified) -> KvResult<()> {
-        let block = Arc::new(
-            DubpBlockV10::from_string_object(&block)
-                .map_err(|e| KvError::DeserError(format!("{}", e)))?,
-        );
-        self.current = Some(duniter_dbs_write_ops::apply_block::apply_block(
-            &self.bc_db,
-            block.clone(),
-            self.current,
-            &self.dbs_pool,
-            false,
-        )?);
-        apply_block_modules(block, &self.conf, &self.dbs_pool, None)
+    pub fn remove_all_peers(&self) -> KvResult<()> {
+        use duniter_dbs::databases::dunp_v1::DunpV1DbWritable as _;
+        self.dbs_pool
+            .execute(move |dbs| dbs.dunp_db.peers_old_write().clear())
+            .expect("dbs pool disconnected")
     }
-    pub fn apply_chunk_of_blocks(&mut self, blocks: Vec<DubpBlockV10Stringified>) -> KvResult<()> {
-        log::debug!("apply_chunk(#{})", blocks[0].number);
-        let blocks = Arc::from(
-            blocks
-                .into_iter()
-                .map(|block| DubpBlockV10::from_string_object(&block))
-                .collect::<Result<Vec<_>, _>>()
-                .map_err(|e| KvError::DeserError(format!("{}", e)))?,
-        );
-        self.current = Some(duniter_dbs_write_ops::apply_block::apply_chunk(
-            &self.bc_db,
-            self.current,
-            &self.dbs_pool,
-            blocks.clone(),
-        )?);
-        apply_chunk_of_blocks_modules(blocks, &self.conf, &self.dbs_pool, None)
+    pub fn remove_peer_by_pubkey(&self, pubkey: PublicKey) -> KvResult<()> {
+        use duniter_dbs::databases::dunp_v1::DunpV1DbWritable as _;
+        self.dbs_pool
+            .execute(move |dbs| dbs.dunp_db.peers_old_write().remove(PubKeyKeyV2(pubkey)))
+            .expect("dbs pool disconnected")
+    }
+    pub fn save_peer(&self, new_peer_card: PeerCardStringified) -> anyhow::Result<()> {
+        use dubp::crypto::keys::PublicKey as _;
+        let pubkey = PublicKey::from_base58(&new_peer_card.pubkey)?;
+        use duniter_dbs::databases::dunp_v1::DunpV1DbWritable as _;
+        self.dbs_pool
+            .execute(move |dbs| {
+                dbs.dunp_db.peers_old_write().upsert(
+                    PubKeyKeyV2(pubkey),
+                    duniter_dbs::PeerCardDbV1 {
+                        version: new_peer_card.version,
+                        currency: new_peer_card.currency,
+                        pubkey: new_peer_card.pubkey,
+                        blockstamp: new_peer_card.blockstamp,
+                        endpoints: new_peer_card.endpoints,
+                        status: new_peer_card.status,
+                        signature: new_peer_card.signature,
+                    },
+                )
+            })
+            .expect("dbs pool disconnected")
+            .map_err(|e| e.into())
     }
     pub fn trim_expired_non_written_txs(&self, limit_time: i64) -> KvResult<()> {
         self.dbs_pool
diff --git a/test/dal/basic-dal-tests.ts b/test/dal/basic-dal-tests.ts
index 7891325bc..a3e39fffc 100644
--- a/test/dal/basic-dal-tests.ts
+++ b/test/dal/basic-dal-tests.ts
@@ -26,12 +26,14 @@ var constants = require('../../app/lib/constants');
 var mocks = {
   peer1: {
     pubkey: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-      block: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855',
-      currency: 'bb',
-      version: constants.DOCUMENTS_VERSION,
-      endpoints: [
+    blockstamp: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855',
+    currency: 'bb',
+    version: constants.DOCUMENTS_VERSION,
+    endpoints: [
       'BASIC_MERKLED_API localhost 7777'
-    ]
+    ],
+    status: "UP",
+    signature: "T84YUhY5PeOH1cmlxn+UCG0YjYQSnpKRlyHTlsDTLB19QneCAIxDrxx+Yz/VfzXyq3B5ScjpQG5MQ45wI+tZAw==",
   },
   block0: {
     "issuersCount": 0,
-- 
GitLab


From e5a5cd08ab5ff2745b0cc5c0ea55a8c3f45429bc Mon Sep 17 00:00:00 2001
From: librelois <c@elo.tf>
Date: Wed, 9 Dec 2020 01:40:06 +0100
Subject: [PATCH 3/4] [test] server: test save_peer & receive_new_heads

---
 Cargo.lock                                    |   1 +
 rust-libs/duniter-module/src/lib.rs           |   2 +
 rust-libs/duniter-server/Cargo.toml           |   4 +
 rust-libs/duniter-server/src/legacy.rs        |  21 ++
 .../src/legacy/block_indexer.rs               |  69 ++++
 rust-libs/duniter-server/src/legacy/dunp.rs   | 166 ++++++++++
 .../duniter-server/src/legacy/tx_history.rs   |  47 +++
 .../duniter-server/src/legacy/txs_mempool.rs  | 117 +++++++
 rust-libs/duniter-server/src/lib.rs           | 294 +++---------------
 rust-libs/modules/gva/src/lib.rs              |   9 +-
 rust-libs/modules/gva/src/queries.rs          |   2 +-
 11 files changed, 473 insertions(+), 259 deletions(-)
 create mode 100644 rust-libs/duniter-server/src/legacy.rs
 create mode 100644 rust-libs/duniter-server/src/legacy/block_indexer.rs
 create mode 100644 rust-libs/duniter-server/src/legacy/dunp.rs
 create mode 100644 rust-libs/duniter-server/src/legacy/tx_history.rs
 create mode 100644 rust-libs/duniter-server/src/legacy/txs_mempool.rs

diff --git a/Cargo.lock b/Cargo.lock
index 6271a9a55..78d354aaf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1253,6 +1253,7 @@ name = "duniter-server"
 version = "1.8.1"
 dependencies = [
  "anyhow",
+ "cfg-if 1.0.0",
  "dubp",
  "duniter-conf",
  "duniter-dbs",
diff --git a/rust-libs/duniter-module/src/lib.rs b/rust-libs/duniter-module/src/lib.rs
index 1ad5b71c1..bc804f974 100644
--- a/rust-libs/duniter-module/src/lib.rs
+++ b/rust-libs/duniter-module/src/lib.rs
@@ -29,6 +29,8 @@ use duniter_mempools::Mempools;
 use fast_threadpool::{JoinHandle, ThreadPoolDisconnected};
 use std::path::Path;
 
+pub const SOFTWARE_NAME: &str = "duniter";
+
 pub type Endpoint = String;
 
 #[async_trait::async_trait]
diff --git a/rust-libs/duniter-server/Cargo.toml b/rust-libs/duniter-server/Cargo.toml
index de8b7bb4d..f3e120d72 100644
--- a/rust-libs/duniter-server/Cargo.toml
+++ b/rust-libs/duniter-server/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2018"
 
 [dependencies]
 anyhow = "1.0.34"
+cfg-if = "1.0.0"
 dubp = { version = "0.32.3" }
 duniter-conf = { path = "../duniter-conf" }
 duniter-dbs = { path = "../duniter-dbs" }
@@ -22,3 +23,6 @@ log = "0.4.11"
 paste = "1.0.2"
 resiter = "0.4.0"
 tokio = { version = "0.2.22", features = ["io-util", "rt-threaded"] }
+
+[dev-dependencies]
+duniter-dbs = { path = "../duniter-dbs", features = ["mem"] }
diff --git a/rust-libs/duniter-server/src/legacy.rs b/rust-libs/duniter-server/src/legacy.rs
new file mode 100644
index 000000000..d1d0a65b5
--- /dev/null
+++ b/rust-libs/duniter-server/src/legacy.rs
@@ -0,0 +1,21 @@
+//  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/>.
+
+//! Legacy functions intended to be used by DuniterJs uniquely. This module will be removed when the migration is complete.
+
+mod block_indexer;
+mod dunp;
+mod tx_history;
+mod txs_mempool;
diff --git a/rust-libs/duniter-server/src/legacy/block_indexer.rs b/rust-libs/duniter-server/src/legacy/block_indexer.rs
new file mode 100644
index 000000000..4b3483e1c
--- /dev/null
+++ b/rust-libs/duniter-server/src/legacy/block_indexer.rs
@@ -0,0 +1,69 @@
+//  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/>.
+
+use crate::*;
+
+impl DuniterServer {
+    pub fn apply_block(&mut self, block: DubpBlockV10Stringified) -> KvResult<()> {
+        let block = Arc::new(
+            DubpBlockV10::from_string_object(&block)
+                .map_err(|e| KvError::DeserError(format!("{}", e)))?,
+        );
+        self.current = Some(duniter_dbs_write_ops::apply_block::apply_block(
+            &self.bc_db,
+            block.clone(),
+            self.current,
+            &self.dbs_pool,
+            false,
+        )?);
+        apply_block_modules(block, &self.conf, &self.dbs_pool, None)
+    }
+    pub fn apply_chunk_of_blocks(&mut self, blocks: Vec<DubpBlockV10Stringified>) -> KvResult<()> {
+        log::debug!("apply_chunk(#{})", blocks[0].number);
+        let blocks = Arc::from(
+            blocks
+                .into_iter()
+                .map(|block| DubpBlockV10::from_string_object(&block))
+                .collect::<Result<Vec<_>, _>>()
+                .map_err(|e| KvError::DeserError(format!("{}", e)))?,
+        );
+        self.current = Some(duniter_dbs_write_ops::apply_block::apply_chunk(
+            &self.bc_db,
+            self.current,
+            &self.dbs_pool,
+            blocks.clone(),
+        )?);
+        apply_chunk_of_blocks_modules(blocks, &self.conf, &self.dbs_pool, None)
+    }
+    pub fn revert_block(&mut self, block: DubpBlockV10Stringified) -> KvResult<()> {
+        let block = Arc::new(
+            DubpBlockV10::from_string_object(&block)
+                .map_err(|e| KvError::DeserError(format!("{}", e)))?,
+        );
+        let block_arc_clone = Arc::clone(&block);
+        let txs_mp_job_handle = self
+            .dbs_pool
+            .launch(move |dbs| {
+                duniter_dbs_write_ops::txs_mp::revert_block(
+                    block_arc_clone.transactions(),
+                    &dbs.txs_mp_db,
+                )
+            })
+            .expect("dbs pool disconnected");
+        self.current = duniter_dbs_write_ops::bc::revert_block(&self.bc_db, &block)?;
+        txs_mp_job_handle.join().expect("dbs pool disconnected")?;
+        revert_block_modules(block, &self.conf, &self.dbs_pool, None)
+    }
+}
diff --git a/rust-libs/duniter-server/src/legacy/dunp.rs b/rust-libs/duniter-server/src/legacy/dunp.rs
new file mode 100644
index 000000000..020e32e70
--- /dev/null
+++ b/rust-libs/duniter-server/src/legacy/dunp.rs
@@ -0,0 +1,166 @@
+//  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/>.
+
+use crate::*;
+
+impl DuniterServer {
+    pub fn receive_new_heads(
+        &self,
+        heads: Vec<(duniter_dbs::DunpNodeIdV1Db, duniter_dbs::DunpHeadDbV1)>,
+    ) -> KvResult<()> {
+        self.dbs_pool
+            .execute(move |dbs| {
+                for (dunp_node_id, dunp_head) in heads {
+                    dbs.cm_db
+                        .dunp_heads_old_write()
+                        .upsert(dunp_node_id, dunp_head)?
+                }
+                Ok::<(), KvError>(())
+            })
+            .expect("dbs pool disconnected")
+    }
+    pub fn remove_all_peers(&self) -> KvResult<()> {
+        use duniter_dbs::databases::dunp_v1::DunpV1DbWritable as _;
+        self.dbs_pool
+            .execute(move |dbs| dbs.dunp_db.peers_old_write().clear())
+            .expect("dbs pool disconnected")
+    }
+    pub fn remove_peer_by_pubkey(&self, pubkey: PublicKey) -> KvResult<()> {
+        use duniter_dbs::databases::dunp_v1::DunpV1DbWritable as _;
+        self.dbs_pool
+            .execute(move |dbs| dbs.dunp_db.peers_old_write().remove(PubKeyKeyV2(pubkey)))
+            .expect("dbs pool disconnected")
+    }
+    pub fn save_peer(&self, new_peer_card: PeerCardStringified) -> anyhow::Result<()> {
+        use dubp::crypto::keys::PublicKey as _;
+        let pubkey = PublicKey::from_base58(&new_peer_card.pubkey)?;
+        use duniter_dbs::databases::dunp_v1::DunpV1DbWritable as _;
+        self.dbs_pool
+            .execute(move |dbs| {
+                dbs.dunp_db.peers_old_write().upsert(
+                    PubKeyKeyV2(pubkey),
+                    duniter_dbs::PeerCardDbV1 {
+                        version: new_peer_card.version,
+                        currency: new_peer_card.currency,
+                        pubkey: new_peer_card.pubkey,
+                        blockstamp: new_peer_card.blockstamp,
+                        endpoints: new_peer_card.endpoints,
+                        status: new_peer_card.status,
+                        signature: new_peer_card.signature,
+                    },
+                )
+            })
+            .expect("dbs pool disconnected")
+            .map_err(|e| e.into())
+    }
+    pub fn update_self_peer(&self, new_peer_card: PeerCardStringified) {
+        self.dbs_pool
+            .execute(move |dbs| {
+                dbs.cm_db
+                    .self_peer_old_write()
+                    .upsert(
+                        (),
+                        duniter_dbs::PeerCardDbV1 {
+                            version: new_peer_card.version,
+                            currency: new_peer_card.currency,
+                            pubkey: new_peer_card.pubkey,
+                            blockstamp: new_peer_card.blockstamp,
+                            endpoints: new_peer_card.endpoints,
+                            status: new_peer_card.status,
+                            signature: new_peer_card.signature,
+                        },
+                    )
+                    .expect("fail to write on memory db")
+            })
+            .expect("dbs pool disconnected")
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use dubp::crypto::keys::{
+        ed25519::{PublicKey, Signature},
+        PublicKey as _,
+    };
+    use duniter_dbs::PeerCardDbV1;
+
+    use super::*;
+
+    #[test]
+    fn test_receive_new_heads() -> anyhow::Result<()> {
+        use duniter_dbs::databases::cm_v1::CmV1DbReadable as _;
+        let (server, dbs) = DuniterServer::test(DuniterConf::default())?;
+
+        let head = (
+            duniter_dbs::DunpNodeIdV1Db::new(53, PublicKey::default()),
+            duniter_dbs::DunpHeadDbV1 {
+                api: "WS2P".to_owned(),
+                pubkey: PublicKey::default(),
+                blockstamp: Blockstamp::default(),
+                software: duniter_module::SOFTWARE_NAME.to_owned(),
+                software_version: "test".to_owned(),
+                pow_prefix: 1,
+                free_member_room: 0,
+                free_mirror_room: 0,
+                signature: Signature::default(),
+            },
+        );
+
+        assert_eq!(dbs.cm_db.dunp_heads_old().count()?, 0);
+        server.receive_new_heads(vec![head.clone()])?;
+        assert_eq!(dbs.cm_db.dunp_heads_old().count()?, 1);
+        assert_eq!(dbs.cm_db.dunp_heads_old().get(&head.0)?, Some(head.1));
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_save_peer() -> anyhow::Result<()> {
+        use duniter_dbs::databases::dunp_v1::DunpV1DbReadable as _;
+        let (server, dbs) = DuniterServer::test(DuniterConf::default())?;
+
+        let peer = PeerCardStringified {
+            version: 0,
+            currency: "test".to_owned(),
+            pubkey: "82NdD9eEbXSjRJXeJdqf56xkpu6taTfTeEqtAtmtbyXY".to_owned(),
+            blockstamp: "379922-0000001D97770A8203062F9E618F29FFAA2EF4218649FCE6DD13E01C3932E943".to_owned(),
+            endpoints: vec![],
+            status: "UP".to_owned(),
+            signature: "KBaoJuKIfkWJO015BTegUN8l81VYPfleVUfQUwPRPAAF1oB398hDb1bX/QUFe+3CKFz57aGT8bB745mz90x5Ag==".to_owned(),
+        };
+        let pubkey = PublicKey::from_base58(&peer.pubkey)?;
+
+        assert_eq!(dbs.dunp_db.peers_old().count()?, 0);
+        server.save_peer(peer.clone())?;
+
+        assert_eq!(dbs.dunp_db.peers_old().count()?, 1);
+        let peer_db = dbs.dunp_db.peers_old().get(&PubKeyKeyV2(pubkey))?;
+
+        assert_eq!(
+            peer_db,
+            Some(PeerCardDbV1 {
+                version: peer.version,
+                currency: peer.currency,
+                pubkey: peer.pubkey,
+                blockstamp: peer.blockstamp,
+                endpoints: peer.endpoints,
+                status: peer.status,
+                signature: peer.signature,
+            })
+        );
+
+        Ok(())
+    }
+}
diff --git a/rust-libs/duniter-server/src/legacy/tx_history.rs b/rust-libs/duniter-server/src/legacy/tx_history.rs
new file mode 100644
index 000000000..4c55b2fc0
--- /dev/null
+++ b/rust-libs/duniter-server/src/legacy/tx_history.rs
@@ -0,0 +1,47 @@
+//  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/>.
+
+use crate::*;
+
+impl DuniterServer {
+    pub fn get_transactions_history(&self, pubkey: PublicKey) -> KvResult<TxsHistory> {
+        self.dbs_pool
+            .execute(move |dbs| {
+                duniter_gva_dbs_reader::txs_history::get_transactions_history_for_bma(
+                    &dbs.gva_db,
+                    &dbs.txs_mp_db,
+                    pubkey,
+                )
+            })
+            .expect("dbs pool disconnected")
+    }
+
+    pub fn get_tx_by_hash(
+        &self,
+        hash: Hash,
+    ) -> KvResult<Option<(TransactionDocumentV10, Option<BlockNumber>)>> {
+        self.dbs_pool
+            .execute(move |dbs| {
+                if let Some(tx) = dbs.txs_mp_db.txs().get(&HashKeyV2(hash))? {
+                    Ok(Some((tx.0, None)))
+                } else if let Some(tx_db) = dbs.gva_db.txs().get(&HashKeyV2(hash))? {
+                    Ok(Some((tx_db.tx, Some(tx_db.written_block.number))))
+                } else {
+                    Ok(None)
+                }
+            })
+            .expect("dbs pool disconnected")
+    }
+}
diff --git a/rust-libs/duniter-server/src/legacy/txs_mempool.rs b/rust-libs/duniter-server/src/legacy/txs_mempool.rs
new file mode 100644
index 000000000..528a45b60
--- /dev/null
+++ b/rust-libs/duniter-server/src/legacy/txs_mempool.rs
@@ -0,0 +1,117 @@
+//  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/>.
+
+use crate::*;
+
+impl DuniterServer {
+    pub fn accept_new_tx(
+        &self,
+        tx: TransactionDocumentV10,
+        server_pubkey: PublicKey,
+    ) -> KvResult<bool> {
+        let txs_mempool = self.txs_mempool;
+        match self
+            .dbs_pool
+            .execute(move |dbs| {
+                txs_mempool.accept_new_tx(&dbs.bc_db_ro, server_pubkey, tx, &dbs.txs_mp_db)
+            })
+            .expect("dbs pool discorrected")
+        {
+            Ok(()) => Ok(true),
+            Err(TxMpError::Db(e)) => Err(e),
+            Err(_) => Ok(false),
+        }
+    }
+    pub fn add_pending_tx_force(&self, tx: TransactionDocumentV10) -> KvResult<()> {
+        let txs_mempool = self.txs_mempool;
+        self.dbs_pool
+            .execute(move |dbs| txs_mempool.add_pending_tx_force(&dbs.txs_mp_db, &tx))
+            .expect("dbs pool disconnected")
+    }
+    pub fn get_self_endpoints(&self) -> anyhow::Result<Vec<Endpoint>> {
+        if let Some(self_peer) = self
+            .dbs_pool
+            .execute(|dbs| dbs.cm_db.self_peer_old().get(&()))?
+            .context("fail to get self endpoints")?
+        {
+            Ok(self_peer.endpoints)
+        } else {
+            Ok(vec![])
+        }
+    }
+    pub fn get_mempool_txs_free_rooms(&self) -> KvResult<usize> {
+        let txs_mempool = self.txs_mempool;
+        self.dbs_pool
+            .execute(move |dbs| txs_mempool.get_free_rooms(&dbs.txs_mp_db))
+            .expect("dbs pool discorrected")
+    }
+    pub fn get_new_pending_txs(&self) -> KvResult<Vec<TransactionDocumentV10>> {
+        let mut new_pending_txs = BTreeMap::new();
+        for events in self.pending_txs_subscriber.drain() {
+            use std::ops::Deref as _;
+            for event in events.deref() {
+                match event {
+                    duniter_dbs::databases::txs_mp_v2::TxsEvent::Upsert { key, value } => {
+                        new_pending_txs.insert(key.0, value.0.clone());
+                    }
+                    duniter_dbs::databases::txs_mp_v2::TxsEvent::Remove { key } => {
+                        new_pending_txs.remove(&key.0);
+                    }
+                    _ => (),
+                }
+            }
+        }
+        Ok(new_pending_txs.into_iter().map(|(_k, v)| v).collect())
+    }
+    pub fn get_pending_txs(
+        &self,
+        _blockchain_time: i64,
+        min_version: usize,
+    ) -> KvResult<Vec<PendingTxDbV2>> {
+        self.dbs_pool
+            .execute(move |dbs| {
+                dbs.txs_mp_db.txs().iter(.., |it| {
+                    it.values()
+                        .filter_ok(|tx| tx.0.version() >= min_version)
+                        .collect()
+                })
+            })
+            .expect("dbs pool disconnected")
+    }
+    pub fn remove_all_pending_txs(&self) -> KvResult<()> {
+        self.dbs_pool
+            .execute(move |dbs| {
+                duniter_dbs_write_ops::txs_mp::remove_all_pending_txs(&dbs.txs_mp_db)
+            })
+            .expect("dbs pool disconnected")
+    }
+    pub fn remove_pending_tx_by_hash(&self, hash: Hash) -> KvResult<()> {
+        self.dbs_pool
+            .execute(move |dbs| {
+                duniter_dbs_write_ops::txs_mp::remove_pending_tx_by_hash(&dbs.txs_mp_db, hash)
+            })
+            .expect("dbs pool disconnected")
+    }
+    pub fn trim_expired_non_written_txs(&self, limit_time: i64) -> KvResult<()> {
+        self.dbs_pool
+            .execute(move |dbs| {
+                duniter_dbs_write_ops::txs_mp::trim_expired_non_written_txs(
+                    &dbs.txs_mp_db,
+                    limit_time,
+                )
+            })
+            .expect("dbs pool disconnected")
+    }
+}
diff --git a/rust-libs/duniter-server/src/lib.rs b/rust-libs/duniter-server/src/lib.rs
index ac936bfed..900ac5f02 100644
--- a/rust-libs/duniter-server/src/lib.rs
+++ b/rust-libs/duniter-server/src/lib.rs
@@ -22,6 +22,8 @@
     unused_import_braces
 )]
 
+mod legacy;
+
 pub use duniter_conf::DuniterConf;
 pub use duniter_dbs::{kv_typed::prelude::KvResult, smallvec, DunpHeadDbV1, DunpNodeIdV1Db};
 pub use duniter_gva::{GvaConf, GvaModule, PeerCardStringified};
@@ -69,14 +71,29 @@ pub struct DuniterServer {
 
 plug_duniter_modules!([GvaModule]);
 
+#[cfg(not(test))]
+type DuniterServerInstance = DuniterServer;
+#[cfg(test)]
+type DuniterServerInstance = (DuniterServer, DuniterDbs<FileBackend>);
+
 impl DuniterServer {
+    #[cfg(test)]
+    pub(crate) fn test(conf: DuniterConf) -> anyhow::Result<DuniterServerInstance> {
+        DuniterServer::start(
+            None,
+            conf,
+            "test".to_owned(),
+            None,
+            duniter_module::SOFTWARE_NAME,
+        )
+    }
     pub fn start(
         command_name: Option<String>,
         conf: DuniterConf,
         currency: String,
         home_path_opt: Option<&Path>,
         software_version: &'static str,
-    ) -> anyhow::Result<Self> {
+    ) -> anyhow::Result<DuniterServerInstance> {
         let command = match command_name.unwrap_or_default().as_str() {
             "sync" => DuniterCommand::Sync,
             _ => DuniterCommand::Start,
@@ -103,6 +120,11 @@ impl DuniterServer {
 
         let threadpool = if home_path_opt.is_some() {
             log::info!("start dbs threadpool...");
+
+            #[cfg(test)]
+            let threadpool =
+                fast_threadpool::ThreadPool::start(ThreadPoolConfig::default(), dbs.clone());
+            #[cfg(not(test))]
             let threadpool = fast_threadpool::ThreadPool::start(ThreadPoolConfig::default(), dbs);
 
             if command != DuniterCommand::Sync && conf.gva.is_some() {
@@ -127,271 +149,29 @@ impl DuniterServer {
             }
             threadpool
         } else {
-            fast_threadpool::ThreadPool::start(ThreadPoolConfig::low(), dbs)
+            cfg_if::cfg_if! {
+                if #[cfg(test)] {
+                    fast_threadpool::ThreadPool::start(ThreadPoolConfig::low(), dbs.clone())
+                } else {
+                    fast_threadpool::ThreadPool::start(ThreadPoolConfig::low(), dbs)
+                }
+            }
         };
 
-        Ok(DuniterServer {
+        let duniter_server = DuniterServer {
             bc_db,
             conf,
             current,
             dbs_pool: threadpool.into_sync_handler(),
             pending_txs_subscriber,
             txs_mempool,
-        })
-    }
-
-    /*
-     * READ FUNCTIONS FOR DUNITER JS ONLY
-     */
-    pub fn get_self_endpoints(&self) -> anyhow::Result<Vec<Endpoint>> {
-        if let Some(self_peer) = self
-            .dbs_pool
-            .execute(|dbs| dbs.cm_db.self_peer_old().get(&()))?
-            .context("fail to get self endpoints")?
-        {
-            Ok(self_peer.endpoints)
-        } else {
-            Ok(vec![])
-        }
-    }
-    pub fn accept_new_tx(
-        &self,
-        tx: TransactionDocumentV10,
-        server_pubkey: PublicKey,
-    ) -> KvResult<bool> {
-        let txs_mempool = self.txs_mempool;
-        match self
-            .dbs_pool
-            .execute(move |dbs| {
-                txs_mempool.accept_new_tx(&dbs.bc_db_ro, server_pubkey, tx, &dbs.txs_mp_db)
-            })
-            .expect("dbs pool discorrected")
-        {
-            Ok(()) => Ok(true),
-            Err(TxMpError::Db(e)) => Err(e),
-            Err(_) => Ok(false),
-        }
-    }
-    pub fn get_mempool_txs_free_rooms(&self) -> KvResult<usize> {
-        let txs_mempool = self.txs_mempool;
-        self.dbs_pool
-            .execute(move |dbs| txs_mempool.get_free_rooms(&dbs.txs_mp_db))
-            .expect("dbs pool discorrected")
-    }
-    pub fn get_new_pending_txs(&self) -> KvResult<Vec<TransactionDocumentV10>> {
-        let mut new_pending_txs = BTreeMap::new();
-        for events in self.pending_txs_subscriber.drain() {
-            use std::ops::Deref as _;
-            for event in events.deref() {
-                match event {
-                    duniter_dbs::databases::txs_mp_v2::TxsEvent::Upsert { key, value } => {
-                        new_pending_txs.insert(key.0, value.0.clone());
-                    }
-                    duniter_dbs::databases::txs_mp_v2::TxsEvent::Remove { key } => {
-                        new_pending_txs.remove(&key.0);
-                    }
-                    _ => (),
-                }
+        };
+        cfg_if::cfg_if! {
+            if #[cfg(test)] {
+                Ok((duniter_server, dbs))
+            } else {
+                Ok(duniter_server)
             }
         }
-        Ok(new_pending_txs.into_iter().map(|(_k, v)| v).collect())
-    }
-    pub fn get_pending_txs(
-        &self,
-        _blockchain_time: i64,
-        min_version: usize,
-    ) -> KvResult<Vec<PendingTxDbV2>> {
-        self.dbs_pool
-            .execute(move |dbs| {
-                dbs.txs_mp_db.txs().iter(.., |it| {
-                    it.values()
-                        .filter_ok(|tx| tx.0.version() >= min_version)
-                        .collect()
-                })
-            })
-            .expect("dbs pool disconnected")
-    }
-
-    pub fn get_transactions_history(&self, pubkey: PublicKey) -> KvResult<TxsHistory> {
-        self.dbs_pool
-            .execute(move |dbs| {
-                duniter_gva_dbs_reader::txs_history::get_transactions_history_for_bma(
-                    &dbs.gva_db,
-                    &dbs.txs_mp_db,
-                    pubkey,
-                )
-            })
-            .expect("dbs pool disconnected")
-    }
-
-    pub fn get_tx_by_hash(
-        &self,
-        hash: Hash,
-    ) -> KvResult<Option<(TransactionDocumentV10, Option<BlockNumber>)>> {
-        self.dbs_pool
-            .execute(move |dbs| {
-                if let Some(tx) = dbs.txs_mp_db.txs().get(&HashKeyV2(hash))? {
-                    Ok(Some((tx.0, None)))
-                } else if let Some(tx_db) = dbs.gva_db.txs().get(&HashKeyV2(hash))? {
-                    Ok(Some((tx_db.tx, Some(tx_db.written_block.number))))
-                } else {
-                    Ok(None)
-                }
-            })
-            .expect("dbs pool disconnected")
-    }
-
-    /*
-     * WRITE FUNCTION FOR DUNITER JS ONLY
-     */
-    pub fn add_pending_tx_force(&self, tx: TransactionDocumentV10) -> KvResult<()> {
-        let txs_mempool = self.txs_mempool;
-        self.dbs_pool
-            .execute(move |dbs| txs_mempool.add_pending_tx_force(&dbs.txs_mp_db, &tx))
-            .expect("dbs pool disconnected")
-    }
-    pub fn apply_block(&mut self, block: DubpBlockV10Stringified) -> KvResult<()> {
-        let block = Arc::new(
-            DubpBlockV10::from_string_object(&block)
-                .map_err(|e| KvError::DeserError(format!("{}", e)))?,
-        );
-        self.current = Some(duniter_dbs_write_ops::apply_block::apply_block(
-            &self.bc_db,
-            block.clone(),
-            self.current,
-            &self.dbs_pool,
-            false,
-        )?);
-        apply_block_modules(block, &self.conf, &self.dbs_pool, None)
-    }
-    pub fn apply_chunk_of_blocks(&mut self, blocks: Vec<DubpBlockV10Stringified>) -> KvResult<()> {
-        log::debug!("apply_chunk(#{})", blocks[0].number);
-        let blocks = Arc::from(
-            blocks
-                .into_iter()
-                .map(|block| DubpBlockV10::from_string_object(&block))
-                .collect::<Result<Vec<_>, _>>()
-                .map_err(|e| KvError::DeserError(format!("{}", e)))?,
-        );
-        self.current = Some(duniter_dbs_write_ops::apply_block::apply_chunk(
-            &self.bc_db,
-            self.current,
-            &self.dbs_pool,
-            blocks.clone(),
-        )?);
-        apply_chunk_of_blocks_modules(blocks, &self.conf, &self.dbs_pool, None)
-    }
-    pub fn receive_new_heads(
-        &self,
-        heads: Vec<(duniter_dbs::DunpNodeIdV1Db, duniter_dbs::DunpHeadDbV1)>,
-    ) -> KvResult<()> {
-        self.dbs_pool
-            .execute(move |dbs| {
-                for (dunp_node_id, dunp_head) in heads {
-                    dbs.cm_db
-                        .dunp_heads_old_write()
-                        .upsert(dunp_node_id, dunp_head)?
-                }
-                Ok::<(), KvError>(())
-            })
-            .expect("dbs pool disconnected")
-    }
-    pub fn remove_all_pending_txs(&self) -> KvResult<()> {
-        self.dbs_pool
-            .execute(move |dbs| {
-                duniter_dbs_write_ops::txs_mp::remove_all_pending_txs(&dbs.txs_mp_db)
-            })
-            .expect("dbs pool disconnected")
-    }
-    pub fn remove_pending_tx_by_hash(&self, hash: Hash) -> KvResult<()> {
-        self.dbs_pool
-            .execute(move |dbs| {
-                duniter_dbs_write_ops::txs_mp::remove_pending_tx_by_hash(&dbs.txs_mp_db, hash)
-            })
-            .expect("dbs pool disconnected")
-    }
-    pub fn revert_block(&mut self, block: DubpBlockV10Stringified) -> KvResult<()> {
-        let block = Arc::new(
-            DubpBlockV10::from_string_object(&block)
-                .map_err(|e| KvError::DeserError(format!("{}", e)))?,
-        );
-        let block_arc_clone = Arc::clone(&block);
-        let txs_mp_job_handle = self
-            .dbs_pool
-            .launch(move |dbs| {
-                duniter_dbs_write_ops::txs_mp::revert_block(
-                    block_arc_clone.transactions(),
-                    &dbs.txs_mp_db,
-                )
-            })
-            .expect("dbs pool disconnected");
-        self.current = duniter_dbs_write_ops::bc::revert_block(&self.bc_db, &block)?;
-        txs_mp_job_handle.join().expect("dbs pool disconnected")?;
-        revert_block_modules(block, &self.conf, &self.dbs_pool, None)
-    }
-    pub fn remove_all_peers(&self) -> KvResult<()> {
-        use duniter_dbs::databases::dunp_v1::DunpV1DbWritable as _;
-        self.dbs_pool
-            .execute(move |dbs| dbs.dunp_db.peers_old_write().clear())
-            .expect("dbs pool disconnected")
-    }
-    pub fn remove_peer_by_pubkey(&self, pubkey: PublicKey) -> KvResult<()> {
-        use duniter_dbs::databases::dunp_v1::DunpV1DbWritable as _;
-        self.dbs_pool
-            .execute(move |dbs| dbs.dunp_db.peers_old_write().remove(PubKeyKeyV2(pubkey)))
-            .expect("dbs pool disconnected")
-    }
-    pub fn save_peer(&self, new_peer_card: PeerCardStringified) -> anyhow::Result<()> {
-        use dubp::crypto::keys::PublicKey as _;
-        let pubkey = PublicKey::from_base58(&new_peer_card.pubkey)?;
-        use duniter_dbs::databases::dunp_v1::DunpV1DbWritable as _;
-        self.dbs_pool
-            .execute(move |dbs| {
-                dbs.dunp_db.peers_old_write().upsert(
-                    PubKeyKeyV2(pubkey),
-                    duniter_dbs::PeerCardDbV1 {
-                        version: new_peer_card.version,
-                        currency: new_peer_card.currency,
-                        pubkey: new_peer_card.pubkey,
-                        blockstamp: new_peer_card.blockstamp,
-                        endpoints: new_peer_card.endpoints,
-                        status: new_peer_card.status,
-                        signature: new_peer_card.signature,
-                    },
-                )
-            })
-            .expect("dbs pool disconnected")
-            .map_err(|e| e.into())
-    }
-    pub fn trim_expired_non_written_txs(&self, limit_time: i64) -> KvResult<()> {
-        self.dbs_pool
-            .execute(move |dbs| {
-                duniter_dbs_write_ops::txs_mp::trim_expired_non_written_txs(
-                    &dbs.txs_mp_db,
-                    limit_time,
-                )
-            })
-            .expect("dbs pool disconnected")
-    }
-    pub fn update_self_peer(&self, new_peer_card: PeerCardStringified) {
-        self.dbs_pool
-            .execute(move |dbs| {
-                dbs.cm_db
-                    .self_peer_old_write()
-                    .upsert(
-                        (),
-                        duniter_dbs::PeerCardDbV1 {
-                            version: new_peer_card.version,
-                            currency: new_peer_card.currency,
-                            pubkey: new_peer_card.pubkey,
-                            blockstamp: new_peer_card.blockstamp,
-                            endpoints: new_peer_card.endpoints,
-                            status: new_peer_card.status,
-                            signature: new_peer_card.signature,
-                        },
-                    )
-                    .expect("fail to write on memory db")
-            })
-            .expect("dbs pool disconnected")
     }
 }
diff --git a/rust-libs/modules/gva/src/lib.rs b/rust-libs/modules/gva/src/lib.rs
index 0b1cb6612..5328f9338 100644
--- a/rust-libs/modules/gva/src/lib.rs
+++ b/rust-libs/modules/gva/src/lib.rs
@@ -324,7 +324,14 @@ pub struct ServerMetaData {
 }
 
 #[derive(
-    async_graphql::SimpleObject, Clone, Debug, Default, serde::Deserialize, serde::Serialize,
+    async_graphql::SimpleObject,
+    Clone,
+    Debug,
+    Default,
+    Eq,
+    PartialEq,
+    serde::Deserialize,
+    serde::Serialize,
 )]
 #[serde(rename_all = "camelCase")]
 #[graphql(name = "PeerCard")]
diff --git a/rust-libs/modules/gva/src/queries.rs b/rust-libs/modules/gva/src/queries.rs
index 2d240cdf3..f9ffeb9e0 100644
--- a/rust-libs/modules/gva/src/queries.rs
+++ b/rust-libs/modules/gva/src/queries.rs
@@ -57,7 +57,7 @@ impl Node {
     }
     /// Software
     async fn software(&self) -> &'static str {
-        "duniter"
+        duniter_module::SOFTWARE_NAME
     }
     /// Software version
     async fn version(
-- 
GitLab


From 1e1b74473a84a0c96e1c5ff32f774fa59fd889a1 Mon Sep 17 00:00:00 2001
From: librelois <c@elo.tf>
Date: Wed, 9 Dec 2020 22:58:58 +0100
Subject: [PATCH 4/4] [feat] dex: add db dunp_v1

---
 rust-bins/duniter-dbex/src/cli.rs     |  4 +++-
 rust-bins/duniter-dbex/src/main.rs    | 33 ++++++++++++++++++---------
 rust-libs/duniter-dbs/src/lib.rs      |  1 +
 rust-libs/duniter-dbs/src/open_dbs.rs | 14 +++++++-----
 4 files changed, 34 insertions(+), 18 deletions(-)

diff --git a/rust-bins/duniter-dbex/src/cli.rs b/rust-bins/duniter-dbex/src/cli.rs
index e98ee25e2..aa8aa5420 100644
--- a/rust-bins/duniter-dbex/src/cli.rs
+++ b/rust-bins/duniter-dbex/src/cli.rs
@@ -28,7 +28,7 @@ pub struct Opt {
     pub home: Option<PathBuf>,
 
     /// database
-    #[structopt(default_value = "bc_v1", possible_values = &["bc_v1", "bc_v2", "gva_v1", "txs_mp_v2"])]
+    #[structopt(default_value = "bc_v1", possible_values = &["bc_v1", "bc_v2", "dunp_v1", "gva_v1", "txs_mp_v2"])]
     pub database: Database,
 
     #[structopt(subcommand)]
@@ -39,6 +39,7 @@ pub struct Opt {
 pub enum Database {
     BcV1,
     BcV2,
+    DunpV1,
     GvaV1,
     TxsMpV2,
 }
@@ -50,6 +51,7 @@ impl FromStr for Database {
         match s {
             "bc_v1" => Ok(Self::BcV1),
             "bc_v2" => Ok(Self::BcV2),
+            "dunp_v1" => Ok(Self::DunpV1),
             "gva_v1" => Ok(Self::GvaV1),
             "txs_mp_v2" => Ok(Self::TxsMpV2),
             _ => unreachable!(),
diff --git a/rust-bins/duniter-dbex/src/main.rs b/rust-bins/duniter-dbex/src/main.rs
index ddd314b8b..7002d803e 100644
--- a/rust-bins/duniter-dbex/src/main.rs
+++ b/rust-bins/duniter-dbex/src/main.rs
@@ -31,13 +31,13 @@ use self::cli::{Database, Opt, OutputFormat, SubCommand};
 use self::stringify_json_value::stringify_json_value;
 use anyhow::anyhow;
 use comfy_table::Table;
-use duniter_dbs::databases::bc_v2::{BcV2Db, BcV2DbWritable};
 use duniter_dbs::databases::{
     bc_v1::{BcV1Db, BcV1DbWritable},
+    bc_v2::{BcV2Db, BcV2DbWritable},
+    dunp_v1::{DunpV1Db, DunpV1DbWritable},
     gva_v1::{GvaV1Db, GvaV1DbWritable},
     txs_mp_v2::{TxsMpV2Db, TxsMpV2DbWritable},
 };
-use duniter_dbs::kv_typed::backend::sled;
 use duniter_dbs::kv_typed::prelude::*;
 use duniter_dbs::prelude::*;
 use duniter_dbs::regex::Regex;
@@ -100,23 +100,34 @@ fn main() -> anyhow::Result<()> {
                 open_db_start_time,
             ),
             Database::BcV2 => apply_subcommand(
-                BcV2Db::<Sled>::open(
-                    sled::Config::default().path(data_path.as_path().join("bc_v2_sled")),
-                )?,
+                BcV2Db::<Sled>::open(Sled::gen_backend_conf(
+                    BcV2Db::<Sled>::NAME,
+                    Some(profile_path.as_path()),
+                ))?,
+                opt.cmd,
+                open_db_start_time,
+            ),
+            Database::DunpV1 => apply_subcommand(
+                DunpV1Db::<Sled>::open(Sled::gen_backend_conf(
+                    DunpV1Db::<Sled>::NAME,
+                    Some(profile_path.as_path()),
+                ))?,
                 opt.cmd,
                 open_db_start_time,
             ),
             Database::GvaV1 => apply_subcommand(
-                GvaV1Db::<Sled>::open(
-                    sled::Config::default().path(data_path.as_path().join("gva_v1_sled")),
-                )?,
+                GvaV1Db::<Sled>::open(Sled::gen_backend_conf(
+                    GvaV1Db::<Sled>::NAME,
+                    Some(profile_path.as_path()),
+                ))?,
                 opt.cmd,
                 open_db_start_time,
             ),
             Database::TxsMpV2 => apply_subcommand(
-                TxsMpV2Db::<Sled>::open(
-                    sled::Config::default().path(data_path.as_path().join("txs_mp_v2_sled")),
-                )?,
+                TxsMpV2Db::<Sled>::open(Sled::gen_backend_conf(
+                    TxsMpV2Db::<Sled>::NAME,
+                    Some(profile_path.as_path()),
+                ))?,
                 opt.cmd,
                 open_db_start_time,
             ),
diff --git a/rust-libs/duniter-dbs/src/lib.rs b/rust-libs/duniter-dbs/src/lib.rs
index a9e2d3dd4..ade5c98f0 100644
--- a/rust-libs/duniter-dbs/src/lib.rs
+++ b/rust-libs/duniter-dbs/src/lib.rs
@@ -40,6 +40,7 @@ pub use kv_typed;
 
 // Prelude
 pub mod prelude {
+    pub use crate::open_dbs::BackendConf;
     pub use crate::DuniterDbs;
     #[cfg(feature = "explorer")]
     pub use kv_typed::explorer::{
diff --git a/rust-libs/duniter-dbs/src/open_dbs.rs b/rust-libs/duniter-dbs/src/open_dbs.rs
index 014d5aaf6..cc07815fa 100644
--- a/rust-libs/duniter-dbs/src/open_dbs.rs
+++ b/rust-libs/duniter-dbs/src/open_dbs.rs
@@ -23,25 +23,27 @@ use crate::*;
 pub fn open_dbs<B: BackendConf>(
     home_path_opt: Option<&Path>,
 ) -> (crate::databases::bc_v2::BcV2Db<B>, DuniterDbs<B>) {
-    let bc_db =
-        crate::databases::bc_v2::BcV2Db::<B>::open(B::gen_backend_conf("bc_v2", home_path_opt))
-            .expect("fail to open BcV2 DB");
+    let bc_db = crate::databases::bc_v2::BcV2Db::<B>::open(B::gen_backend_conf(
+        crate::databases::bc_v2::BcV2Db::<B>::NAME,
+        home_path_opt,
+    ))
+    .expect("fail to open BcV2 DB");
     let dbs = DuniterDbs {
         bc_db_ro: bc_db.get_ro_handler(),
         cm_db: crate::databases::cm_v1::CmV1Db::<Mem>::open(MemConf::default())
             .expect("fail to open CmV1 DB"),
         dunp_db: crate::databases::dunp_v1::DunpV1Db::<B>::open(B::gen_backend_conf(
-            "dunp_v1",
+            crate::databases::dunp_v1::DunpV1Db::<B>::NAME,
             home_path_opt,
         ))
         .expect("fail to open Dunp DB"),
         gva_db: crate::databases::gva_v1::GvaV1Db::<B>::open(B::gen_backend_conf(
-            "gva_v1",
+            crate::databases::gva_v1::GvaV1Db::<B>::NAME,
             home_path_opt,
         ))
         .expect("fail to open Gva DB"),
         txs_mp_db: crate::databases::txs_mp_v2::TxsMpV2Db::<B>::open(B::gen_backend_conf(
-            "txs_mp_v2",
+            crate::databases::txs_mp_v2::TxsMpV2Db::<B>::NAME,
             home_path_opt,
         ))
         .expect("fail to open TxsMp DB"),
-- 
GitLab