diff --git a/Cargo.lock b/Cargo.lock
index d7dd4bcdb78ba89763b3e6d2eb67a6b15238d29c..fdcb2707b948b3aff4a9c16de31eeba7c39cb7c5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -110,7 +110,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "bytes"
-version = "0.4.7"
+version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -717,12 +717,12 @@ dependencies = [
  "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.30"
+version = "0.9.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1132,7 +1132,7 @@ dependencies = [
 
 [[package]]
 name = "tokio"
-version = "0.1.6"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1142,8 +1142,8 @@ dependencies = [
  "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-threadpool 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-timer 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1152,17 +1152,17 @@ name = "tokio-core"
 version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-timer 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1180,7 +1180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-threadpool 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1188,7 +1188,7 @@ name = "tokio-io"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1211,7 +1211,7 @@ name = "tokio-tcp"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1221,7 +1221,7 @@ dependencies = [
 
 [[package]]
 name = "tokio-threadpool"
-version = "0.1.3"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1234,7 +1234,7 @@ dependencies = [
 
 [[package]]
 name = "tokio-timer"
-version = "0.2.3"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1257,7 +1257,7 @@ name = "tokio-udp"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1367,7 +1367,7 @@ dependencies = [
  "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1438,7 +1438,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
 "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
 "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
-"checksum bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1d50c876fb7545f5f289cd8b2aee3f359d073ae819eed5d6373638e2c61e59"
+"checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff"
 "checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba"
 "checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18"
 "checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6"
@@ -1488,7 +1488,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28"
 "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
 "checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985"
-"checksum openssl-sys 0.9.30 (registry+https://github.com/rust-lang/crates.io-index)" = "73ae718c3562989cd3a0a5c26610feca02f8116822f6f195e6cf4887481e57f5"
+"checksum openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)" = "d8abc04833dcedef24221a91852931df2f63e3369ae003134e70aff3645775cc"
 "checksum pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "deb73390ab68d81992bd994d145f697451bb0b54fd39738e72eef32458ad6907"
 "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
 "checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f"
@@ -1537,15 +1537,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
 "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
 "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
-"checksum tokio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d00555353b013e170ed8bc4e13f648a317d1fd12157dbcae13f7013f6cf29f5"
+"checksum tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ee337e5f4e501fc32966fec6fe0ca0cc1c237b0b1b14a335f8bfe3c5f06e286"
 "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71"
 "checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113"
 "checksum tokio-fs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76766830bbf9a2d5bfb50c95350d56a2e79e2c80f675967fff448bc615899708"
 "checksum tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af9eb326f64b2d6b68438e1953341e00ab3cf54de7e35d92bfc73af8555313a"
 "checksum tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3cedc8e5af5131dc3423ffa4f877cce78ad25259a9a62de0613735a13ebc64b"
 "checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f"
-"checksum tokio-threadpool 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5783254b10c7c84a56f62c74766ef7e5b83d1f13053218c7cab8d3f2c826fa0e"
-"checksum tokio-timer 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535fed0ccee189f3d48447587697ba3fd234b3dbbb091f0ec4613ddfec0a7c4c"
+"checksum tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c3873a6d8d0b636e024e77b9a82eaab6739578a06189ecd0e731c7308fbc5d"
+"checksum tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "028b94314065b90f026a21826cffd62a4e40a92cda3e5c069cc7b02e5945f5e9"
 "checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913"
 "checksum tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "137bda266504893ac4774e0ec4c2108f7ccdbcb7ac8dced6305fe9e4e0b5041a"
 "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
diff --git a/Cargo.toml b/Cargo.toml
index 7d75866bbfb4f61d01bba1f07212141590110912..d718f4841291111a7ce8bbedf80889222c7c0a59 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,12 +8,15 @@ license = "AGPL-3.0"
 [dependencies]
 duniter-core = { path = "./core" }
 duniter-tui = { path = "./tui" }
-duniter-ws2p = { path = "./ws2p" }
+duniter-ws2p = { path = "./ws2p", optional = true }
 
 [features]
+default = ["ws2p"]
+ws2p = ["duniter-ws2p"]
 # Treat warnings as a build error.
 strict = []
 
+
 [workspace]
 members = [
     "blockchain",
@@ -27,5 +30,5 @@ members = [
     "network",
     "tui",
     "wotb",
-    "ws2p",
+    "ws2p"
 ]
diff --git a/blockchain/apply_valid_block.rs b/blockchain/apply_valid_block.rs
index 26b31cbcde6fb39f54f73a7a701dbc3926443d23..c395d2fcf598f12fbfefc1782dcf6b896ffb23cd 100644
--- a/blockchain/apply_valid_block.rs
+++ b/blockchain/apply_valid_block.rs
@@ -147,6 +147,7 @@ pub fn apply_valid_block<W: WebOfTrust, B: Backend + Debug>(
         wot_dbs_requests.push(WotsDBsWriteQuery::RevokeIdentity(
             compact_revoc.issuer,
             block.blockstamp(),
+            true,
         ));
     }
     for certification in block.certifications.clone() {
diff --git a/blockchain/check_and_apply_block.rs b/blockchain/check_and_apply_block.rs
index 21f4e567fa561a9850164e43b389645e1d5a8580..2981adefdd099d1a85ca3f6e4c961a17a5310a89 100644
--- a/blockchain/check_and_apply_block.rs
+++ b/blockchain/check_and_apply_block.rs
@@ -156,6 +156,7 @@ pub fn check_and_apply_block<W: WebOfTrust, B: Backend + Debug>(
                         &dal_block,
                         None,
                         false,
+                        false,
                     ).expect("duniter_dal::writers::block::write() : DALError")
                 }
                 Block::LocalBlock(block_doc) => {
@@ -173,6 +174,7 @@ pub fn check_and_apply_block<W: WebOfTrust, B: Backend + Debug>(
                         &dal_block,
                         old_fork_id,
                         false,
+                        false,
                     ).expect("duniter_dal::writers::block::write() : DALError")
                 }
             };
diff --git a/blockchain/clippy.toml b/blockchain/clippy.toml
index 1c6d687e2556b27948a8036e154546fcebec87eb..16934920c7fa627dc091b94ed08687bea1afe437 100644
--- a/blockchain/clippy.toml
+++ b/blockchain/clippy.toml
@@ -1 +1 @@
-cyclomatic-complexity-threshold = 37
\ No newline at end of file
+cyclomatic-complexity-threshold = 38
\ No newline at end of file
diff --git a/blockchain/dbex.rs b/blockchain/dbex.rs
index 9999f311c2c37e3c1ff977632b21dfc898f140c2..6da2fa3096de5961b992ee7b513c6f573610698d 100644
--- a/blockchain/dbex.rs
+++ b/blockchain/dbex.rs
@@ -18,12 +18,19 @@ use duniter_dal::identity::DALIdentity;
 use duniter_documents::blockchain::v10::documents::transaction::*;
 use duniter_module::DuniterConf;
 use duniter_wotb::data::rusty::RustyWebOfTrust;
+use duniter_wotb::operations::distance::{DistanceCalculator, WotDistance, WotDistanceParameters};
 use std::time::*;
 use *;
 
 #[derive(Debug, Clone)]
 /// Query for wot databases explorer
 pub enum DBExWotQuery {
+    /// Ask distance of all members
+    AllDistances(bool),
+    /// Show members expire date
+    ExpireMembers(bool, bool),
+    /// Show members list
+    ListMembers(bool),
     /// Ask member datas
     MemberDatas(String),
 }
@@ -69,7 +76,6 @@ pub fn dbex_tx(conf: &DuniterConf, query: &DBExTxQuery) {
         load_dbs_duration.subsec_nanos() / 1_000_000
     );
     let req_process_begin = SystemTime::now();
-
     match *query {
         DBExTxQuery::Balance(ref address_str) => {
             let pubkey = if let Ok(ed25519_pubkey) = ed25519::PublicKey::from_base58(address_str) {
@@ -115,7 +121,8 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) {
 
     // Open databases
     let load_dbs_begin = SystemTime::now();
-    //let blocks_databases = BlocksV10DBs::open(&db_path, false);
+    let currency_params_db =
+        open_db::<CurrencyParamsV10Datas>(&db_path, "params.db").expect("Fail to open params db");
     let wot_databases = WotsV10DBs::open(&db_path, false);
     let load_dbs_duration = SystemTime::now()
         .duration_since(load_dbs_begin)
@@ -125,7 +132,11 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) {
         load_dbs_duration.as_secs(),
         load_dbs_duration.subsec_nanos() / 1_000_000
     );
-    let req_process_begin = SystemTime::now();
+
+    // Get currency parameters
+    let currency_params = currency_params_db
+        .read(|db| CurrencyParameters::from(db.clone()))
+        .expect("Fail to parse currency params !");
 
     // get wot_index
     let wot_index = DALIdentity::get_wotb_index(&wot_databases.identities_db).expect("DALError");
@@ -134,21 +145,126 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) {
     let wot_reverse_index: HashMap<NodeId, &PubKey> =
         wot_index.iter().map(|(p, id)| (*id, p)).collect();
 
+    // get wot uid index
+    let wot_uid_index: HashMap<NodeId, String> = wot_databases
+        .identities_db
+        .read(|db| {
+            db.iter()
+                .map(|(_, idty)| (idty.wot_id, String::from(idty.idty_doc.username())))
+                .collect()
+        })
+        .expect("Fail to read IdentitiesDB !");
+
     // Open wot db
     let wot_db = open_wot_db::<RustyWebOfTrust>(&db_path).expect("Fail to open WotDB !");
 
     // Print wot blockstamp
     //println!("Wot : Current blockstamp = {}.", wot_blockstamp);
 
-    // Print members count
+    // Get members count
     let members_count = wot_db
         .read(|db| db.get_enabled())
         .expect("Fail to read WotDB")
         .len();
-    println!(" Members count = {}.", members_count);
 
     match *query {
+        DBExWotQuery::AllDistances(ref reverse) => {
+            println!("compute distances...");
+            let compute_distances_begin = SystemTime::now();
+            let mut distances_datas: Vec<(NodeId, WotDistance)> = wot_db
+                .read(|db| {
+                    db.get_enabled()
+                        .iter()
+                        .map(|wot_id| {
+                            (
+                                *wot_id,
+                                DISTANCE_CALCULATOR
+                                    .compute_distance(
+                                        db,
+                                        WotDistanceParameters {
+                                            node: *wot_id,
+                                            sentry_requirement: 5,
+                                            step_max: currency_params.step_max as u32,
+                                            x_percent: currency_params.x_percent,
+                                        },
+                                    )
+                                    .expect("Fail to get distance !"),
+                            )
+                        })
+                        .collect()
+                })
+                .expect("Fail to read WotDB");
+            let compute_distances_duration = SystemTime::now()
+                .duration_since(compute_distances_begin)
+                .expect("duration_since error");
+            if *reverse {
+                distances_datas.sort_unstable_by(|(_, d1), (_, d2)| d1.success.cmp(&d2.success));
+            } else {
+                distances_datas.sort_unstable_by(|(_, d1), (_, d2)| d2.success.cmp(&d1.success));
+            }
+            for (wot_id, distance_datas) in distances_datas {
+                let distance_percent: f64 =
+                    f64::from(distance_datas.success) / f64::from(distance_datas.sentries) * 100.0;
+                println!(
+                    "{} -> distance: {:.2}% ({}/{})",
+                    wot_uid_index[&wot_id],
+                    distance_percent,
+                    distance_datas.success,
+                    distance_datas.sentries
+                );
+            }
+            println!(
+                "compute_distances_duration = {},{:03}.",
+                compute_distances_duration.as_secs(),
+                compute_distances_duration.subsec_nanos() / 1_000_000
+            );
+        }
+        DBExWotQuery::ExpireMembers(ref reverse, ref _csv) => {
+            // Open blockchain database
+            let blockchain_db = open_db::<LocalBlockchainV10Datas>(&db_path, "blockchain.db")
+                .expect("Fail to open blockchain db");
+            // Get blocks_times
+            let (current_bc_time, blocks_times): (u64, HashMap<BlockId, u64>) = blockchain_db
+                .read(|db| {
+                    (
+                        db[&BlockId(db.len() as u32 - 1)].block.median_time,
+                        db.iter()
+                            .map(|(block_id, dal_block)| (*block_id, dal_block.block.median_time))
+                            .collect(),
+                    )
+                })
+                .expect("Fail to read blockchain db");
+            // Get expire_dates
+            let min_created_ms_time = current_bc_time - currency_params.ms_validity;
+            let mut expire_dates: Vec<(NodeId, u64)> = wot_databases
+                .ms_db
+                .read(|db| {
+                    let mut expire_dates = Vec::new();
+                    for (block_id, nodes_ids) in db {
+                        let created_ms_time = blocks_times[&block_id];
+                        if created_ms_time > min_created_ms_time {
+                            for node_id in nodes_ids {
+                                expire_dates.push((
+                                    *node_id,
+                                    created_ms_time + currency_params.ms_validity,
+                                ));
+                            }
+                        }
+                    }
+                    expire_dates
+                })
+                .expect("Fail to read ms db");
+            if *reverse {
+                expire_dates.sort_unstable_by(|(_, d1), (_, d2)| d1.cmp(&d2));
+            } else {
+                expire_dates.sort_unstable_by(|(_, d1), (_, d2)| d2.cmp(&d1));
+            }
+            for (node_id, expire_date) in expire_dates {
+                println!("{}, {}", wot_uid_index[&node_id], expire_date);
+            }
+        }
         DBExWotQuery::MemberDatas(ref uid) => {
+            println!(" Members count = {}.", members_count);
             if let Some(pubkey) =
                 duniter_dal::identity::get_pubkey_from_uid(&wot_databases.identities_db, uid)
                     .expect("get_pubkey_from_uid() : DALError !")
@@ -160,6 +276,26 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) {
                     wot_id.0,
                     pubkey.to_string()
                 );
+                let distance_datas = wot_db
+                    .read(|db| {
+                        DISTANCE_CALCULATOR.compute_distance(
+                            db,
+                            WotDistanceParameters {
+                                node: wot_id,
+                                sentry_requirement: 5,
+                                step_max: currency_params.step_max as u32,
+                                x_percent: currency_params.x_percent,
+                            },
+                        )
+                    })
+                    .expect("Fail to read WotDB")
+                    .expect("Fail to get distance !");
+                let distance_percent: f64 =
+                    f64::from(distance_datas.success) / f64::from(distance_datas.sentries) * 100.0;
+                println!(
+                    "Distance {:.2}% ({}/{})",
+                    distance_percent, distance_datas.success, distance_datas.sentries
+                );
                 let sources = wot_db
                     .read(|db| db.get_links_source(wot_id))
                     .expect("Fail to read WotDB")
@@ -177,13 +313,6 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) {
                 println!("Uid \"{}\" not found !", uid);
             }
         }
+        _ => {}
     }
-    let req_process_duration = SystemTime::now()
-        .duration_since(req_process_begin)
-        .expect("duration_since error");
-    println!(
-        "Request processed in  {}.{:06} seconds.",
-        req_process_duration.as_secs(),
-        req_process_duration.subsec_nanos() / 1_000
-    );
 }
diff --git a/blockchain/lib.rs b/blockchain/lib.rs
index c7ef4ec4c8d4d2712d77faeea781c64d5e6ba0d1..7fbd4fbab84237134e5908a68efb3cdc21a9412a 100644
--- a/blockchain/lib.rs
+++ b/blockchain/lib.rs
@@ -42,6 +42,7 @@ extern crate sqlite;
 mod apply_valid_block;
 mod check_and_apply_block;
 mod dbex;
+mod revert_block;
 mod sync;
 mod ts_parsers;
 
@@ -74,6 +75,7 @@ use duniter_network::{
     NetworkBlock, NetworkDocument, NetworkEvent, NetworkRequest, NetworkResponse, NodeFullId,
 };
 use duniter_wotb::data::rusty::RustyWebOfTrust;
+use duniter_wotb::operations::distance::RustyDistanceCalculator;
 use duniter_wotb::{NodeId, WebOfTrust};
 use rustbreak::backend::{Backend, FileBackend};
 
@@ -83,6 +85,8 @@ pub static CHUNK_SIZE: &'static u32 = &50;
 pub static INFINITE_SIG_STOCK: &'static usize = &4_000_000_000;
 /// The blocks are requested by packet groups. This constant sets the number of packets per group.
 pub static MAX_BLOCKS_REQUEST: &'static u32 = &500;
+/// The distance calculator
+pub static DISTANCE_CALCULATOR: &'static RustyDistanceCalculator = &RustyDistanceCalculator {};
 
 /// Blockchain Module
 #[derive(Debug)]
@@ -193,17 +197,6 @@ impl BlockchainModule {
     }
     /// Synchronize blockchain from a duniter-ts database
     pub fn sync_ts(conf: &DuniterConf, ts_profile: &str, cautious: bool) {
-        // get databases path
-        let db_path = duniter_conf::get_blockchain_db_path(&conf.profile(), &conf.currency());
-        // Open blocks dbs
-        let blocks_dbs = BlocksV10DBs::open(&db_path, false);
-        // Get local current blockstamp
-        debug!("Get local current blockstamp...");
-        let current_blockstamp: Blockstamp = duniter_dal::block::get_current_blockstamp(
-            &blocks_dbs,
-        ).expect("ForksV10DB : RustBreakError !")
-            .unwrap_or_default();
-        debug!("Success to get local current blockstamp.");
         // get db_ts_path
         let mut db_ts_path = match env::home_dir() {
             Some(path) => path,
@@ -215,7 +208,7 @@ impl BlockchainModule {
         if !db_ts_path.as_path().exists() {
             panic!("Fatal error : duniter-ts database don't exist !");
         }
-        sync::sync_ts(conf, &current_blockstamp, db_ts_path, cautious);
+        sync::sync_ts(conf, db_ts_path, cautious);
     }
     /// Request chunk from network (chunk = group of blocks)
     fn request_chunk(&self, req_id: &ModuleReqId, from: u32) -> (ModuleReqId, NetworkRequest) {
@@ -651,6 +644,26 @@ impl BlockchainModule {
                                         {
                                             if let Ok(blockstamp) = response {
                                                 consensus = blockstamp;
+                                                if current_blockstamp.id.0 > consensus.id.0 + 2 {
+                                                    // Find free fork id
+                                                    let free_fork_id = ForkId(49);
+                                                    // Get last dal_block
+                                                    let last_dal_block_id =
+                                                        BlockId(current_blockstamp.id.0 - 1);
+                                                    let last_dal_block = self
+                                                        .blocks_databases
+                                                        .blockchain_db
+                                                        .read(|db| db.get(&last_dal_block_id).cloned())
+                                                        .expect("Fail to read blockchain DB.")
+                                                        .expect("Fatal error : not foutn last dal block !");
+                                                    revert_block::revert_block(
+                                                        &last_dal_block,
+                                                        &mut wotb_index,
+                                                        &wot_db,
+                                                        Some(free_fork_id),
+                                                        &self.currency_databases.tx_db.read(|db| db.clone()).expect("Fail to read TxDB.")
+                                                    ).expect("Fail to revert block");
+                                                }
                                             }
                                         }
                                     }
diff --git a/blockchain/revert_block.rs b/blockchain/revert_block.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a349ba7fad4b0252500f72c045dc18b39e0ec1d4
--- /dev/null
+++ b/blockchain/revert_block.rs
@@ -0,0 +1,230 @@
+//  Copyright (C) 2018  The Duniter Project Developers.
+//
+// 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 duniter_crypto::keys::*;
+use duniter_dal::block::DALBlock;
+use duniter_dal::sources::SourceAmount;
+use duniter_dal::writers::requests::*;
+use duniter_dal::writers::transaction::DALTxV10;
+use duniter_dal::{BinDB, ForkId, TxV10Datas};
+use duniter_documents::blockchain::v10::documents::block::TxDocOrTxHash;
+use duniter_documents::blockchain::v10::documents::transaction::{TxAmount, TxBase};
+use duniter_documents::blockchain::Document;
+use duniter_wotb::data::NewLinkResult;
+use duniter_wotb::{NodeId, WebOfTrust};
+use rustbreak::backend::Backend;
+use std::collections::HashMap;
+use std::fmt::Debug;
+
+#[derive(Debug)]
+/// Stores all queries to apply in database to "apply" the block
+pub struct ValidBlockRevertReqs(
+    pub BlocksDBsWriteQuery,
+    pub Vec<WotsDBsWriteQuery>,
+    pub Vec<CurrencyDBsWriteQuery>,
+);
+
+#[derive(Debug, Copy, Clone)]
+/// RevertValidBlockError
+pub enum RevertValidBlockError {
+    ExcludeUnknowNodeId(),
+    RevokeUnknowNodeId(),
+}
+
+pub fn revert_block<W: WebOfTrust, B: Backend + Debug>(
+    dal_block: &DALBlock,
+    wot_index: &mut HashMap<PubKey, NodeId>,
+    wot_db: &BinDB<W, B>,
+    to_fork_id: Option<ForkId>,
+    txs: &TxV10Datas,
+) -> Result<ValidBlockRevertReqs, RevertValidBlockError> {
+    // Revert DALBlock
+    let mut block = dal_block.block.clone();
+    let expire_certs = dal_block
+        .expire_certs
+        .clone()
+        .expect("Try to get expire_certs of an uncompleted block !");
+
+    // Get transactions
+    let dal_txs: Vec<DALTxV10> = block
+        .transactions
+        .iter()
+        .map(|tx_enum| match *tx_enum {
+            TxDocOrTxHash::TxHash(ref tx_hash) => txs[tx_hash].clone(),
+            TxDocOrTxHash::TxDoc(ref _dal_tx) => panic!("Try to revert not reduce block !"),
+        })
+        .collect();
+
+    // Revert reduce block
+    block.compute_inner_hash();
+    debug!(
+        "BlockchainModule : revert_valid_block({})",
+        block.blockstamp()
+    );
+
+    // REVERT_CURRENCY_EVENTS
+    let mut currency_dbs_requests = Vec::new();
+    // Revert transactions
+    for dal_tx in dal_txs.iter().rev() {
+        currency_dbs_requests.push(CurrencyDBsWriteQuery::RevertTx(Box::new(dal_tx.clone())));
+    }
+    // Revert DU
+    if let Some(du_amount) = block.dividend {
+        if du_amount > 0 {
+            let members_wot_ids = wot_db
+                .read(|db| db.get_enabled())
+                .expect("Fail to read WotDB");
+            let mut members_pubkeys = Vec::new();
+            for (pubkey, wotb_id) in wot_index.iter() {
+                if members_wot_ids.contains(wotb_id) {
+                    members_pubkeys.push(*pubkey);
+                }
+            }
+            currency_dbs_requests.push(CurrencyDBsWriteQuery::RevertDU(
+                SourceAmount(TxAmount(du_amount as isize), TxBase(block.unit_base)),
+                block.number,
+                members_pubkeys,
+            ));
+        }
+    }
+    // REVERT WOT EVENTS
+    let mut wot_dbs_requests = Vec::new();
+    // Revert expire_certs
+    for ((source, target), created_block_id) in expire_certs {
+        wot_dbs_requests.push(WotsDBsWriteQuery::RevertExpireCert(
+            source,
+            target,
+            created_block_id,
+        ));
+    }
+    // Revert certifications
+    for certification in block.certifications.clone() {
+        trace!("stack_up_valid_block: apply cert...");
+        let compact_cert = certification.to_compact_document();
+        let wotb_node_from = wot_index[&compact_cert.issuer];
+        let wotb_node_to = wot_index[&compact_cert.target];
+        wot_db
+            .write(|db| {
+                let result = db.add_link(wotb_node_from, wotb_node_to);
+                match result {
+                    NewLinkResult::Ok(_) => {}
+                    _ => panic!(
+                        "Fail to add_link {}->{} : {:?}",
+                        wotb_node_from.0, wotb_node_to.0, result
+                    ),
+                }
+            })
+            .expect("Fail to read WotDB");
+        wot_dbs_requests.push(WotsDBsWriteQuery::RevertCert(
+            compact_cert,
+            wotb_node_from,
+            wotb_node_to,
+        ));
+        trace!("stack_up_valid_block: apply cert...success.");
+    }
+    // Revert revocations
+    for revocation in block.revoked.clone() {
+        let compact_revoc = revocation.to_compact_document();
+        let wot_id = if let Some(wot_id) = wot_index.get(&compact_revoc.issuer) {
+            wot_id
+        } else {
+            return Err(RevertValidBlockError::RevokeUnknowNodeId());
+        };
+        wot_db
+            .write(|db| {
+                db.set_enabled(*wot_id, false);
+            })
+            .expect("Fail to write in WotDB");
+        wot_dbs_requests.push(WotsDBsWriteQuery::RevertRevokeIdentity(
+            compact_revoc.issuer,
+            block.blockstamp(),
+            true,
+        ));
+    }
+    // Revert exclusions
+    for exclusion in block.excluded.clone() {
+        let wot_id = if let Some(wot_id) = wot_index.get(&exclusion) {
+            wot_id
+        } else {
+            return Err(RevertValidBlockError::ExcludeUnknowNodeId());
+        };
+        wot_db
+            .write(|db| {
+                db.set_enabled(*wot_id, false);
+            })
+            .expect("Fail to write in WotDB");
+        wot_dbs_requests.push(WotsDBsWriteQuery::RevertExcludeIdentity(
+            exclusion,
+            block.blockstamp(),
+        ));
+    }
+    // List block identities
+    let mut identities = HashMap::with_capacity(block.identities.len());
+    for identity in block.identities.clone() {
+        identities.insert(identity.issuers()[0], identity);
+    }
+    // Revert renewals
+    for active in block.actives.clone() {
+        let pubkey = active.issuers()[0];
+        if !identities.contains_key(&pubkey) {
+            let wotb_id = wot_index[&pubkey];
+            wot_db
+                .write(|db| {
+                    db.set_enabled(wotb_id, true);
+                })
+                .expect("Fail to write in WotDB");
+            wot_dbs_requests.push(WotsDBsWriteQuery::RevertRenewalIdentity(
+                pubkey,
+                wotb_id,
+                block.median_time,
+                active.blockstamp().id,
+            ));
+        }
+    }
+    // Revert joiners
+    for joiner in block.joiners.iter().rev() {
+        let pubkey = joiner.clone().issuers()[0];
+        if let Some(_idty_doc) = identities.get(&pubkey) {
+            // Newcomer
+            wot_db
+                .write(|db| {
+                    db.rem_node();
+                })
+                .expect("Fail to write in WotDB");
+            wot_index.remove(&pubkey);
+            wot_dbs_requests.push(WotsDBsWriteQuery::RevertCreateIdentity(pubkey));
+        } else {
+            // Renewer
+            let wotb_id = wot_index[&joiner.issuers()[0]];
+            wot_db
+                .write(|db| {
+                    db.set_enabled(wotb_id, true);
+                })
+                .expect("Fail to write in WotDB");
+            wot_dbs_requests.push(WotsDBsWriteQuery::RevertRenewalIdentity(
+                joiner.issuers()[0],
+                wotb_id,
+                block.median_time,
+                joiner.blockstamp().id,
+            ));
+        }
+    }
+    // Return DBs requests
+    Ok(ValidBlockRevertReqs(
+        BlocksDBsWriteQuery::RevertBlock(Box::new(dal_block.clone()), to_fork_id),
+        wot_dbs_requests,
+        currency_dbs_requests,
+    ))
+}
diff --git a/blockchain/sync.rs b/blockchain/sync.rs
index 2f5c2f0f8a18371fb6396bb3575bb425a4f3c6f6..6636be2a604fcfd55bc907bd2b880aab40b75c44 100644
--- a/blockchain/sync.rs
+++ b/blockchain/sync.rs
@@ -67,23 +67,27 @@ enum SyncJobsMess {
 }
 
 /// Sync from a duniter-ts database
-pub fn sync_ts(
-    conf: &DuniterConf,
-    current_blockstamp: &Blockstamp,
-    db_ts_path: PathBuf,
-    cautious: bool,
-) {
+pub fn sync_ts(conf: &DuniterConf, db_ts_path: PathBuf, cautious: bool) {
     // get profile and currency and current_blockstamp
     let profile = &conf.profile();
     let currency = &conf.currency();
-    let mut current_blockstamp = *current_blockstamp;
 
-    // Get wot path
+    // Get databases path
     let db_path = duniter_conf::get_blockchain_db_path(&profile, &currency);
 
     // Open wot db
     let wot_db = open_wot_db::<RustyWebOfTrust>(&db_path).expect("Fail to open WotDB !");
 
+    // Open blocks databases
+    let databases = BlocksV10DBs::open(&db_path, false);
+
+    // Get local current blockstamp
+    debug!("Get local current blockstamp...");
+    let mut current_blockstamp: Blockstamp = duniter_dal::block::get_current_blockstamp(&databases)
+        .expect("ForksV10DB : RustBreakError !")
+        .unwrap_or_default();
+    debug!("Success to get local current blockstamp.");
+
     // Get verification level
     let _verif_level = if cautious {
         println!("Start cautious sync...");
@@ -275,14 +279,9 @@ pub fn sync_ts(
     let (sender_wot_thread, recv_wot_thread) = mpsc::channel();
 
     // Launch blocks_worker thread
-    let profile_copy = conf.profile().clone();
-    let currency_copy = conf.currency().clone();
     let sender_sync_thread_clone = sender_sync_thread.clone();
     pool.execute(move || {
         let blocks_job_begin = SystemTime::now();
-        // Open databases
-        let db_path = duniter_conf::get_blockchain_db_path(&profile_copy, &currency_copy);
-        let databases = BlocksV10DBs::open(&db_path, false);
 
         // Listen db requets
         let mut chunk_index = 0;
@@ -441,6 +440,11 @@ pub fn sync_ts(
     });
     let main_job_begin = SystemTime::now();
 
+    // Open currency_params_db
+    let dbs_path = duniter_conf::get_blockchain_db_path(&conf.profile(), &conf.currency());
+    let currency_params_db =
+        open_db::<CurrencyParamsV10Datas>(&dbs_path, "params.db").expect("Fail to open params db");
+
     // Apply blocks
     let mut blocks_not_expiring = VecDeque::with_capacity(200_000);
     let mut last_block_expiring: isize = -1;
@@ -464,19 +468,21 @@ pub fn sync_ts(
             .duration_since(complete_block_begin)
             .unwrap();
         // Get currency params
-        if !get_currency_params {
-            if block_doc.number.0 == 0 {
-                if block_doc.parameters.is_some() {
-                    currency_params = CurrencyParameters::from((
-                        block_doc.currency.clone(),
-                        block_doc.parameters.unwrap(),
-                    ));
-                    get_currency_params = true;
-                } else {
-                    panic!("The genesis block are None parameters !");
-                }
+        if !get_currency_params && block_doc.number.0 == 0 {
+            if block_doc.parameters.is_some() {
+                currency_params_db
+                    .write(|db| {
+                        db.0 = block_doc.currency.clone();
+                        db.1 = block_doc.parameters.unwrap();
+                    })
+                    .expect("fail to write in params DB");
+                currency_params = CurrencyParameters::from((
+                    block_doc.currency.clone(),
+                    block_doc.parameters.unwrap(),
+                ));
+                get_currency_params = true;
             } else {
-                panic!("The first block is not genesis !");
+                panic!("The genesis block are None parameters !");
             }
         }
         // Push block median_time in blocks_not_expiring
@@ -582,6 +588,9 @@ pub fn sync_ts(
         .expect("Sync : Fail to send End signal to writer worker !");
     info!("Sync : send End signal to tx job.");
 
+    // Save params db
+    currency_params_db.save().expect("Fail to save params db");
+
     // Save wot file
     wot_db.save().expect("Fail to save wotb db");
 
diff --git a/core/cli/en.yml b/core/cli/en.yml
index ff97559fd4978303483a432af5d5b24a63795822..f295780739b4181d8856aa3825f0d7a4d27f1478 100644
--- a/core/cli/en.yml
+++ b/core/cli/en.yml
@@ -43,9 +43,23 @@ subcommands:
         about: durs databases explorer
         version: "0.1.0"
         author: Elois L. <elois@duniter.org>
+        args:
+            - csv:
+                short: c
+                long: csv
+                help: csv output
         subcommands:
+            - distances:
+                about: durs databases explorer (distances datas)
+                version: "0.1.0"
+                author: Elois L. <elois@duniter.org>
+                args:
+                    - reverse:
+                        short: r
+                        long: reverse
+                        help: reverse order
             - member:
-                about: durs databases explorer (wot members datas)
+                about: durs databases explorer (wot member datas)
                 version: "0.1.0"
                 author: Elois L. <elois@duniter.org>
                 args:
@@ -53,6 +67,19 @@ subcommands:
                         help : choose member uid
                         index: 1
                         required: true
+            - members:
+                about: durs databases explorer (wot members datas)
+                version: "0.1.0"
+                author: Elois L. <elois@duniter.org>
+                args:
+                    - expire:
+                        short: e
+                        long: expire
+                        help: show members expire date
+                    - reverse:
+                        short: r
+                        long: reverse
+                        help: reverse order
             - balance:
                 about: durs databases explorer (balances datas)
                 version: "0.1.0"
diff --git a/core/lib.rs b/core/lib.rs
index 773a77f785b5e4a11870c7254188f384cdbb7b53..574bd7811818aeddfae0d2530a685a2865648fa0 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -125,12 +125,37 @@ impl DuniterCore {
             sync_ts(&conf, ts_profile, matches.is_present("cautious"));
             None
         } else if let Some(matches) = cli_args.subcommand_matches("dbex") {
-            if let Some(member_matches) = matches.subcommand_matches("member") {
+            let csv = matches.is_present("csv");
+            if let Some(distances_matches) = matches.subcommand_matches("distances") {
+                dbex(
+                    &conf,
+                    &DBExQuery::WotQuery(DBExWotQuery::AllDistances(
+                        distances_matches.is_present("reverse"),
+                    )),
+                );
+            } else if let Some(member_matches) = matches.subcommand_matches("member") {
                 let uid = member_matches.value_of("UID").unwrap_or("");
                 dbex(
                     &conf,
                     &DBExQuery::WotQuery(DBExWotQuery::MemberDatas(String::from(uid))),
                 );
+            } else if let Some(members_matches) = matches.subcommand_matches("members") {
+                if members_matches.is_present("expire") {
+                    dbex(
+                        &conf,
+                        &DBExQuery::WotQuery(DBExWotQuery::ExpireMembers(
+                            members_matches.is_present("reverse"),
+                            csv,
+                        )),
+                    );
+                } else {
+                    dbex(
+                        &conf,
+                        &DBExQuery::WotQuery(DBExWotQuery::ListMembers(
+                            members_matches.is_present("reverse"),
+                        )),
+                    );
+                }
             } else if let Some(balance_matches) = matches.subcommand_matches("balance") {
                 let address = balance_matches.value_of("ADDRESS").unwrap_or("");
                 dbex(
diff --git a/dal/identity.rs b/dal/identity.rs
index 38ee0955b4e0a2dc379c3749bcc7565684d69b51..ee35e4c3bec9660eb847b7e024ed4b81fd922006 100644
--- a/dal/identity.rs
+++ b/dal/identity.rs
@@ -25,7 +25,8 @@ pub struct DALIdentity {
     pub expired_on: Option<Blockstamp>,
     pub revoked_on: Option<Blockstamp>,
     pub idty_doc: IdentityDocument,
-    pub wotb_id: NodeId,
+    pub wot_id: NodeId,
+    pub ms_created_block_id: BlockId,
     pub ms_chainable_on: Vec<u64>,
     pub cert_chainable_on: Vec<u64>,
 }
@@ -100,35 +101,13 @@ impl DALIdentity {
         Ok(identities_db.read(|db| {
             let mut wotb_index: HashMap<PubKey, NodeId> = HashMap::new();
             for (pubkey, member_datas) in db {
-                let wotb_id = member_datas.wotb_id;
+                let wotb_id = member_datas.wot_id;
                 wotb_index.insert(*pubkey, wotb_id);
             }
             wotb_index
         })?)
     }
 
-    pub fn create_identity(
-        currency_params: &CurrencyParameters,
-        idty_doc: &IdentityDocument,
-        wotb_id: NodeId,
-        current_blockstamp: Blockstamp,
-        current_bc_time: u64,
-    ) -> DALIdentity {
-        let mut idty_doc = idty_doc.clone();
-        idty_doc.reduce();
-        DALIdentity {
-            hash: "0".to_string(),
-            state: DALIdentityState::Member(vec![0]),
-            joined_on: current_blockstamp,
-            expired_on: None,
-            revoked_on: None,
-            idty_doc,
-            wotb_id,
-            ms_chainable_on: vec![current_bc_time + currency_params.ms_period],
-            cert_chainable_on: vec![],
-        }
-    }
-
     pub fn revoke_identity<B: Backend + Debug>(
         identities_db: &BinDB<IdentitiesV10Datas, B>,
         pubkey: &PubKey,
diff --git a/dal/lib.rs b/dal/lib.rs
index 3704a8db7c901b3f0b6005af0028c109bb637003..d6e4196a56aca24151cecd0ee9e8775a4fa2c8d9 100644
--- a/dal/lib.rs
+++ b/dal/lib.rs
@@ -50,6 +50,7 @@ pub mod tools;
 pub mod writers;
 
 use duniter_crypto::keys::*;
+use duniter_documents::blockchain::v10::documents::block::{BlockV10Parameters, CurrencyName};
 use duniter_documents::blockchain::v10::documents::transaction::*;
 use duniter_documents::{BlockHash, BlockId, Blockstamp, Hash, PreviousBlockstamp};
 use duniter_wotb::{NodeId, WebOfTrust};
@@ -73,6 +74,7 @@ use writers::transaction::DALTxV10;
 /// Each fork has a unique identifier. The local blockchain (also called local branch) has ForkId equal to zero.
 pub struct ForkId(pub usize);
 
+pub type CurrencyParamsV10Datas = (CurrencyName, BlockV10Parameters);
 pub type LocalBlockchainV10Datas = HashMap<BlockId, DALBlock>;
 pub type ForksV10Datas = HashMap<ForkId, HashMap<PreviousBlockstamp, BlockHash>>;
 pub type ForksBlocksV10Datas = HashMap<Blockstamp, DALBlock>;
diff --git a/dal/sources.rs b/dal/sources.rs
index dcb27bbafdee5b75b10f3f60df846b91487e085b..bfe6c54b6dfbf98512f5cd285756af5c0c19d94d 100644
--- a/dal/sources.rs
+++ b/dal/sources.rs
@@ -19,9 +19,10 @@ extern crate duniter_documents;
 use duniter_crypto::keys::PubKey;
 use duniter_documents::blockchain::v10::documents::transaction::*;
 use duniter_documents::{BlockId, Hash};
+use std::cmp::Ordering;
 use std::ops::{Add, Sub};
 
-#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Serialize)]
 pub struct SourceAmount(pub TxAmount, pub TxBase);
 
 impl Default for SourceAmount {
@@ -30,6 +31,16 @@ impl Default for SourceAmount {
     }
 }
 
+impl Ord for SourceAmount {
+    fn cmp(&self, other: &SourceAmount) -> Ordering {
+        if self.1 == other.1 {
+            self.0.cmp(&other.0)
+        } else {
+            self.1.cmp(&other.1)
+        }
+    }
+}
+
 impl Add for SourceAmount {
     type Output = SourceAmount;
     fn add(self, s2: SourceAmount) -> Self::Output {
diff --git a/dal/writers/block.rs b/dal/writers/block.rs
index e86bf9f6714ef94e7bdc19962a1e01d47d7f5378..053146d4bb2bca5f2798d2c29f6681071c39226f 100644
--- a/dal/writers/block.rs
+++ b/dal/writers/block.rs
@@ -1,6 +1,6 @@
 use block::DALBlock;
 use duniter_documents::blockchain::Document;
-use duniter_documents::{BlockHash, BlockId, Blockstamp, PreviousBlockstamp};
+use duniter_documents::{BlockHash, BlockId, PreviousBlockstamp};
 use std::collections::HashMap;
 use ForkId;
 use {BinFileDB, DALError, ForksBlocksV10Datas, ForksV10Datas, LocalBlockchainV10Datas};
@@ -11,39 +11,61 @@ pub fn write(
     forks_db: &BinFileDB<ForksV10Datas>,
     forks_blocks_db: &BinFileDB<ForksBlocksV10Datas>,
     dal_block: &DALBlock,
-    old_fork_id: Option<ForkId>,
+    from_to_fork_id: Option<ForkId>,
     sync: bool,
+    revert: bool,
 ) -> Result<(), DALError> {
     if dal_block.fork_id.0 == 0 {
         blockchain_db.write(|db| {
-            db.insert(dal_block.block.number, dal_block.clone());
+            if revert {
+                db.remove(&dal_block.block.number);
+            } else {
+                db.insert(dal_block.block.number, dal_block.clone());
+            }
         })?;
 
-        if old_fork_id.is_some() {
+        if from_to_fork_id.is_some() {
             forks_blocks_db.write(|db| {
                 db.remove(&dal_block.block.blockstamp());
             })?;
         }
     }
-    if let Some(old_fork_id) = old_fork_id {
+    // Move block in a fork
+    if revert {
+        if let Some(to_fork_id) = from_to_fork_id {
+            forks_db.write(|db| {
+                let previous_blockstamp = dal_block.block.previous_blockstamp();
+                let mut fork_meta_datas = db.get(&to_fork_id).unwrap().clone();
+                fork_meta_datas.insert(
+                    previous_blockstamp,
+                    dal_block
+                        .block
+                        .hash
+                        .expect("Try to get hash of a reduce block !"),
+                );
+                db.insert(to_fork_id, fork_meta_datas);
+            })?;
+        }
+    } else if let Some(from_fork_id) = from_to_fork_id {
+        // Remove block in fork origin
         forks_db.write(|db| {
             let mut fork_meta_datas = db
-                .get(&old_fork_id)
-                .expect("old_fork_id don(t exist !")
+                .get(&from_fork_id)
+                .expect("from_fork_id don(t exist !")
                 .clone();
-            let previous_blockstamp = Blockstamp {
-                id: BlockId(dal_block.block.blockstamp().id.0 - 1),
-                hash: dal_block
-                    .block
-                    .hash
-                    .expect("Try to get hash of an uncompleted or reduce block !"),
-            };
+            let previous_blockstamp = dal_block.block.previous_blockstamp();
             fork_meta_datas.remove(&previous_blockstamp);
-            db.insert(old_fork_id, fork_meta_datas);
+            db.insert(from_fork_id, fork_meta_datas);
             if dal_block.fork_id.0 > 0 {
                 let mut fork_meta_datas = db.get(&dal_block.fork_id).unwrap().clone();
-                fork_meta_datas.insert(previous_blockstamp, dal_block.block.hash.unwrap());
-                db.insert(old_fork_id, fork_meta_datas);
+                fork_meta_datas.insert(
+                    previous_blockstamp,
+                    dal_block
+                        .block
+                        .hash
+                        .expect("Try to get hash of a reduce block !"),
+                );
+                db.insert(from_fork_id, fork_meta_datas);
             }
         })?;
     }
diff --git a/dal/writers/dividend.rs b/dal/writers/dividend.rs
index 7f7a4a350bdc0872de0fac405f48fe6f0ba4dd1a..3071e6c675942754143d36be262b2d254d8a1817 100644
--- a/dal/writers/dividend.rs
+++ b/dal/writers/dividend.rs
@@ -28,12 +28,17 @@ pub fn create_du<B: Backend + Debug>(
     du_amount: &SourceAmount,
     du_block_id: &BlockId,
     members: &[PubKey],
+    revert: bool,
 ) -> Result<(), DALError> {
-    // Insert DU sources in DUsV10DB
+    // Insert/Remove DU sources in DUsV10DB
     du_db.write(|db| {
         for pubkey in members {
             let mut pubkey_dus = db.get(&pubkey).cloned().unwrap_or_default();
-            pubkey_dus.insert(*du_block_id);
+            if revert {
+                pubkey_dus.remove(du_block_id);
+            } else {
+                pubkey_dus.insert(*du_block_id);
+            }
             db.insert(*pubkey, pubkey_dus);
         }
     })?;
@@ -52,11 +57,15 @@ pub fn create_du<B: Backend + Debug>(
             }
             members_balances
         })?;
-    // Increment members balance
+    // Increase/Decrease members balance
     let members_balances: Vec<(PubKey, (SourceAmount, HashSet<UTXOIndexV10>))> = members_balances
         .iter()
         .map(|(pubkey, (balance, utxos_indexs))| {
-            let new_balance = *balance + *du_amount;
+            let new_balance = if revert {
+                *balance - *du_amount
+            } else {
+                *balance + *du_amount
+            };
             (*pubkey, (new_balance, utxos_indexs.clone()))
         })
         .collect();
diff --git a/dal/writers/identity.rs b/dal/writers/identity.rs
index 214f4dbd769baee30dabe49325f8124c723bfe25..8426edf30340ee82163eebd9cc559f83eab1646d 100644
--- a/dal/writers/identity.rs
+++ b/dal/writers/identity.rs
@@ -1,24 +1,70 @@
-use super::super::identity::DALIdentity;
+use currency_params::CurrencyParameters;
+use duniter_crypto::keys::PubKey;
+use duniter_documents::blockchain::v10::documents::IdentityDocument;
 use duniter_documents::blockchain::Document;
-use duniter_documents::BlockId;
+use duniter_documents::{BlockId, Blockstamp};
 use duniter_wotb::NodeId;
+use identity::{DALIdentity, DALIdentityState};
 use {BinFileDB, DALError, IdentitiesV10Datas, MsExpirV10Datas};
 
-pub fn write(
-    idty: &DALIdentity,
-    idty_wot_id: NodeId,
+pub fn revert_create_identity(
     identities_db: &BinFileDB<IdentitiesV10Datas>,
     ms_db: &BinFileDB<MsExpirV10Datas>,
+    pubkey: &PubKey,
+) -> Result<(), DALError> {
+    let dal_idty = identities_db.read(|db| {
+        db.get(&pubkey)
+            .expect("Fatal error : try to revert unknow identity !")
+            .clone()
+    })?;
+    // Remove membership
+    ms_db.write(|db| {
+        let mut memberships = db
+            .get(&dal_idty.ms_created_block_id)
+            .cloned()
+            .expect("Try to revert a membership that does not exist !");
+        memberships.remove(&dal_idty.wot_id);
+        db.insert(dal_idty.ms_created_block_id, memberships);
+    })?;
+    // Remove identity
+    identities_db.write(|db| {
+        db.remove(&dal_idty.idty_doc.issuers()[0]);
+    })?;
+    Ok(())
+}
+
+pub fn create_identity(
+    currency_params: &CurrencyParameters,
+    identities_db: &BinFileDB<IdentitiesV10Datas>,
+    ms_db: &BinFileDB<MsExpirV10Datas>,
+    idty_doc: &IdentityDocument,
     ms_created_block_id: BlockId,
+    wot_id: NodeId,
+    current_blockstamp: Blockstamp,
+    current_bc_time: u64,
 ) -> Result<(), DALError> {
+    let mut idty_doc = idty_doc.clone();
+    idty_doc.reduce();
+    let idty = DALIdentity {
+        hash: "0".to_string(),
+        state: DALIdentityState::Member(vec![0]),
+        joined_on: current_blockstamp,
+        expired_on: None,
+        revoked_on: None,
+        idty_doc,
+        wot_id,
+        ms_created_block_id,
+        ms_chainable_on: vec![current_bc_time + currency_params.ms_period],
+        cert_chainable_on: vec![],
+    };
     // Write Identity
     identities_db.write(|db| {
         db.insert(idty.idty_doc.issuers()[0], idty.clone());
     })?;
-    // Update IdentitiesV10DB
+    // Write membership
     ms_db.write(|db| {
         let mut memberships = db.get(&ms_created_block_id).cloned().unwrap_or_default();
-        memberships.insert(idty_wot_id);
+        memberships.insert(wot_id);
         db.insert(ms_created_block_id, memberships);
     })?;
     Ok(())
diff --git a/dal/writers/requests.rs b/dal/writers/requests.rs
index ef5ca6216a1bf9948080e0e3a60a22b24b4cf29f..0b42b7d24f9d0a3682c94640e6b57827b11cd417 100644
--- a/dal/writers/requests.rs
+++ b/dal/writers/requests.rs
@@ -4,6 +4,7 @@ extern crate serde_json;
 use block::DALBlock;
 use currency_params::CurrencyParameters;
 use duniter_crypto::keys::PubKey;
+use duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument;
 use duniter_documents::blockchain::v10::documents::identity::IdentityDocument;
 use duniter_documents::Blockstamp;
 use duniter_wotb::NodeId;
@@ -12,6 +13,7 @@ use rustbreak::backend::Backend;
 use sources::SourceAmount;
 use std::fmt::Debug;
 use std::ops::Deref;
+use writers::transaction::DALTxV10;
 use *;
 
 #[derive(Debug, Clone)]
@@ -31,29 +33,40 @@ pub enum BlocksDBsWriteQuery {
     /// Write block
     WriteBlock(Box<DALBlock>, Option<ForkId>, PreviousBlockstamp, BlockHash),
     /// Revert block
-    RevertBlock(Box<DALBlock>),
+    RevertBlock(Box<DALBlock>, Option<ForkId>),
 }
 
 impl BlocksDBsWriteQuery {
     pub fn apply(&self, databases: &BlocksV10DBs, sync: bool) -> Result<(), DALError> {
-        if let BlocksDBsWriteQuery::WriteBlock(
-            ref dal_block,
-            ref old_fork_id,
-            ref _previous_blockstamp,
-            ref _block_hash,
-        ) = *self
-        {
-            let dal_block = dal_block.deref();
-            trace!("BlocksDBsWriteQuery::WriteBlock...");
-            super::block::write(
-                &databases.blockchain_db,
-                &databases.forks_db,
-                &databases.forks_blocks_db,
-                &dal_block,
-                *old_fork_id,
-                sync,
-            )?;
-            trace!("BlocksDBsWriteQuery::WriteBlock...finish");
+        match *self {
+            BlocksDBsWriteQuery::WriteBlock(ref dal_block, ref old_fork_id, _, _) => {
+                let dal_block = dal_block.deref();
+                trace!("BlocksDBsWriteQuery::WriteBlock...");
+                super::block::write(
+                    &databases.blockchain_db,
+                    &databases.forks_db,
+                    &databases.forks_blocks_db,
+                    &dal_block,
+                    *old_fork_id,
+                    sync,
+                    false,
+                )?;
+                trace!("BlocksDBsWriteQuery::WriteBlock...finish");
+            }
+            BlocksDBsWriteQuery::RevertBlock(ref dal_block, ref to_fork_id) => {
+                let dal_block = dal_block.deref();
+                trace!("BlocksDBsWriteQuery::WriteBlock...");
+                super::block::write(
+                    &databases.blockchain_db,
+                    &databases.forks_db,
+                    &databases.forks_blocks_db,
+                    &dal_block,
+                    *to_fork_id,
+                    sync,
+                    true,
+                )?;
+                trace!("BlocksDBsWriteQuery::WriteBlock...finish");
+            }
         }
         Ok(())
     }
@@ -64,16 +77,28 @@ impl BlocksDBsWriteQuery {
 pub enum WotsDBsWriteQuery {
     /// Newcomer (wotb_id, blockstamp, current_bc_time, idty_doc, ms_created_block_id)
     CreateIdentity(NodeId, Blockstamp, u64, Box<IdentityDocument>, BlockId),
+    /// Revert newcomer event (wotb_id, blockstamp, current_bc_time, idty_doc, ms_created_block_id)
+    RevertCreateIdentity(PubKey),
     /// Active (pubKey, idty_wot_id, current_bc_time, ms_created_block_id)
     RenewalIdentity(PubKey, NodeId, u64, BlockId),
+    /// Revert active (pubKey, idty_wot_id, current_bc_time, ms_created_block_id)
+    RevertRenewalIdentity(PubKey, NodeId, u64, BlockId),
     /// Excluded
     ExcludeIdentity(PubKey, Blockstamp),
+    /// Revert exclusion
+    RevertExcludeIdentity(PubKey, Blockstamp),
     /// Revoked
-    RevokeIdentity(PubKey, Blockstamp),
+    RevokeIdentity(PubKey, Blockstamp, bool),
+    /// Revert revocation
+    RevertRevokeIdentity(PubKey, Blockstamp, bool),
     /// Certification (source_pubkey, source, target, created_block_id, median_time)
     CreateCert(PubKey, NodeId, NodeId, BlockId, u64),
+    /// Revert certification (source_pubkey, source, target, created_block_id, median_time)
+    RevertCert(CompactCertificationDocument, NodeId, NodeId),
     /// Certification expiry (source, target, created_block_id)
     ExpireCert(NodeId, NodeId, BlockId),
+    /// Revert certification expiry event (source, target, created_block_id)
+    RevertExpireCert(NodeId, NodeId, BlockId),
 }
 
 impl WotsDBsWriteQuery {
@@ -90,22 +115,23 @@ impl WotsDBsWriteQuery {
                 ref idty_doc,
                 ref ms_created_block_id,
             ) => {
-                trace!("WotsDBsWriteQuery::CreateIdentity...");
-                let idty = DALIdentity::create_identity(
+                writers::identity::create_identity(
                     currency_params,
+                    &databases.identities_db,
+                    &databases.ms_db,
                     idty_doc.deref(),
+                    *ms_created_block_id,
                     *wotb_id,
                     *blockstamp,
                     *current_bc_time,
-                );
-                super::identity::write(
-                    &idty,
-                    *wotb_id,
+                )?;
+            }
+            WotsDBsWriteQuery::RevertCreateIdentity(ref pubkey) => {
+                writers::identity::revert_create_identity(
                     &databases.identities_db,
                     &databases.ms_db,
-                    *ms_created_block_id,
+                    pubkey,
                 )?;
-                trace!("WotsDBsWriteQuery::CreateIdentity...finish.");
             }
             WotsDBsWriteQuery::RenewalIdentity(
                 ref pubkey,
@@ -128,18 +154,49 @@ impl WotsDBsWriteQuery {
                 )?;
                 trace!("DBWrWotsDBsWriteQueryiteRequest::RenewalIdentity...");
             }
+            WotsDBsWriteQuery::RevertRenewalIdentity(
+                ref pubkey,
+                ref idty_wot_id,
+                ref current_bc_time,
+                ms_created_block_id,
+            ) => {
+                let mut idty = DALIdentity::get_identity(&databases.identities_db, pubkey)?
+                    .expect("Fatal error : impossible to renewal an identidy that don't exist !");
+                idty.renewal_identity(
+                    currency_params,
+                    &databases.identities_db,
+                    &databases.ms_db,
+                    pubkey,
+                    *idty_wot_id,
+                    *current_bc_time,
+                    ms_created_block_id,
+                    true,
+                )?;
+            }
             WotsDBsWriteQuery::ExcludeIdentity(ref pubkey, ref blockstamp) => {
                 DALIdentity::exclude_identity(&databases.identities_db, pubkey, blockstamp, false)?;
             }
-            WotsDBsWriteQuery::RevokeIdentity(ref pubkey, ref blockstamp) => {
+            WotsDBsWriteQuery::RevertExcludeIdentity(ref pubkey, ref blockstamp) => {
+                DALIdentity::exclude_identity(&databases.identities_db, pubkey, blockstamp, true)?;
+            }
+            WotsDBsWriteQuery::RevokeIdentity(ref pubkey, ref blockstamp, ref explicit) => {
                 DALIdentity::revoke_identity(
                     &databases.identities_db,
                     pubkey,
                     blockstamp,
-                    true,
+                    *explicit,
                     false,
                 )?;
             }
+            WotsDBsWriteQuery::RevertRevokeIdentity(ref pubkey, ref blockstamp, ref explicit) => {
+                DALIdentity::revoke_identity(
+                    &databases.identities_db,
+                    pubkey,
+                    blockstamp,
+                    *explicit,
+                    true,
+                )?;
+            }
             WotsDBsWriteQuery::CreateCert(
                 ref source_pubkey,
                 ref source,
@@ -148,7 +205,7 @@ impl WotsDBsWriteQuery {
                 ref median_time,
             ) => {
                 trace!("WotsDBsWriteQuery::CreateCert...");
-                super::certification::write_certification(
+                writers::certification::write_certification(
                     currency_params,
                     &databases.identities_db,
                     &databases.certs_db,
@@ -160,12 +217,37 @@ impl WotsDBsWriteQuery {
                 )?;
                 trace!("WotsDBsWriteQuery::CreateCert...finish");
             }
+            WotsDBsWriteQuery::RevertCert(ref compact_doc, ref source, ref target) => {
+                trace!("WotsDBsWriteQuery::CreateCert...");
+                writers::certification::revert_write_cert(
+                    &databases.identities_db,
+                    &databases.certs_db,
+                    *compact_doc,
+                    *source,
+                    *target,
+                )?;
+                trace!("WotsDBsWriteQuery::CreateCert...finish");
+            }
             WotsDBsWriteQuery::ExpireCert(ref _source, ref _target, ref _created_block_id) => {
                 /*super::certification::expire_cert(
                     &databases.certs_db,
                     *source,
                     *target,
                     *created_block_id,
+                    false,
+                )?;*/
+            }
+            WotsDBsWriteQuery::RevertExpireCert(
+                ref _source,
+                ref _target,
+                ref _created_block_id,
+            ) => {
+                /*super::certification::expire_cert(
+                    &databases.certs_db,
+                    *source,
+                    *target,
+                    *created_block_id,
+                    true,
                 )?;*/
             }
         }
@@ -178,29 +260,41 @@ impl WotsDBsWriteQuery {
 pub enum CurrencyDBsWriteQuery {
     /// Write transaction
     WriteTx(Box<TransactionDocument>),
+    /// Revert transaction
+    RevertTx(Box<DALTxV10>),
     /// Create dividend
     CreateDU(SourceAmount, BlockId, Vec<PubKey>),
+    /// Revert dividend
+    RevertDU(SourceAmount, BlockId, Vec<PubKey>),
 }
 
 impl CurrencyDBsWriteQuery {
     pub fn apply<B: Backend + Debug>(&self, databases: &CurrencyV10DBs<B>) -> Result<(), DALError> {
         match *self {
             CurrencyDBsWriteQuery::WriteTx(ref tx_doc) => {
-                super::transaction::apply_and_write_tx::<B>(
-                    &databases.tx_db,
-                    &databases.utxos_db,
+                super::transaction::apply_and_write_tx::<B>(&databases, tx_doc.deref())?;
+            }
+            CurrencyDBsWriteQuery::RevertTx(ref dal_tx) => {
+                super::transaction::revert_tx::<B>(&databases, dal_tx.deref())?;
+            }
+            CurrencyDBsWriteQuery::CreateDU(ref du_amount, ref block_id, ref members) => {
+                super::dividend::create_du::<B>(
                     &databases.du_db,
                     &databases.balances_db,
-                    tx_doc.deref(),
+                    du_amount,
+                    block_id,
+                    members,
+                    false,
                 )?;
             }
-            CurrencyDBsWriteQuery::CreateDU(ref du_amount, ref block_id, ref members) => {
+            CurrencyDBsWriteQuery::RevertDU(ref du_amount, ref block_id, ref members) => {
                 super::dividend::create_du::<B>(
                     &databases.du_db,
                     &databases.balances_db,
                     du_amount,
                     block_id,
                     members,
+                    true,
                 )?;
             }
         }
diff --git a/dal/writers/transaction.rs b/dal/writers/transaction.rs
index 662dc1712148fb84e5480bf1a184612758c49c88..9aeafafa92f91c95b310435f67d40e82018e4882 100644
--- a/dal/writers/transaction.rs
+++ b/dal/writers/transaction.rs
@@ -33,15 +33,212 @@ impl From<DALError> for TxError {
 
 #[derive(Debug, Clone, Deserialize, Serialize)]
 pub struct DALTxV10 {
-    tx_doc: TransactionDocument,
-    sources_destroyed: HashSet<UTXOIndexV10>,
+    pub tx_doc: TransactionDocument,
+    pub sources_destroyed: HashSet<UTXOIndexV10>,
+}
+
+pub fn revert_tx<B: Backend + Debug>(
+    dbs: &CurrencyV10DBs<B>,
+    dal_tx: &DALTxV10,
+) -> Result<(), DALError> {
+    let mut tx_doc = dal_tx.tx_doc.clone();
+    let tx_hash = tx_doc.get_hash();
+    let sources_destroyed = &dal_tx.sources_destroyed;
+
+    // Index consumed utxos
+    let consumed_utxos: Vec<UTXOV10> = tx_doc
+        .get_outputs()
+        .iter()
+        .enumerate()
+        .map(|(tx_index, output)| UTXOV10(UTXOIndexV10(tx_hash, TxIndex(tx_index)), output.clone()))
+        .collect();
+    // Recalculate balance of consumed adress
+    let new_balances_consumed_adress = dbs.balances_db.read(|db| {
+        let mut new_balances_consumed_adress: HashMap<
+            TransactionOutputConditionGroup,
+            (SourceAmount, HashSet<UTXOIndexV10>),
+        > = HashMap::new();
+        for source in &consumed_utxos {
+            let source_amount = source.get_amount();
+            let conditions = source.get_conditions();
+            let (balance, new_sources_index) = if let Some((balance, sources_index)) =
+                new_balances_consumed_adress.get(&conditions)
+            {
+                let mut new_sources_index = sources_index.clone();
+                new_sources_index.remove(&source.0);
+                (*balance, new_sources_index)
+            } else if let Some((balance, sources_index)) = db.get(&conditions) {
+                let mut new_sources_index = sources_index.clone();
+                new_sources_index.remove(&source.0);
+                (*balance, new_sources_index)
+            } else {
+                panic!("Fail to revert tx : an output conditions don't exist in BalancesDB.")
+            };
+            let new_balance = if balance >= source_amount {
+                balance - source_amount
+            } else {
+                panic!("Fail to revert tx : an output revert cause negative balance.")
+            };
+            new_balances_consumed_adress.insert(conditions, (new_balance, new_sources_index));
+        }
+        new_balances_consumed_adress
+    })?;
+    // Remove consumed UTXOs
+    dbs.utxos_db.write(|db| {
+        for utxo_v10 in consumed_utxos {
+            db.remove(&utxo_v10.0);
+        }
+    })?;
+    // Write new balance of consumed adress
+    dbs.balances_db.write(|db| {
+        for (conditions, (balance, sources_index)) in new_balances_consumed_adress {
+            db.insert(conditions, (balance, sources_index));
+        }
+    })?;
+    // Complete sources_destroyed
+    let sources_destroyed: HashMap<
+        TransactionOutputConditionGroup,
+        Vec<(UTXOIndexV10, SourceAmount)>,
+    > = if !sources_destroyed.is_empty() {
+        dbs.tx_db.read(|db| {
+            let mut sources_destroyed_completed = HashMap::new();
+            for s_index in sources_destroyed {
+                let tx_output = db
+                    .get(&s_index.0)
+                    .expect("Not find tx")
+                    .tx_doc
+                    .get_outputs()[(s_index.1).0]
+                    .clone();
+                let mut sources_destroyed_for_same_address: Vec<(
+                    UTXOIndexV10,
+                    SourceAmount,
+                )> = sources_destroyed_completed
+                    .get(&tx_output.conditions)
+                    .cloned()
+                    .unwrap_or_default();
+                sources_destroyed_for_same_address
+                    .push((*s_index, SourceAmount(tx_output.amount, tx_output.base)));
+                sources_destroyed_completed
+                    .insert(tx_output.conditions, sources_destroyed_for_same_address);
+            }
+            sources_destroyed_completed
+        })?
+    } else {
+        HashMap::with_capacity(0)
+    };
+    // Index recreated sources
+    let recreated_sources: HashMap<SourceIndexV10, SourceAmount> = tx_doc
+        .get_inputs()
+        .iter()
+        .map(|input| match *input {
+            TransactionInput::D(tx_amout, tx_amout_base, pubkey, block_id) => (
+                SourceIndexV10::DU(pubkey, block_id),
+                SourceAmount(tx_amout, tx_amout_base),
+            ),
+            TransactionInput::T(tx_amout, tx_amout_base, hash, tx_index) => (
+                SourceIndexV10::UTXO(UTXOIndexV10(hash, tx_index)),
+                SourceAmount(tx_amout, tx_amout_base),
+            ),
+        })
+        .collect();
+    // Find adress of recreated sources
+    let recreated_adress: HashMap<
+        TransactionOutputConditionGroup,
+        (SourceAmount, HashSet<UTXOIndexV10>),
+    > = dbs.utxos_db.read(|db| {
+        let mut recreated_adress: HashMap<
+            TransactionOutputConditionGroup,
+            (SourceAmount, HashSet<UTXOIndexV10>),
+        > = HashMap::new();
+        for (source_index, source_amount) in &recreated_sources {
+            if let SourceIndexV10::UTXO(utxo_index) = source_index {
+                // Get utxo
+                let utxo = db
+                    .get(&utxo_index)
+                    .expect("ApplyBLockError : unknow UTXO in inputs !");
+                // Get utxo conditions(=address)
+                let conditions = &utxo.conditions;
+                // Calculate new balances datas for "conditions" address
+                let (mut balance, mut utxos_index) = recreated_adress
+                    .get(conditions)
+                    .cloned()
+                    .unwrap_or_default();
+                balance = balance + *source_amount;
+                utxos_index.insert(*utxo_index);
+                // Write new balances datas for "conditions" address
+                recreated_adress.insert(conditions.clone(), (balance, utxos_index));
+            } else if let SourceIndexV10::DU(pubkey, _block_id) = source_index {
+                let address = TransactionOutputConditionGroup::Single(
+                    TransactionOutputCondition::Sig(*pubkey),
+                );
+                let (mut balance, utxos_index) =
+                    recreated_adress.get(&address).cloned().unwrap_or_default();
+                balance = balance + *source_amount;
+                recreated_adress.insert(address, (balance, utxos_index));
+            }
+        }
+        recreated_adress
+    })?;
+    // Recalculate balance of recreated adress
+    let new_balances_recreated_adress = dbs.balances_db.read(|db| {
+        let mut new_balances_recreated_adress = Vec::new();
+        for (conditions, (amount_recreated, adress_recreated_sources)) in recreated_adress {
+            let (mut balance, mut sources_indexs) =
+                if let Some((balance, sources_indexs)) = db.get(&conditions) {
+                    (*balance, sources_indexs.clone())
+                } else {
+                    (SourceAmount::default(), HashSet::new())
+                };
+            // Apply recreated sources (inputs)
+            balance = balance + amount_recreated;
+            for s_index in adress_recreated_sources {
+                sources_indexs.insert(s_index);
+            }
+            // Recreate destroy sources
+            if let Some(address_sources_destroyed) = sources_destroyed.get(&conditions) {
+                for (utxo_index, s_amout) in address_sources_destroyed {
+                    balance = balance + *s_amout;
+                    sources_indexs.insert(*utxo_index);
+                }
+            }
+            new_balances_recreated_adress.push((conditions.clone(), (balance, sources_indexs)));
+        }
+        new_balances_recreated_adress
+    })?;
+    // Write new balance of recreated adress
+    dbs.balances_db.write(|db| {
+        for (conditions, (balance, sources_index)) in new_balances_recreated_adress {
+            db.insert(conditions, (balance, sources_index));
+        }
+    })?;
+    // Recreate recreated sources
+    for s_index in recreated_sources.keys() {
+        if let SourceIndexV10::UTXO(utxo_index) = s_index {
+            let utxo_content = dbs.tx_db.read(|db| {
+                db.get(&utxo_index.0)
+                    .expect("Fatal error : not found Source TX of this utxo !")
+                    .tx_doc
+                    .get_outputs()[(utxo_index.1).0]
+                    .clone()
+            })?;
+            dbs.utxos_db.write(|db| {
+                db.insert(*utxo_index, utxo_content);
+            })?;
+        } else if let SourceIndexV10::DU(pubkey, block_id) = s_index {
+            let mut pubkey_dus: HashSet<BlockId> = dbs
+                .du_db
+                .read(|db| db.get(&pubkey).cloned().unwrap_or_default())?;
+            pubkey_dus.insert(*block_id);
+            dbs.du_db.write(|db| {
+                db.insert(*pubkey, pubkey_dus);
+            })?;
+        }
+    }
+    Ok(())
 }
 
 pub fn apply_and_write_tx<B: Backend + Debug>(
-    tx_db: &BinDB<TxV10Datas, B>,
-    utxos_db: &BinDB<UTXOsV10Datas, B>,
-    dus_db: &BinDB<DUsV10Datas, B>,
-    balances_db: &BinDB<BalancesV10Datas, B>,
+    dbs: &CurrencyV10DBs<B>,
     tx_doc: &TransactionDocument,
 ) -> Result<(), DALError> {
     let mut tx_doc = tx_doc.clone();
@@ -66,7 +263,7 @@ pub fn apply_and_write_tx<B: Backend + Debug>(
     let consumed_adress: HashMap<
         TransactionOutputConditionGroup,
         (SourceAmount, HashSet<UTXOIndexV10>),
-    > = utxos_db.read(|db| {
+    > = dbs.utxos_db.read(|db| {
         let mut consumed_adress: HashMap<
             TransactionOutputConditionGroup,
             (SourceAmount, HashSet<UTXOIndexV10>),
@@ -99,7 +296,7 @@ pub fn apply_and_write_tx<B: Backend + Debug>(
         consumed_adress
     })?;
     // Recalculate balance of consumed adress
-    let new_balances_consumed_adress = balances_db.read(|db| {
+    let new_balances_consumed_adress = dbs.balances_db.read(|db| {
         let mut new_balances_consumed_adress = Vec::new();
         for (conditions, (amount_consumed, adress_consumed_sources)) in consumed_adress {
             if let Some((balance, sources)) = db.get(&conditions) {
@@ -121,7 +318,7 @@ pub fn apply_and_write_tx<B: Backend + Debug>(
         new_balances_consumed_adress
     })?;
     // Write new balance of consumed adress
-    balances_db.write(|db| {
+    dbs.balances_db.write(|db| {
         for (conditions, (balance, sources_index)) in new_balances_consumed_adress {
             db.insert(conditions, (balance, sources_index));
         }
@@ -129,14 +326,15 @@ pub fn apply_and_write_tx<B: Backend + Debug>(
     // Remove consumed sources
     for source_index in consumed_sources.keys() {
         if let SourceIndexV10::UTXO(utxo_index) = source_index {
-            utxos_db.write(|db| {
+            dbs.utxos_db.write(|db| {
                 db.remove(utxo_index);
             })?;
         } else if let SourceIndexV10::DU(pubkey, block_id) = source_index {
-            let mut pubkey_dus: HashSet<BlockId> =
-                dus_db.read(|db| db.get(&pubkey).cloned().unwrap_or_default())?;
+            let mut pubkey_dus: HashSet<BlockId> = dbs
+                .du_db
+                .read(|db| db.get(&pubkey).cloned().unwrap_or_default())?;
             pubkey_dus.remove(block_id);
-            dus_db.write(|db| {
+            dbs.du_db.write(|db| {
                 db.insert(*pubkey, pubkey_dus);
             })?;
         }
@@ -158,7 +356,7 @@ pub fn apply_and_write_tx<B: Backend + Debug>(
         .map(|(tx_index, output)| UTXOV10(UTXOIndexV10(tx_hash, TxIndex(tx_index)), output.clone()))
         .collect();
     // Recalculate balance of supplied adress
-    let new_balances_supplied_adress = balances_db.read(|db| {
+    let new_balances_supplied_adress = dbs.balances_db.read(|db| {
         let mut new_balances_supplied_adress: HashMap<
             TransactionOutputConditionGroup,
             (SourceAmount, HashSet<UTXOIndexV10>),
@@ -187,20 +385,20 @@ pub fn apply_and_write_tx<B: Backend + Debug>(
         new_balances_supplied_adress
     })?;
     // Insert created UTXOs
-    utxos_db.write(|db| {
+    dbs.utxos_db.write(|db| {
         for utxo_v10 in created_utxos {
             db.insert(utxo_v10.0, utxo_v10.1);
         }
     })?;
     // Write new balance of supplied adress
-    balances_db.write(|db| {
+    dbs.balances_db.write(|db| {
         for (conditions, (balance, sources_index)) in new_balances_supplied_adress {
             db.insert(conditions, (balance, sources_index));
         }
     })?;
     // Write tx
     tx_doc.reduce();
-    tx_db.write(|db| {
+    dbs.tx_db.write(|db| {
         db.insert(
             tx_hash,
             DALTxV10 {
@@ -256,7 +454,7 @@ mod tests {
     }
 
     #[test]
-    fn apply_one_tx() {
+    fn apply_and_revert_one_tx() {
         // Get document of first g1 transaction
         let tx_doc = build_first_tx_of_g1();
         assert_eq!(tx_doc.verify_signatures(), VerificationResult::Valid());
@@ -274,6 +472,7 @@ mod tests {
             &SourceAmount(TxAmount(1000), TxBase(0)),
             &BlockId(1),
             &vec![tx_doc.issuers()[0], tortue_pubkey],
+            false,
         ).expect("Fail to create first g1 DU !");
         // Check members balance
         let cgeek_new_balance = currency_dbs
@@ -300,13 +499,7 @@ mod tests {
             SourceAmount(TxAmount(1000), TxBase(0))
         );
         // Apply first g1 transaction
-        apply_and_write_tx(
-            &currency_dbs.tx_db,
-            &currency_dbs.utxos_db,
-            &currency_dbs.du_db,
-            &currency_dbs.balances_db,
-            &tx_doc,
-        ).expect("Fail to apply first g1 tx");
+        apply_and_write_tx(&currency_dbs, &tx_doc).expect("Fail to apply first g1 tx");
         // Check issuer new balance
         let cgeek_new_balance = currency_dbs
             .balances_db
@@ -333,5 +526,41 @@ mod tests {
             receiver_new_balance.0,
             SourceAmount(TxAmount(1001), TxBase(0))
         );
+
+        // Revert first g1 tx
+        revert_tx(
+            &currency_dbs,
+            &DALTxV10 {
+                tx_doc: tx_doc.clone(),
+                sources_destroyed: HashSet::with_capacity(0),
+            },
+        ).expect("Fail to revert first g1 tx");
+
+        // Check issuer new balance
+        let cgeek_new_balance = currency_dbs
+            .balances_db
+            .read(|db| {
+                db.get(&TransactionOutputConditionGroup::Single(
+                    TransactionOutputCondition::Sig(tx_doc.issuers()[0]),
+                )).cloned()
+            })
+            .expect("Fail to read cgeek new balance")
+            .expect("Error : cgeek is not referenced in balances_db !");
+        assert_eq!(cgeek_new_balance.0, SourceAmount(TxAmount(1000), TxBase(0)));
+
+        // Check receiver new balance
+        let receiver_new_balance = currency_dbs
+            .balances_db
+            .read(|db| {
+                db.get(&TransactionOutputConditionGroup::Single(
+                    TransactionOutputCondition::Sig(tortue_pubkey),
+                )).cloned()
+            })
+            .expect("Fail to read receiver new balance")
+            .expect("Error : receiver is not referenced in balances_db !");
+        assert_eq!(
+            receiver_new_balance.0,
+            SourceAmount(TxAmount(1000), TxBase(0))
+        );
     }
 }
diff --git a/documents/blockchain/v10/documents/block.rs b/documents/blockchain/v10/documents/block.rs
index 5cc23ba33cddede3460126e7457a694bee571d9d..1968890f733498c6208d04b2c1fcc42fb7789fe2 100644
--- a/documents/blockchain/v10/documents/block.rs
+++ b/documents/blockchain/v10/documents/block.rs
@@ -34,6 +34,12 @@ use {BlockHash, BlockId, Blockstamp, Hash};
 #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
 pub struct CurrencyName(pub String);
 
+impl Default for CurrencyName {
+    fn default() -> CurrencyName {
+        CurrencyName(String::from("default_currency"))
+    }
+}
+
 impl Display for CurrencyName {
     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
         write!(f, "{}", self.0)
diff --git a/documents/blockchain/v10/documents/transaction.rs b/documents/blockchain/v10/documents/transaction.rs
index aa6ddacd9db91975ccd1a4d803bf1fe2e9cbe62a..12388f01f17ab4a91a555ce5ca211471d7285260 100644
--- a/documents/blockchain/v10/documents/transaction.rs
+++ b/documents/blockchain/v10/documents/transaction.rs
@@ -75,7 +75,7 @@ impl Sub for TxAmount {
 }
 
 /// Wrap a transaction amout base
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Hash, Serialize)]
+#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Deserialize, Hash, Serialize)]
 pub struct TxBase(pub usize);
 
 /// Wrap a transaction index
diff --git a/documents/lib.rs b/documents/lib.rs
index f39b5f5db3d16f2a8cf5336fcedc2939dd6ed6e3..4d006cb654eeb7ff909a09f3cd88c318d01bc6bc 100644
--- a/documents/lib.rs
+++ b/documents/lib.rs
@@ -43,7 +43,7 @@ use std::fmt::{Debug, Display, Error, Formatter};
 pub mod blockchain;
 
 /// A block Id.
-#[derive(Debug, Deserialize, Copy, Clone, Ord, PartialEq, PartialOrd, Eq, Hash, Serialize)]
+#[derive(Copy, Clone, Debug, Deserialize, Ord, PartialEq, PartialOrd, Eq, Hash, Serialize)]
 pub struct BlockId(pub u32);
 
 impl Display for BlockId {
diff --git a/src/main.rs b/src/main.rs
index c9e127fb73aeea7c141dcba4ecfa7250f1f68531..d8e7d606e6bacb619f58c9ba45988f829ec32c46 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -24,10 +24,12 @@
 
 extern crate duniter_core;
 extern crate duniter_tui;
+#[cfg(feature = "ws2p")]
 extern crate duniter_ws2p;
 
 pub use duniter_core::DuniterCore;
 pub use duniter_tui::TuiModule;
+#[cfg(feature = "ws2p")]
 pub use duniter_ws2p::WS2PModule;
 
 /// Main function
@@ -38,13 +40,21 @@ fn main() {
 
     // Run duniter core
     if let Some(mut duniter_core) = DuniterCore::new(soft_name, soft_version) {
-        duniter_core.plug::<WS2PModule>();
-        duniter_core.plug::<TuiModule>();
-        //duniter_core.plug::<PoolModule>();
-        //duniter_core.plug::<PowModule>();
-        //duniter_core.plug::<GvaModule>();
         //duniter_core.plug::<DasaModule>();
         //duniter_core.plug::<GuiModule>();
+        //duniter_core.plug::<GvaModule>();
+        //duniter_core.plug::<PoolModule>();
+        //duniter_core.plug::<PowModule>();
+        duniter_core.plug::<TuiModule>();
+        plug_ws2p_module(&mut duniter_core);
         duniter_core.start_blockchain();
     };
 }
+
+/// Plug WS2P Module
+#[cfg(feature = "ws2p")]
+fn plug_ws2p_module(duniter_core: &mut DuniterCore) {
+    duniter_core.plug::<WS2PModule>();
+}
+#[cfg(not(feature = "ws2p"))]
+fn plug_ws2p_module(_duniter_core: &mut DuniterCore) {}
diff --git a/wotb/data/mod.rs b/wotb/data/mod.rs
index fe6beec488891f4a6943b0b87a2fc92b58db9b88..e88b69337c1da0c2a0b9a9fa5d2e8652e74d1c52 100644
--- a/wotb/data/mod.rs
+++ b/wotb/data/mod.rs
@@ -19,14 +19,68 @@
 
 pub mod rusty;
 
-use serde::de::DeserializeOwned;
-use serde::Serialize;
-use std::fmt::Debug;
+use serde::de::{self, Deserialize, DeserializeOwned, Deserializer, Visitor};
+use serde::{Serialize, Serializer};
+use std::fmt::{self, Debug};
 
 /// Wrapper for a node id.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct NodeId(pub usize);
 
+impl Serialize for NodeId {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        serializer.serialize_u32(self.0 as u32)
+    }
+}
+
+struct NodeIdVisitor;
+
+impl<'de> Visitor<'de> for NodeIdVisitor {
+    type Value = NodeId;
+
+    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        formatter.write_str("an integer between -2^31 and 2^31")
+    }
+
+    fn visit_u8<E>(self, value: u8) -> Result<NodeId, E>
+    where
+        E: de::Error,
+    {
+        Ok(NodeId(value as usize))
+    }
+
+    fn visit_u32<E>(self, value: u32) -> Result<NodeId, E>
+    where
+        E: de::Error,
+    {
+        Ok(NodeId(value as usize))
+    }
+
+    fn visit_u64<E>(self, value: u64) -> Result<NodeId, E>
+    where
+        E: de::Error,
+    {
+        use std::usize;
+        if value >= usize::MIN as u64 && value <= usize::MAX as u64 {
+            Ok(NodeId(value as usize))
+        } else {
+            Err(E::custom(format!("u32 out of range: {}", value)))
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for NodeId {
+    fn deserialize<D>(deserializer: D) -> Result<NodeId, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        deserializer.deserialize_u32(NodeIdVisitor)
+    }
+}
+
 /// Results of a certification, with the current certification count
 /// of the destination as parameter.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]