diff --git a/dal/Cargo.toml b/dal/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..a3ecdaa1528d5fe2d814221abafe3abf69e91eb7
--- /dev/null
+++ b/dal/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+name = "duniter-dal"
+version = "0.1.0"
+authors = ["librelois <elois@ifee.fr>"]
+description = "Data Access Layer for the Duniter project."
+license = "AGPL-3.0"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+duniter-crypto = { path = "../crypto" }
+duniter-documents = { path = "../documents" }
+duniter-module = { path = "../module" }
+duniter-network = { path = "../network" }
+duniter-wotb = { path = "../wotb" }
+lazy_static = "1.0.0"
+log = "0.4.1"
+rand = "0.4.2"
+rust-crypto = "0.2.36"
+regex = "0.2.6"
+sqlite = "0.23.9"
+serde = "1.0.24"
+serde_derive = "1.0.24"
+serde_json = "1.0.9"
+websocket = "0.20.2"
+
+[features]
+exp = []
\ No newline at end of file
diff --git a/dal/block.rs b/dal/block.rs
new file mode 100644
index 0000000000000000000000000000000000000000..92d5cefda333ccb34e1662288f3c3530ef86a741
--- /dev/null
+++ b/dal/block.rs
@@ -0,0 +1,523 @@
+extern crate duniter_crypto;
+extern crate duniter_documents;
+extern crate duniter_wotb;
+extern crate serde;
+extern crate serde_json;
+extern crate sqlite;
+
+use self::duniter_crypto::keys;
+use self::duniter_crypto::keys::{ed25519, PublicKey, Signature};
+use self::duniter_documents::blockchain::v10::documents::identity::IdentityDocument;
+use self::duniter_documents::blockchain::v10::documents::membership::MembershipType;
+use self::duniter_documents::blockchain::v10::documents::BlockDocument;
+use self::duniter_documents::blockchain::Document;
+use self::duniter_documents::{BlockHash, BlockId, Blockstamp, Hash};
+use self::duniter_wotb::NodeId;
+use super::constants::MAX_FORKS;
+use super::parsers::certifications::parse_certifications;
+use super::parsers::excluded::parse_exclusions;
+use super::parsers::identities::parse_identities;
+use super::parsers::memberships::parse_memberships;
+use super::parsers::revoked::parse_revocations;
+use super::parsers::transactions::parse_compact_transactions;
+use super::{DuniterDB, ForkState};
+use std::collections::HashMap;
+
+pub fn blockstamp_to_timestamp(blockstamp: &Blockstamp, db: &DuniterDB) -> Option<u64> {
+    if blockstamp.id.0 == 0 {
+        return Some(1_488_987_127);
+    }
+    let mut cursor = db
+        .0
+        .prepare("SELECT median_time FROM blocks WHERE number=? AND hash=? LIMIT 1;")
+        .expect("convert blockstamp to timestamp failure at step 0 !")
+        .cursor();
+
+    cursor
+        .bind(&[
+            sqlite::Value::Integer(blockstamp.id.0 as i64),
+            sqlite::Value::String(blockstamp.hash.0.to_hex()),
+        ])
+        .expect("convert blockstamp to timestamp failure at step 1 !");
+
+    if let Some(row) = cursor
+        .next()
+        .expect("convert blockstamp to timestamp failure at step 2 !")
+    {
+        return Some(row[0]
+            .as_integer()
+            .expect("convert blockstamp to timestamp failure at step 3 !")
+            as u64);
+    }
+    None
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum WotEvent {
+    AddNode(ed25519::PublicKey, NodeId),
+    RemNode(ed25519::PublicKey),
+    AddLink(NodeId, NodeId),
+    RemLink(NodeId, NodeId),
+    EnableNode(NodeId),
+    DisableNode(NodeId),
+}
+
+#[derive(Debug, Clone)]
+pub struct BlockContext {
+    pub blockstamp: Blockstamp,
+    pub wot_events: Vec<WotEvent>,
+}
+
+#[derive(Debug, Clone)]
+pub struct BlockContextV2 {
+    pub blockstamp: Blockstamp,
+    pub wot_events: Vec<WotEvent>,
+}
+
+#[derive(Debug, Clone)]
+pub struct DALBlock {
+    pub fork: usize,
+    pub isolate: bool,
+    pub block: BlockDocument,
+    pub median_frame: usize,
+    pub second_tiercile_frame: usize,
+}
+
+impl DALBlock {
+    pub fn blockstamp(&self) -> Blockstamp {
+        self.block.blockstamp()
+    }
+}
+
+pub fn get_forks(db: &DuniterDB) -> Vec<ForkState> {
+    let mut forks = Vec::new();
+    forks.push(ForkState::Full());
+    for fork in 1..*MAX_FORKS {
+        let mut cursor = db
+            .0
+            .prepare("SELECT isolate FROM blocks WHERE fork=? ORDER BY median_time DESC LIMIT 1;")
+            .expect("Fail to get block !")
+            .cursor();
+
+        cursor
+            .bind(&[sqlite::Value::Integer(fork as i64)])
+            .expect("Fail to get block !");
+
+        if let Some(row) = cursor.next().unwrap() {
+            if row[0].as_integer().unwrap() == 0 {
+                forks.push(ForkState::Full())
+            } else {
+                forks.push(ForkState::Isolate())
+            }
+        } else {
+            forks.push(ForkState::Free());
+        }
+    }
+    forks
+}
+
+impl DALBlock {
+    pub fn unisolate_fork(db: &DuniterDB, fork: usize) {
+        db.0
+            .execute(format!("UPDATE blocks SET isolate=0 WHERE fork={};", fork))
+            .unwrap();
+    }
+    pub fn delete_fork(db: &DuniterDB, fork: usize) {
+        db.0
+            .execute(format!("DELETE FROM blocks WHERE fork={};", fork))
+            .unwrap();
+    }
+    pub fn get_block_fork(db: &DuniterDB, blockstamp: &Blockstamp) -> Option<usize> {
+        let mut cursor = db
+            .0
+            .prepare("SELECT fork FROM blocks WHERE number=? AND hash=?;")
+            .expect("Fail to get block !")
+            .cursor();
+
+        cursor
+            .bind(&[
+                sqlite::Value::Integer(blockstamp.id.0 as i64),
+                sqlite::Value::String(blockstamp.hash.0.to_string()),
+            ])
+            .expect("Fail to get block !");
+
+        if let Some(row) = cursor.next().unwrap() {
+            Some(row[0].as_integer().unwrap() as usize)
+        } else {
+            None
+        }
+    }
+    pub fn get_block_hash(db: &DuniterDB, block_number: &BlockId) -> Option<BlockHash> {
+        let mut cursor = db
+            .0
+            .prepare("SELECT hash FROM blocks WHERE number=? AND fork=0;")
+            .expect("Fail to get block !")
+            .cursor();
+
+        cursor
+            .bind(&[sqlite::Value::Integer(block_number.0 as i64)])
+            .expect("Fail to get block !");
+
+        if let Some(row) = cursor.next().unwrap() {
+            Some(BlockHash(
+                Hash::from_hex(row[0].as_string().unwrap()).unwrap(),
+            ))
+        } else {
+            None
+        }
+    }
+
+    pub fn get_blocks_hashs_all_forks(
+        db: &DuniterDB,
+        block_number: &BlockId,
+    ) -> (Vec<BlockHash>, Vec<Hash>) {
+        let mut cursor = db
+            .0
+            .prepare("SELECT hash, previous_hash FROM blocks WHERE number=?;")
+            .expect("Fail to get block !")
+            .cursor();
+
+        cursor
+            .bind(&[sqlite::Value::Integer(block_number.0 as i64)])
+            .expect("Fail to get block !");
+
+        let mut hashs = Vec::new();
+        let mut previous_hashs = Vec::new();
+        while let Some(row) = cursor.next().unwrap() {
+            hashs.push(BlockHash(
+                Hash::from_hex(row[0].as_string().unwrap()).unwrap(),
+            ));
+            previous_hashs.push(Hash::from_hex(row[1].as_string().unwrap()).unwrap());
+        }
+        (hashs, previous_hashs)
+    }
+
+    pub fn get_stackables_blocks(
+        currency: &str,
+        db: &DuniterDB,
+        wotb_index: &HashMap<ed25519::PublicKey, NodeId>,
+        current_blockstamp: &Blockstamp,
+    ) -> Vec<DALBlock> {
+        debug!("get_stackables_blocks() after {}", current_blockstamp);
+        let mut stackables_blocks = Vec::new();
+        let block_id = BlockId(current_blockstamp.id.0 + 1);
+        let (hashs, previous_hashs) = DALBlock::get_blocks_hashs_all_forks(db, &block_id);
+        for (hash, previous_hash) in hashs.into_iter().zip(previous_hashs) {
+            if previous_hash == current_blockstamp.hash.0 {
+                if let Some(dal_block) = DALBlock::get_block(
+                    currency,
+                    db,
+                    wotb_index,
+                    &Blockstamp { id: block_id, hash },
+                ) {
+                    stackables_blocks.push(dal_block);
+                } else {
+                    panic!(format!(
+                        "Fail to get stackable block {} !",
+                        Blockstamp { id: block_id, hash }
+                    ));
+                }
+            }
+        }
+        stackables_blocks
+    }
+    pub fn get_stackables_forks(db: &DuniterDB, current_blockstamp: &Blockstamp) -> Vec<usize> {
+        let mut stackables_forks = Vec::new();
+        let block_id = BlockId(current_blockstamp.id.0 + 1);
+        let (hashs, previous_hashs) = DALBlock::get_blocks_hashs_all_forks(db, &block_id);
+        for (hash, previous_hash) in hashs.into_iter().zip(previous_hashs) {
+            if previous_hash == current_blockstamp.hash.0 {
+                if let Some(fork) = DALBlock::get_block_fork(db, &Blockstamp { id: block_id, hash })
+                {
+                    if fork > 0 {
+                        stackables_forks.push(fork);
+                    }
+                }
+            }
+        }
+        stackables_forks
+    }
+    pub fn get_block(
+        currency: &str,
+        db: &DuniterDB,
+        wotb_index: &HashMap<ed25519::PublicKey, NodeId>,
+        blockstamp: &Blockstamp,
+    ) -> Option<DALBlock> {
+        let mut cursor = db
+            .0
+            .prepare(
+                "SELECT fork, isolate, nonce, number,
+            pow_min, time, median_time, members_count,
+            monetary_mass, unit_base, issuers_count, issuers_frame,
+            issuers_frame_var, median_frame, second_tiercile_frame,
+            currency, issuer, signature, hash, previous_hash, dividend, identities, joiners,
+            actives, leavers, revoked, excluded, certifications,
+            transactions FROM blocks WHERE number=? AND hash=?;",
+            )
+            .expect("Fail to get block !")
+            .cursor();
+
+        cursor
+            .bind(&[
+                sqlite::Value::Integer(blockstamp.id.0 as i64),
+                sqlite::Value::String(blockstamp.hash.0.to_string()),
+            ])
+            .expect("Fail to get block !");
+
+        if let Some(row) = cursor.next().expect("block not found in bdd !") {
+            let dividend_amount = row[20]
+                .as_integer()
+                .expect("dal::get_block() : fail to parse dividend !");
+            let dividend = if dividend_amount > 0 {
+                Some(dividend_amount as usize)
+            } else if dividend_amount == 0 {
+                None
+            } else {
+                return None;
+            };
+            let nonce = row[2]
+                .as_integer()
+                .expect("dal::get_block() : fail to parse nonce !") as u64;
+            let inner_hash = Hash::from_hex(
+                row[18]
+                    .as_string()
+                    .expect("dal::get_block() : fail to parse inner_hash !"),
+            ).expect("dal::get_block() : fail to parse inner_hash (2) !");
+            let identities = parse_identities(
+                currency,
+                row[21]
+                    .as_string()
+                    .expect("dal::get_block() : fail to parse identities !"),
+            ).expect("dal::get_block() : fail to parse identities (2) !");
+            let hashmap_identities = identities
+                .iter()
+                .map(|i| (i.issuers()[0], i.clone()))
+                .collect::<HashMap<ed25519::PublicKey, IdentityDocument>>();
+            Some(DALBlock {
+                fork: row[0]
+                    .as_integer()
+                    .expect("dal::get_block() : fail to parse fork !")
+                    as usize,
+                isolate: if row[1]
+                    .as_integer()
+                    .expect("dal::get_block() : fail to parse isolate !")
+                    == 0
+                {
+                    false
+                } else {
+                    true
+                },
+                block: BlockDocument {
+                    nonce,
+                    number: BlockId(row[3]
+                        .as_integer()
+                        .expect("dal::get_block() : fail to parse number !")
+                        as u32),
+                    pow_min: row[4]
+                        .as_integer()
+                        .expect("dal::get_block() : fail to parse pow min !")
+                        as usize,
+                    time: row[5]
+                        .as_integer()
+                        .expect("dal::get_block() : fail to parse time !")
+                        as u64,
+                    median_time: row[6]
+                        .as_integer()
+                        .expect("dal::get_block() : fail to parse median_time !")
+                        as u64,
+                    members_count: row[7]
+                        .as_integer()
+                        .expect("dal::get_block() : fail to parse members_count !")
+                        as usize,
+                    monetary_mass: row[8]
+                        .as_integer()
+                        .expect("dal::get_block() : fail to parse monetary_mass !")
+                        as usize,
+                    unit_base: row[9]
+                        .as_integer()
+                        .expect("dal::get_block() : fail to parse unit_base !")
+                        as usize,
+                    issuers_count: row[10]
+                        .as_integer()
+                        .expect("dal::get_block() : fail to parse issuers_count !")
+                        as usize,
+                    issuers_frame: row[11]
+                        .as_integer()
+                        .expect("dal::get_block() : fail to parse issuers_frame !")
+                        as isize,
+                    issuers_frame_var: row[12]
+                        .as_integer()
+                        .expect("dal::get_block() : fail to parse issuers_frame_var !")
+                        as isize,
+                    currency: row[15]
+                        .as_string()
+                        .expect("dal::get_block() : fail to parse currency !")
+                        .to_string(),
+                    issuers: vec![
+                        PublicKey::from_base58(
+                            row[16]
+                                .as_string()
+                                .expect("dal::get_block() : fail to parse issuer !"),
+                        ).expect("dal::get_block() : fail to parse pubkey !"),
+                    ],
+                    signatures: vec![
+                        Signature::from_base64(
+                            row[17]
+                                .as_string()
+                                .expect("dal::get_block() : fail to parse signature !"),
+                        ).expect("dal::get_block() : fail to parse signature (2) !"),
+                    ],
+                    hash: Some(BlockHash(
+                        Hash::from_hex(
+                            row[18]
+                                .as_string()
+                                .expect("dal::get_block() : fail to parse hash !"),
+                        ).expect("dal::get_block() : fail to parse hash (2) !"),
+                    )),
+                    parameters: None,
+                    previous_hash: Hash::from_hex(
+                        row[19]
+                            .as_string()
+                            .expect("dal::get_block() : fail to parse previous_hash !"),
+                    ).expect(
+                        "dal::get_block() : fail to parse previous_hash (2) !",
+                    ),
+                    previous_issuer: None,
+                    inner_hash: Some(inner_hash),
+                    dividend,
+                    identities: identities.clone(),
+                    joiners: parse_memberships(
+                        currency,
+                        MembershipType::In(),
+                        row[22]
+                            .as_string()
+                            .expect("dal::get_block() : fail to parse joiners !"),
+                    ).expect("dal::get_block() : fail to parse joiners (2) !"),
+                    actives: parse_memberships(
+                        currency,
+                        MembershipType::In(),
+                        row[23]
+                            .as_string()
+                            .expect("dal::get_block() : fail to parse actives !"),
+                    ).expect("dal::get_block() : fail to parse actives (2) !"),
+                    leavers: parse_memberships(
+                        currency,
+                        MembershipType::Out(),
+                        row[24]
+                            .as_string()
+                            .expect("dal::get_block() : fail to parse leavers !"),
+                    ).expect("dal::get_block() : fail to parse leavers (2) !"),
+                    revoked: parse_revocations(
+                        currency,
+                        db,
+                        wotb_index,
+                        &hashmap_identities,
+                        row[25]
+                            .as_string()
+                            .expect("dal::get_block() : fail to parse revoked !"),
+                    ).expect("dal::get_block() : fail to parse revoked (2) !"),
+                    excluded: parse_exclusions(
+                        row[26]
+                            .as_string()
+                            .expect("dal::get_block() : fail to parse excluded !"),
+                    ).expect("dal::get_block() : fail to parse excluded (2) !"),
+                    certifications: parse_certifications(
+                        currency,
+                        db,
+                        wotb_index,
+                        &hashmap_identities,
+                        row[27]
+                            .as_string()
+                            .expect("dal::get_block() : fail to parse certifications !"),
+                    ).expect(
+                        "dal::get_block() : fail to parse certifications (2) !",
+                    ),
+                    transactions: parse_compact_transactions(
+                        currency,
+                        row[28]
+                            .as_string()
+                            .expect("dal::get_block() : fail to parse transactions !"),
+                    ).expect("dal::get_block() : fail to parse transactions (2) !"),
+                    inner_hash_and_nonce_str: format!(
+                        "InnerHash: {}\nNonce: {}\n",
+                        inner_hash.to_hex(),
+                        nonce
+                    ),
+                },
+                median_frame: row[13].as_integer().unwrap_or(0) as usize,
+                second_tiercile_frame: row[14].as_integer().unwrap_or(0) as usize,
+            })
+        } else {
+            None
+        }
+    }
+
+    pub fn get_current_frame(&self, db: &DuniterDB) -> HashMap<keys::ed25519::PublicKey, usize> {
+        let frame_begin = self.block.number.0 as i64 - (self.block.issuers_frame as i64);
+        let mut current_frame: HashMap<keys::ed25519::PublicKey, usize> = HashMap::new();
+        let mut cursor = db
+            .0
+            .prepare("SELECT issuer FROM blocks WHERE fork=0 AND number>=? LIMIT ?;")
+            .expect("get current frame blocks failure at step 1 !")
+            .cursor();
+        cursor
+            .bind(&[
+                sqlite::Value::Integer(frame_begin),
+                sqlite::Value::Integer(self.block.issuers_frame as i64),
+            ])
+            .expect("get current frame blocks failure at step 2 !");
+
+        while let Some(row) = cursor
+            .next()
+            .expect("get current frame blocks failure at step 3 !")
+        {
+            let current_frame_copy = current_frame.clone();
+            match current_frame_copy
+                .get(&PublicKey::from_base58(row[0].as_string().unwrap()).unwrap())
+            {
+                Some(blocks_count) => {
+                    if let Some(new_blocks_count) = current_frame
+                        .get_mut(&PublicKey::from_base58(row[0].as_string().unwrap()).unwrap())
+                    {
+                        *new_blocks_count = *blocks_count + 1;
+                    }
+                }
+                None => {
+                    current_frame.insert(
+                        PublicKey::from_base58(row[0].as_string().unwrap()).unwrap(),
+                        0,
+                    );
+                }
+            }
+        }
+        current_frame
+    }
+
+    pub fn compute_median_issuers_frame(&mut self, db: &DuniterDB) -> () {
+        let current_frame = self.get_current_frame(db);
+        if !current_frame.is_empty() {
+            let mut current_frame_vec: Vec<_> = current_frame.values().cloned().collect();
+            current_frame_vec.sort_unstable();
+
+            // Calculate median
+            let mut median_index = match self.block.issuers_count % 2 {
+                1 => (self.block.issuers_count / 2) + 1,
+                _ => self.block.issuers_count / 2,
+            };
+            if median_index >= self.block.issuers_count {
+                median_index = self.block.issuers_count - 1;
+            }
+            self.median_frame = current_frame_vec[median_index];
+
+            // Calculate second tiercile index
+            let mut second_tiercile_index = match self.block.issuers_count % 3 {
+                1 | 2 => (self.block.issuers_count as f64 * (2.0 / 3.0)) as usize + 1,
+                _ => (self.block.issuers_count as f64 * (2.0 / 3.0)) as usize,
+            };
+            if second_tiercile_index >= self.block.issuers_count {
+                second_tiercile_index = self.block.issuers_count - 1;
+            }
+            self.second_tiercile_frame = current_frame_vec[second_tiercile_index];
+        }
+    }
+}
diff --git a/dal/constants.rs b/dal/constants.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a35986fcd9853f13f592c16643c3b7aae14f3b9b
--- /dev/null
+++ b/dal/constants.rs
@@ -0,0 +1,48 @@
+#[derive(Debug, Copy, Clone)]
+pub struct CurrencyParametersV10 {
+    pub c: f64,
+    pub dt: i64,
+    pub ud0: i64,
+    pub sig_period: u64,
+    pub sig_stock: i64,
+    pub sig_window: i64,
+    pub sig_validity: i64,
+    pub sig_qty: i64,
+    pub idty_window: i64,
+    pub ms_window: i64,
+    pub x_percent: f64,
+    pub ms_validity: u64,
+    pub step_max: u32,
+    pub median_time_blocks: i64,
+    pub avg_gen_time: i64,
+    pub dt_diff_eval: i64,
+    pub percent_rot: f64,
+    pub ud_time0: i64,
+    pub ud_reeval_time0: i64,
+    pub dt_reeval: i64,
+}
+
+pub static G1_PARAMS: &'static CurrencyParametersV10 = &CurrencyParametersV10 {
+    c: 0.0488,
+    dt: 86_400,
+    ud0: 1_000,
+    sig_period: 432_000,
+    sig_stock: 100,
+    sig_window: 5_259_600,
+    sig_validity: 63_115_200,
+    sig_qty: 5,
+    idty_window: 5_259_600,
+    ms_window: 5_259_600,
+    x_percent: 0.8,
+    ms_validity: 31_557_600,
+    step_max: 5,
+    median_time_blocks: 24,
+    avg_gen_time: 300,
+    dt_diff_eval: 12,
+    percent_rot: 0.67,
+    ud_time0: 1_488_970_800,
+    ud_reeval_time0: 1_490_094_000,
+    dt_reeval: 15_778_800,
+};
+pub static G1_CONNECTIVITY_MAX: &'static usize = &125;
+pub static MAX_FORKS: &'static usize = &50;
diff --git a/dal/dal_event.rs b/dal/dal_event.rs
new file mode 100644
index 0000000000000000000000000000000000000000..99e41058ea4b33366263c6b7cfef62717866f303
--- /dev/null
+++ b/dal/dal_event.rs
@@ -0,0 +1,13 @@
+extern crate duniter_documents;
+extern crate serde;
+
+use self::duniter_documents::blockchain::v10::documents::BlockDocument;
+use self::duniter_documents::blockchain::BlockchainProtocol;
+
+#[derive(Debug, Clone)]
+pub enum DALEvent {
+    StackUpValidBlock(Box<BlockDocument>),
+    RevertBlocks(Vec<Box<BlockDocument>>),
+    NewValidPendingDoc(BlockchainProtocol),
+    RefusedPendingDoc(BlockchainProtocol),
+}
diff --git a/dal/dal_requests.rs b/dal/dal_requests.rs
new file mode 100644
index 0000000000000000000000000000000000000000..efd50dc2b7b821c160ccfb44552396f63b86d4b5
--- /dev/null
+++ b/dal/dal_requests.rs
@@ -0,0 +1,63 @@
+extern crate duniter_crypto;
+extern crate duniter_documents;
+extern crate duniter_module;
+extern crate serde;
+
+use self::duniter_crypto::keys::ed25519;
+use self::duniter_documents::blockchain::v10::documents::{
+    BlockDocument, CertificationDocument, IdentityDocument, MembershipDocument, RevocationDocument,
+};
+use self::duniter_documents::Hash;
+use self::duniter_module::ModuleReqFullId;
+use std::collections::HashMap;
+
+#[derive(Debug, Copy, Clone)]
+pub enum DALReqPendings {
+    AllPendingIdentyties(ModuleReqFullId, usize),
+    AllPendingIdentytiesWithoutCerts(ModuleReqFullId, usize),
+    PendingWotDatasForPubkey(ModuleReqFullId, ed25519::PublicKey),
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum DALReqBlockchain {
+    CurrentBlock(ModuleReqFullId),
+    BlockByNumber(ModuleReqFullId, u64),
+    Chunk(ModuleReqFullId, u64, usize),
+    UIDs(Vec<ed25519::PublicKey>),
+}
+
+#[derive(Debug, Clone)]
+pub enum DALRequest {
+    BlockchainRequest(DALReqBlockchain),
+    PendingsRequest(DALReqPendings),
+}
+
+#[derive(Debug, Clone)]
+pub struct PendingIdtyDatas {
+    pub idty: IdentityDocument,
+    pub memberships: Vec<MembershipDocument>,
+    pub certs_count: usize,
+    pub certs: Vec<CertificationDocument>,
+    pub revocation: Option<RevocationDocument>,
+}
+
+#[derive(Debug, Clone)]
+pub enum DALResPendings {
+    AllPendingIdentyties(HashMap<Hash, PendingIdtyDatas>),
+    AllPendingIdentytiesWithoutCerts(HashMap<Hash, PendingIdtyDatas>),
+    PendingWotDatasForPubkey(Vec<PendingIdtyDatas>),
+}
+
+#[derive(Debug, Clone)]
+pub enum DALResBlockchain {
+    CurrentBlock(ModuleReqFullId, BlockDocument),
+    BlockByNumber(ModuleReqFullId, BlockDocument),
+    Chunk(ModuleReqFullId, Vec<BlockDocument>),
+    UIDs(HashMap<ed25519::PublicKey, Option<String>>),
+}
+
+#[derive(Debug, Clone)]
+pub enum DALResponse {
+    Blockchain(DALResBlockchain),
+    Pendings(ModuleReqFullId, DALResPendings),
+}
diff --git a/dal/endpoint.rs b/dal/endpoint.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2bd5567ca2fa58578fdf66d4fe0b619aa41807b5
--- /dev/null
+++ b/dal/endpoint.rs
@@ -0,0 +1,166 @@
+extern crate crypto;
+extern crate duniter_crypto;
+extern crate sqlite;
+
+use std::time::Duration;
+
+use self::crypto::digest::Digest;
+use self::crypto::sha2::Sha256;
+use self::duniter_crypto::keys::PublicKey;
+use self::duniter_crypto::keys::ed25519::PublicKey as ed25519PublicKey;
+use super::DuniterDB;
+use super::WriteToDuniterDB;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum DALEndpointApi {
+    WS2P,
+    //WS2PS,
+    //WS2PTOR,
+    //DASA,
+    //BMA,
+    //BMAS,
+}
+
+impl From<u32> for DALEndpointApi {
+    fn from(integer: u32) -> Self {
+        match integer {
+            _ => DALEndpointApi::WS2P,
+        }
+    }
+}
+
+pub fn string_to_api(api: &str) -> Option<DALEndpointApi> {
+    match api {
+        "WS2P" => Some(DALEndpointApi::WS2P),
+        //"WS2PS" => Some(DALEndpointApi::WS2PS),
+        //"WS2PTOR" => Some(DALEndpointApi::WS2PTOR),
+        //"DASA" => Some(DALEndpointApi::DASA),
+        //"BASIC_MERKLED_API" => Some(DALEndpointApi::BMA),
+        //"BMAS" => Some(DALEndpointApi::BMAS),
+        &_ => None,
+    }
+}
+
+pub fn api_to_integer(api: &DALEndpointApi) -> i64 {
+    match *api {
+        DALEndpointApi::WS2P => 0,
+        //DALEndpointApi::WS2PS => 1,
+        //DALEndpointApi::WS2PTOR => 2,
+        //DALEndpointApi::DASA => 3,
+        //DALEndpointApi::BMA => 4,
+        //DALEndpointApi::BMAS => 5,
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct DALEndpoint {
+    pub hash_full_id: String,
+    pub status: u32,
+    pub node_id: u32,
+    pub pubkey: ed25519PublicKey,
+    pub api: DALEndpointApi,
+    pub version: usize,
+    pub endpoint: String,
+    pub last_check: u64,
+}
+
+impl DALEndpoint {
+    pub fn new(
+        status: u32,
+        node_id: u32,
+        pubkey: ed25519PublicKey,
+        api: DALEndpointApi,
+        version: usize,
+        endpoint: String,
+        last_check: Duration,
+    ) -> DALEndpoint {
+        let mut sha = Sha256::new();
+        sha.input_str(&format!(
+            "{}{}{}{}",
+            node_id,
+            pubkey,
+            api_to_integer(&api),
+            version
+        ));
+        DALEndpoint {
+            hash_full_id: sha.result_str(),
+            status,
+            node_id,
+            pubkey,
+            api,
+            version,
+            endpoint,
+            last_check: last_check.as_secs(),
+        }
+    }
+    pub fn get_endpoints_for_api(db: &DuniterDB, api: DALEndpointApi) -> Vec<DALEndpoint> {
+        let mut cursor:sqlite::Cursor = db.0
+        .prepare("SELECT hash_full_id, status, node_id, pubkey, api, version, endpoint, last_check FROM endpoints WHERE api=? ORDER BY status DESC;")
+        .expect("get_endpoints_for_api() : Error in SQL request !")
+        .cursor();
+
+        cursor
+            .bind(&[sqlite::Value::Integer(api_to_integer(&api))])
+            .expect("get_endpoints_for_api() : Error in cursor binding !");
+        let mut endpoints = Vec::new();
+        while let Some(row) = cursor
+            .next()
+            .expect("get_endpoints_for_api() : Error in cursor.next()")
+        {
+            endpoints.push(DALEndpoint {
+                hash_full_id: row[0].as_string().unwrap().to_string(),
+                status: row[1].as_integer().unwrap() as u32,
+                node_id: row[2].as_integer().unwrap() as u32,
+                pubkey: ed25519PublicKey::from_base58(row[3].as_string().unwrap()).unwrap(),
+                api: DALEndpointApi::from(row[4].as_integer().unwrap() as u32),
+                version: row[5].as_integer().unwrap() as usize,
+                endpoint: row[6].as_string().unwrap().to_string(),
+                last_check: row[7].as_integer().unwrap() as u64,
+            });
+        }
+        endpoints
+    }
+}
+
+impl WriteToDuniterDB for DALEndpoint {
+    fn write(
+        &self,
+        db: &DuniterDB,
+        _written_blockstamp: super::block_v10::BlockStampV10,
+        _written_timestamp: u64,
+    ) {
+        // Check if endpoint it's already written
+        let mut cursor: sqlite::Cursor = db.0
+            .prepare("SELECT status FROM endpoints WHERE hash_full_id=? ORDER BY status DESC;")
+            .expect("get_endpoints_for_api() : Error in SQL request !")
+            .cursor();
+        cursor
+            .bind(&[sqlite::Value::String(self.hash_full_id.clone())])
+            .expect("get_endpoints_for_api() : Error in cursor binding !");
+
+        // If endpoint it's already written, update status
+        if let Some(row) = cursor
+            .next()
+            .expect("get_endpoints_for_api() : Error in cursor.next()")
+        {
+            if row[0].as_integer().unwrap() as u32 != self.status {
+                db.0
+                    .execute(format!(
+                        "UPDATE endpoints SET status={} WHERE hash_full_id='{}'",
+                        self.status, self.hash_full_id
+                    ))
+                    .unwrap();
+            }
+        } else {
+            db.0
+            .execute(
+                format!(
+                    "INSERT INTO endpoints (hash_full_id, status, node_id, pubkey, api, version, endpoint, last_check) VALUES ('{}', {}, {}, '{}', {}, {}, '{}', {});",
+                    self.hash_full_id, self.status, self.node_id, self.pubkey.to_string(),
+                    api_to_integer(&self.api), self.version, self.endpoint, self.last_check
+                )
+            )
+            .unwrap();
+        }
+    }
+}
diff --git a/dal/identity.rs b/dal/identity.rs
new file mode 100644
index 0000000000000000000000000000000000000000..b65dc0306157f0b8e9f1f715ac9bc387d51932cb
--- /dev/null
+++ b/dal/identity.rs
@@ -0,0 +1,254 @@
+extern crate sqlite;
+
+use super::block::{blockstamp_to_timestamp, DALBlock};
+use super::DuniterDB;
+use duniter_crypto::keys::{ed25519, PublicKey, Signature};
+use duniter_documents::blockchain::v10::documents::identity::IdentityDocumentBuilder;
+use duniter_documents::blockchain::v10::documents::IdentityDocument;
+use duniter_documents::blockchain::{Document, DocumentBuilder};
+use duniter_documents::Blockstamp;
+use duniter_wotb::NodeId;
+use std::collections::HashMap;
+
+#[derive(Debug, Clone)]
+pub struct DALIdentity {
+    pub wotb_id: NodeId,
+    pub hash: String,
+    pub state: isize,
+    pub joined_on: Blockstamp,
+    pub penultimate_renewed_on: Blockstamp,
+    pub last_renewed_on: Blockstamp,
+    pub expires_on: u64,
+    pub revokes_on: u64,
+    pub expired_on: Option<Blockstamp>,
+    pub revoked_on: Option<Blockstamp>,
+    pub idty_doc: IdentityDocument,
+}
+
+impl DALIdentity {
+    pub fn exclude_identity(
+        db: &DuniterDB,
+        wotb_id: NodeId,
+        renewal_blockstamp: Blockstamp,
+        revert: bool,
+    ) {
+        let state = if revert { 0 } else { 1 };
+        let expired_on = if revert {
+            None
+        } else {
+            Some(renewal_blockstamp)
+        };
+        let mut cursor = db
+            .0
+            .prepare("UPDATE identities SET state=?, expired_on=?  WHERE wotb_id=?;")
+            .expect("Fail to exclude idty !")
+            .cursor();
+
+        cursor
+            .bind(&[
+                sqlite::Value::Integer(i64::from(state)),
+                sqlite::Value::String(
+                    expired_on
+                        .clone()
+                        .unwrap_or_else(Blockstamp::default)
+                        .to_string(),
+                ),
+                sqlite::Value::Integer(wotb_id.0 as i64),
+            ])
+            .expect("Fail to exclude idty !");
+    }
+
+    pub fn get_wotb_index(db: &DuniterDB) -> HashMap<ed25519::PublicKey, NodeId> {
+        let mut wotb_index: HashMap<ed25519::PublicKey, NodeId> = HashMap::new();
+
+        let mut cursor = db
+            .0
+            .prepare("SELECT wotb_id, pubkey FROM identities ORDER BY wotb_id ASC;")
+            .unwrap()
+            .cursor();
+
+        while let Some(row) = cursor.next().unwrap() {
+            wotb_index.insert(
+                PublicKey::from_base58(row[1].as_string().unwrap()).unwrap(),
+                NodeId(row[0].as_integer().unwrap() as usize),
+            );
+        }
+        wotb_index
+    }
+
+    pub fn create_identity(
+        db: &DuniterDB,
+        wotb_id: NodeId,
+        idty_doc: &IdentityDocument,
+        current_blockstamp: Blockstamp,
+    ) -> DALIdentity {
+        let created_on = idty_doc.blockstamp();
+        let created_time = blockstamp_to_timestamp(&created_on, &db)
+            .expect("convert blockstamp to timestamp failure !");
+
+        DALIdentity {
+            wotb_id,
+            hash: "0".to_string(),
+            state: 0,
+            joined_on: current_blockstamp,
+            penultimate_renewed_on: created_on.clone(),
+            last_renewed_on: created_on,
+            expires_on: created_time + super::constants::G1_PARAMS.ms_validity,
+            revokes_on: created_time + super::constants::G1_PARAMS.ms_validity,
+            expired_on: None,
+            revoked_on: None,
+            idty_doc: idty_doc.clone(),
+        }
+    }
+
+    pub fn revoke_identity(
+        db: &DuniterDB,
+        wotb_id: NodeId,
+        renewal_blockstamp: &Blockstamp,
+        revert: bool,
+    ) {
+        let state = if revert { 2 } else { 1 };
+        let revoked_on = if revert {
+            String::from("")
+        } else {
+            renewal_blockstamp.to_string()
+        };
+        let mut cursor = db
+            .0
+            .prepare("UPDATE identities SET state=?, revoked_on=?  WHERE wotb_id=?;")
+            .expect("Fail to exclude idty !")
+            .cursor();
+
+        cursor
+            .bind(&[
+                sqlite::Value::Integer(state),
+                sqlite::Value::String(revoked_on),
+                sqlite::Value::Integer(wotb_id.0 as i64),
+            ])
+            .expect("Fail to exclude idty !");
+    }
+
+    pub fn renewal_identity(
+        &mut self,
+        db: &DuniterDB,
+        wotb_index: &HashMap<ed25519::PublicKey, NodeId>,
+        renewal_blockstamp: &Blockstamp,
+        renawal_timestamp: u64,
+        revert: bool,
+    ) {
+        let mut penultimate_renewed_block: Option<DALBlock> = None;
+        let revert_excluding = if revert {
+            penultimate_renewed_block = Some(
+                DALBlock::get_block(
+                    self.idty_doc.currency(),
+                    db,
+                    wotb_index,
+                    &self.penultimate_renewed_on.clone(),
+                ).unwrap(),
+            );
+            penultimate_renewed_block.clone().unwrap().block.median_time
+                + super::constants::G1_PARAMS.ms_validity < renawal_timestamp
+        } else {
+            false
+        };
+        self.state = if revert && revert_excluding { 1 } else { 0 };
+        self.expires_on = if revert {
+            penultimate_renewed_block.unwrap().block.median_time
+                + super::constants::G1_PARAMS.ms_validity
+        } else {
+            renawal_timestamp + super::constants::G1_PARAMS.ms_validity
+        };
+        let mut cursor = db.0
+            .prepare(
+                "UPDATE identities SET state=?, last_renewed_on=?, expires_on=?, revokes_on=?  WHERE wotb_id=?;",
+            )
+            .expect("Fail to renewal idty !")
+            .cursor();
+
+        cursor
+            .bind(&[
+                sqlite::Value::Integer(self.state as i64),
+                sqlite::Value::String(renewal_blockstamp.to_string()),
+                sqlite::Value::Integer(self.expires_on as i64),
+                sqlite::Value::Integer(
+                    (renawal_timestamp + (super::constants::G1_PARAMS.ms_validity * 2)) as i64,
+                ),
+                sqlite::Value::Integer(self.wotb_id.0 as i64),
+            ])
+            .expect("Fail to renewal idty !");
+    }
+
+    pub fn remove_identity(db: &DuniterDB, wotb_id: NodeId) -> () {
+        db.0
+            .execute(format!(
+                "DELETE FROM identities WHERE wotb_id={}",
+                wotb_id.0
+            ))
+            .unwrap();
+    }
+
+    pub fn get_identity(currency: &str, db: &DuniterDB, wotb_id: &NodeId) -> Option<DALIdentity> {
+        let mut cursor = db
+            .0
+            .prepare(
+                "SELECT uid, pubkey, hash, sig,
+                state, created_on, joined_on, penultimate_renewed_on, last_renewed_on,
+                expires_on, revokes_on, expired_on, revoked_on FROM identities WHERE wotb_id=?;",
+            )
+            .expect("Fail to get idty !")
+            .cursor();
+
+        cursor
+            .bind(&[sqlite::Value::Integer(wotb_id.0 as i64)])
+            .expect("Fail to get idty !");
+
+        if let Some(row) = cursor.next().unwrap() {
+            let idty_doc_builder = IdentityDocumentBuilder {
+                currency,
+                username: row[0].as_string().unwrap(),
+                blockstamp: &Blockstamp::from_string(
+                    row[5]
+                        .as_string()
+                        .expect("DB Error : idty created_on invalid !"),
+                ).expect("DB Error : idty created_on invalid (2) !"),
+                issuer: &PublicKey::from_base58(row[1].as_string().unwrap()).unwrap(),
+            };
+            let idty_sig = Signature::from_base64(row[3].as_string().unwrap()).unwrap();
+            let idty_doc = idty_doc_builder.build_with_signature(vec![idty_sig]);
+
+            let expired_on = match Blockstamp::from_string(row[11].as_string().unwrap()) {
+                Ok(blockstamp) => Some(blockstamp),
+                Err(_) => None,
+            };
+            let revoked_on = match Blockstamp::from_string(row[12].as_string().unwrap()) {
+                Ok(blockstamp) => Some(blockstamp),
+                Err(_) => None,
+            };
+            Some(DALIdentity {
+                wotb_id: wotb_id.clone(),
+                hash: row[2].as_string().unwrap().to_string(),
+                state: row[4].as_integer().unwrap() as isize,
+                joined_on: Blockstamp::from_string(
+                    row[6]
+                        .as_string()
+                        .expect("DB Error : idty joined_on invalid !"),
+                ).expect("DB Error : idty joined_on invalid !"),
+                penultimate_renewed_on: Blockstamp::from_string(
+                    row[7]
+                        .as_string()
+                        .expect("DB Error : idty penultimate_renewed_on invalid !"),
+                ).expect(
+                    "DB Error : idty penultimate_renewed_on invalid (2) !",
+                ),
+                last_renewed_on: Blockstamp::from_string(row[8].as_string().unwrap()).unwrap(),
+                expires_on: row[9].as_integer().unwrap() as u64,
+                revokes_on: row[10].as_integer().unwrap() as u64,
+                expired_on,
+                revoked_on,
+                idty_doc,
+            })
+        } else {
+            None
+        }
+    }
+}
diff --git a/dal/lib.rs b/dal/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7b6eb80e0d144737018cc3fd8ba683aa828fed35
--- /dev/null
+++ b/dal/lib.rs
@@ -0,0 +1,271 @@
+//  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/>.
+
+//! Defined the few global types used by all modules,
+//! as well as the DuniterModule trait that all modules must implement.
+
+#![cfg_attr(feature = "strict", deny(warnings))]
+#![cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))]
+#![cfg_attr(feature = "exp", allow(warnings))]
+#![deny(
+    missing_debug_implementations, missing_copy_implementations, trivial_casts,
+    trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces
+)]
+
+#[macro_use]
+extern crate log;
+#[macro_use]
+extern crate serde_json;
+
+extern crate duniter_crypto;
+extern crate duniter_documents;
+extern crate duniter_wotb;
+extern crate serde;
+extern crate sqlite;
+
+pub mod block;
+pub mod constants;
+pub mod dal_event;
+pub mod dal_requests;
+pub mod identity;
+pub mod parsers;
+pub mod tools;
+pub mod writers;
+
+use duniter_crypto::keys::{ed25519, PublicKey, Signature};
+use duniter_documents::blockchain::v10::documents::BlockDocument;
+use duniter_documents::{BlockHash, BlockId, Blockstamp, Hash};
+use duniter_wotb::NodeId;
+use std::collections::HashMap;
+use std::fmt::Debug;
+use std::marker;
+use std::path::PathBuf;
+
+use self::block::DALBlock;
+
+pub struct DuniterDB(pub sqlite::Connection);
+
+impl Debug for DuniterDB {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        write!(f, "DuniterDB {{ }}")
+    }
+}
+
+pub trait FromJsonValue
+where
+    Self: marker::Sized,
+{
+    fn from_json_value(value: &serde_json::Value) -> Option<Self>;
+}
+
+pub trait WriteToDuniterDB {
+    fn write(&self, db: &DuniterDB, written_blockstamp: Blockstamp, written_timestamp: u64);
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum ForkState {
+    Free(),
+    Full(),
+    Isolate(),
+}
+
+#[derive(Debug, Clone)]
+pub struct WotState {
+    pub block_number: u32,
+    pub block_hash: String,
+    pub sentries_count: usize,
+    pub average_density: usize,
+    pub average_distance: usize,
+    pub distances: Vec<usize>,
+    pub average_connectivity: usize,
+    pub connectivities: Vec<usize>,
+    pub average_centrality: usize,
+    pub centralities: Vec<u64>,
+}
+
+fn _use_json_macro() -> serde_json::Value {
+    json!({})
+}
+
+pub fn open_db(db_path: &PathBuf, memory_mode: bool) -> Result<DuniterDB, sqlite::Error> {
+    let conn: sqlite::Connection;
+    if memory_mode || !db_path.as_path().exists() {
+        if memory_mode {
+            conn = sqlite::open(":memory:")?;
+        } else {
+            conn = sqlite::open(db_path.as_path())?;
+        }
+        //conn.execute("PRAGMA synchronous = 0;")
+        //.expect("Fail to configure SQLite DB (PRAGMA) !");
+        conn.execute(
+            "
+        CREATE TABLE wot_history (block_number INTEGER, block_hash TEXT, sentries_count INTEGER,
+            average_density INTEGER, average_distance INTEGER,
+            distances TEXT, average_connectivity INTEGER, connectivities TEXT,
+            average_centrality INTEGER, centralities TEXT);
+        CREATE TABLE blocks (fork INTEGER, isolate INTEGER, version INTEGER, nonce INTEGER, number INTEGER,
+            pow_min INTEGER, time INTEGER, median_time INTEGER, members_count INTEGER,
+            monetary_mass INTEGER, unit_base INTEGER, issuers_count INTEGER, issuers_frame INTEGER,
+            issuers_frame_var INTEGER, median_frame INTEGER, second_tiercile_frame INTEGER,
+            currency TEXT, issuer TEXT, signature TEXT, hash TEXT, previous_hash TEXT, inner_hash TEXT, dividend INTEGER, identities TEXT, joiners TEXT,
+            actives TEXT, leavers TEXT, revoked TEXT, excluded TEXT, certifications TEXT,
+            transactions TEXT);
+        CREATE TABLE identities (wotb_id INTEGER, uid TEXT, pubkey TEXT, hash TEXT, sig TEXT,
+            state INTEGER, created_on TEXT, joined_on TEXT, penultimate_renewed_on TEXT, last_renewed_on TEXT,
+            expires_on INTEGER, revokes_on INTEGER, expired_on TEXT, revoked_on TEXT);
+        CREATE TABLE certifications (pubkey_from TEXT, pubkey_to TEXT, created_on TEXT,
+            signature TEXT, written_on TEXT, expires_on INTEGER, chainable_on INTEGER);
+        ",
+        )?;
+    } else {
+        conn = sqlite::open(db_path.as_path())?;
+    }
+    Ok(DuniterDB(conn))
+}
+
+pub fn close_db(db: &DuniterDB) {
+    db.0
+        .execute("PRAGMA optimize;")
+        .expect("Fail to optimize SQLite DB !");
+}
+
+pub fn get_uid(db: &DuniterDB, wotb_id: NodeId) -> Option<String> {
+    let mut cursor: sqlite::Cursor = db
+        .0
+        .prepare("SELECT uid FROM identities WHERE wotb_id=? LIMIT 1;")
+        .expect("Request SQL get_current_block is wrong !")
+        .cursor();
+    cursor
+        .bind(&[sqlite::Value::Integer(wotb_id.0 as i64)])
+        .expect("0");
+    if let Some(row) = cursor.next().expect("fait to get_uid() : cursor error") {
+        Some(String::from(
+            row[0]
+                .as_string()
+                .expect("get_uid: Fail to parse uid field in str !"),
+        ))
+    } else {
+        None
+    }
+}
+
+pub fn new_get_current_block(db: &DuniterDB) -> Option<BlockDocument> {
+    let mut cursor: sqlite::Cursor = db.0
+        .prepare(
+            "SELECT version, nonce, number, pow_min, time, median_time, members_count, monetary_mass, unit_base, issuers_count, issuers_frame, issuers_frame_var, median_frame, second_tiercile_frame, currency, issuer, signature, hash, dividend, joiners, actives, leavers, revoked, excluded, certifications, transactions FROM blocks
+            WHERE fork=0 ORDER BY median_time DESC LIMIT ?;",
+        )
+        .expect("Request SQL get_current_block is wrong !")
+        .cursor();
+
+    cursor.bind(&[sqlite::Value::Integer(1)]).expect("0");
+    if let Some(row) = cursor.next().expect("1") {
+        let dividend = row[18].as_integer().expect("dividend");
+        let dividend = if dividend > 0 {
+            Some(dividend as usize)
+        } else {
+            None
+        };
+        return Some(BlockDocument {
+            nonce: row[1].as_integer().expect("nonce") as u64,
+            number: BlockId(row[2].as_integer().expect("2") as u32),
+            pow_min: row[3].as_integer().expect("version") as usize,
+            time: row[4].as_integer().expect("time") as u64,
+            median_time: row[5].as_integer().expect("median_time") as u64,
+            members_count: row[6].as_integer().expect("7") as usize,
+            monetary_mass: row[7].as_integer().expect("8") as usize,
+            unit_base: row[8].as_integer().expect("unit_base") as usize,
+            issuers_count: row[9].as_integer().expect("issuers_count") as usize,
+            issuers_frame: row[10].as_integer().expect("issuers_frame") as isize,
+            issuers_frame_var: row[11].as_integer().expect("issuers_frame_var") as isize,
+            currency: row[14].as_string().expect("currency").to_string(),
+            issuers: vec![PublicKey::from_base58(row[15].as_string().expect("issuer")).unwrap()],
+            signatures: vec![
+                Signature::from_base64(row[16].as_string().expect("signature")).unwrap(),
+            ],
+            hash: Some(BlockHash(
+                Hash::from_hex(row[17].as_string().expect("hash")).unwrap(),
+            )),
+            parameters: None,
+            previous_hash: Hash::default(),
+            previous_issuer: None,
+            inner_hash: None,
+            dividend,
+            identities: Vec::with_capacity(0),
+            joiners: Vec::with_capacity(0),
+            actives: Vec::with_capacity(0),
+            leavers: Vec::with_capacity(0),
+            revoked: Vec::with_capacity(0),
+            excluded: Vec::with_capacity(0),
+            certifications: Vec::with_capacity(0),
+            transactions: Vec::with_capacity(0),
+            inner_hash_and_nonce_str: String::new(),
+        });
+    }
+    None
+}
+
+pub fn get_current_block(
+    currency: &str,
+    db: &DuniterDB,
+    wotb_index: &HashMap<ed25519::PublicKey, NodeId>,
+) -> Option<DALBlock> {
+    let mut cursor: sqlite::Cursor = db
+        .0
+        .prepare("SELECT number, hash FROM blocks WHERE fork=0 ORDER BY median_time DESC LIMIT ?;")
+        .expect("Request SQL get_current_block is wrong !")
+        .cursor();
+
+    cursor.bind(&[sqlite::Value::Integer(1)]).expect("0");
+
+    if let Some(row) = cursor.next().unwrap() {
+        let blockstamp = Blockstamp {
+            id: BlockId(row[0].as_integer().unwrap() as u32),
+            hash: BlockHash(Hash::from_hex(row[1].as_string().unwrap()).unwrap()),
+        };
+        DALBlock::get_block(currency, db, wotb_index, &blockstamp)
+    } else {
+        None
+    }
+}
+
+pub fn register_wot_state(db: &DuniterDB, wot_state: &WotState) {
+    if wot_state.block_number != 1 {
+        db.0
+            .execute(format!(
+                "INSERT INTO wot_history (block_number, block_hash, sentries_count,
+                average_density, average_distance, distances,
+                average_connectivity, connectivities, average_centrality, centralities)
+                VALUES ({}, '{}', {}, {}, {}, '{}', {}, '{}', {}, '{}');",
+                wot_state.block_number,
+                wot_state.block_hash,
+                wot_state.sentries_count,
+                wot_state.average_density,
+                wot_state.average_distance,
+                serde_json::to_string(&wot_state.distances).unwrap(),
+                wot_state.average_connectivity,
+                serde_json::to_string(&wot_state.connectivities).unwrap(),
+                wot_state.average_centrality,
+                serde_json::to_string(&wot_state.centralities).unwrap(),
+            ))
+            .unwrap();
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum BlockchainError {
+    UnexpectedBlockNumber(),
+    UnknowError(),
+}
diff --git a/dal/parsers/blocks.rs b/dal/parsers/blocks.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e78ce51adb90701374d846cd4b3812839d117e45
--- /dev/null
+++ b/dal/parsers/blocks.rs
@@ -0,0 +1,110 @@
+extern crate duniter_crypto;
+extern crate duniter_documents;
+extern crate duniter_network;
+extern crate serde_json;
+
+use self::duniter_network::{NetworkBlock, NetworkBlockV10};
+use super::excluded::parse_exclusions_from_json_value;
+use super::identities::parse_compact_identity;
+use super::transactions::parse_transaction;
+use duniter_crypto::keys::{PublicKey, Signature};
+use duniter_documents::blockchain::v10::documents::BlockDocument;
+use duniter_documents::{BlockHash, BlockId, Hash};
+
+pub fn parse_json_block(source: &serde_json::Value) -> Option<NetworkBlock> {
+    let number = BlockId(source.get("number")?.as_u64()? as u32);
+    let currency = source.get("currency")?.as_str()?.to_string();
+    let issuer = match PublicKey::from_base58(source.get("issuer")?.as_str()?) {
+        Ok(pubkey) => pubkey,
+        Err(_) => return None,
+    };
+    let sig = match Signature::from_base64(source.get("signature")?.as_str()?) {
+        Ok(sig) => sig,
+        Err(_) => return None,
+    };
+    let hash = match Hash::from_hex(source.get("hash")?.as_str()?) {
+        Ok(hash) => hash,
+        Err(_) => return None,
+    };
+    let previous_hash = match source.get("previousHash")?.as_str() {
+        Some(hash_str) => match Hash::from_hex(hash_str) {
+            Ok(hash) => hash,
+            Err(_) => return None,
+        },
+        None => if number.0 > 0 {
+            return None;
+        } else {
+            Hash::default()
+        },
+    };
+    let previous_issuer = match source.get("previousIssuer")?.as_str() {
+        Some(pubkey_str) => match PublicKey::from_base58(pubkey_str) {
+            Ok(pubkey) => Some(pubkey),
+            Err(_) => return None,
+        },
+        None => if number.0 > 0 {
+            return None;
+        } else {
+            None
+        },
+    };
+    let inner_hash = match Hash::from_hex(source.get("inner_hash")?.as_str()?) {
+        Ok(hash) => Some(hash),
+        Err(_) => return None,
+    };
+    let dividend = match source.get("dividend")?.as_u64() {
+        Some(dividend) => Some(dividend as usize),
+        None => None,
+    };
+    let mut identities = Vec::new();
+    for raw_idty in source.get("identities")?.as_array()? {
+        identities.push(parse_compact_identity(&currency, &raw_idty)?);
+    }
+    let mut transactions = Vec::new();
+    for json_tx in source.get("transactions")?.as_array()? {
+        transactions.push(parse_transaction("g1", &json_tx)?);
+    }
+    let block_doc = BlockDocument {
+        nonce: source.get("nonce")?.as_i64()? as u64,
+        number: BlockId(source.get("number")?.as_u64()? as u32),
+        pow_min: source.get("powMin")?.as_u64()? as usize,
+        time: source.get("time")?.as_u64()?,
+        median_time: source.get("medianTime")?.as_u64()?,
+        members_count: source.get("membersCount")?.as_u64()? as usize,
+        monetary_mass: source.get("monetaryMass")?.as_u64()? as usize,
+        unit_base: source.get("unitbase")?.as_u64()? as usize,
+        issuers_count: source.get("issuersCount")?.as_u64()? as usize,
+        issuers_frame: source.get("issuersFrame")?.as_i64()? as isize,
+        issuers_frame_var: source.get("issuersFrameVar")?.as_i64()? as isize,
+        currency,
+        issuers: vec![issuer],
+        signatures: vec![sig],
+        hash: Some(BlockHash(hash)),
+        parameters: None,
+        previous_hash,
+        previous_issuer,
+        inner_hash,
+        dividend,
+        identities,
+        joiners: Vec::with_capacity(0),
+        actives: Vec::with_capacity(0),
+        leavers: Vec::with_capacity(0),
+        revoked: Vec::with_capacity(0),
+        excluded: parse_exclusions_from_json_value(&source.get("excluded")?.as_array()?),
+        certifications: Vec::with_capacity(0),
+        transactions,
+        inner_hash_and_nonce_str: format!(
+            "InnerHash: {}\nNonce: {}\n",
+            inner_hash.unwrap().to_hex(),
+            source.get("nonce")?.as_u64()?
+        ),
+    };
+    Some(NetworkBlock::V10(Box::new(NetworkBlockV10 {
+        uncompleted_block_doc: block_doc,
+        joiners: source.get("joiners")?.as_array()?.clone(),
+        actives: source.get("actives")?.as_array()?.clone(),
+        leavers: source.get("leavers")?.as_array()?.clone(),
+        revoked: source.get("revoked")?.as_array()?.clone(),
+        certifications: source.get("certifications")?.as_array()?.clone(),
+    })))
+}
diff --git a/dal/parsers/certifications.rs b/dal/parsers/certifications.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ee395afd0df1ee54bc60ac4d8ee2ddb8eea020ab
--- /dev/null
+++ b/dal/parsers/certifications.rs
@@ -0,0 +1,97 @@
+extern crate serde;
+extern crate serde_json;
+extern crate sqlite;
+
+use super::super::block::DALBlock;
+use super::super::identity::DALIdentity;
+use super::super::DuniterDB;
+use duniter_crypto::keys::{ed25519, PublicKey, Signature};
+use duniter_documents::blockchain::v10::documents::certification::CertificationDocumentBuilder;
+use duniter_documents::blockchain::v10::documents::{CertificationDocument, IdentityDocument};
+use duniter_documents::blockchain::{Document, DocumentBuilder};
+use duniter_documents::{BlockHash, BlockId, Blockstamp, Hash};
+use duniter_wotb::NodeId;
+use std::collections::HashMap;
+
+pub fn parse_certifications_from_json_value(
+    currency: &str,
+    db: &DuniterDB,
+    wotb_index: &HashMap<ed25519::PublicKey, NodeId>,
+    block_identities: &HashMap<ed25519::PublicKey, IdentityDocument>,
+    array_certifications: &[serde_json::Value],
+) -> Vec<CertificationDocument> {
+    let mut certifications: Vec<CertificationDocument> = Vec::new();
+    for certification in array_certifications.iter() {
+        let certification_datas: Vec<&str> = certification.as_str().unwrap().split(':').collect();
+        if certification_datas.len() == 4 {
+            let target = PublicKey::from_base58(certification_datas[1])
+                .expect("Fail to parse cert target !");
+            let target_idty_doc: IdentityDocument = match block_identities.get(&target) {
+                Some(idty_doc) => idty_doc.clone(),
+                None => {
+                    let target_wotb_id = wotb_index.get(&target).expect(&format!(
+                        "target identity {} not found in wotb index !",
+                        target.to_string()
+                    ));
+                    let dal_idty = DALIdentity::get_identity(currency, db, target_wotb_id)
+                        .expect("target identity not found in bdd !");
+                    dal_idty.idty_doc
+                }
+            };
+            let cert_blockstamp_id = BlockId(
+                certification_datas[2]
+                    .parse()
+                    .expect("Fail to parse cert blockstamp !"),
+            );
+            let cert_builder =
+                CertificationDocumentBuilder {
+                    currency,
+                    issuer: &PublicKey::from_base58(certification_datas[0])
+                        .expect("Fail to parse cert issuer !"),
+                    blockstamp: &Blockstamp {
+                        id: cert_blockstamp_id,
+                        hash: if cert_blockstamp_id == BlockId(0) {
+                            BlockHash(Hash::from_hex(
+                            "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
+                        ).unwrap())
+                        } else {
+                            DALBlock::get_block_hash(db, &cert_blockstamp_id).expect(&format!(
+                                "Fatal Error : Block {} not found in bdd !",
+                                cert_blockstamp_id
+                            ))
+                        },
+                    },
+                    target: &target,
+                    identity_username: target_idty_doc.username(),
+                    identity_blockstamp: &target_idty_doc.blockstamp(),
+                    identity_sig: &target_idty_doc.signatures()[0],
+                };
+            let cert_sig =
+                Signature::from_base64(certification_datas[3]).expect("Fail to parse cert sig !");
+            certifications.push(cert_builder.build_with_signature(vec![cert_sig]));
+        }
+    }
+    certifications
+}
+
+pub fn parse_certifications(
+    currency: &str,
+    db: &DuniterDB,
+    wotb_index: &HashMap<ed25519::PublicKey, NodeId>,
+    block_identities: &HashMap<ed25519::PublicKey, IdentityDocument>,
+    json_datas: &str,
+) -> Option<Vec<CertificationDocument>> {
+    let raw_certifications: serde_json::Value = serde_json::from_str(json_datas).unwrap();
+
+    if raw_certifications.is_array() {
+        Some(parse_certifications_from_json_value(
+            currency,
+            db,
+            wotb_index,
+            block_identities,
+            raw_certifications.as_array().unwrap(),
+        ))
+    } else {
+        None
+    }
+}
diff --git a/dal/parsers/excluded.rs b/dal/parsers/excluded.rs
new file mode 100644
index 0000000000000000000000000000000000000000..329261da4fe5a876d6d751945b53ef1d3bd8d505
--- /dev/null
+++ b/dal/parsers/excluded.rs
@@ -0,0 +1,26 @@
+extern crate serde;
+extern crate serde_json;
+
+use duniter_crypto::keys::{ed25519, PublicKey};
+
+pub fn parse_exclusions(json_datas: &str) -> Option<Vec<ed25519::PublicKey>> {
+    let raw_exclusions: serde_json::Value = serde_json::from_str(json_datas).unwrap();
+
+    if raw_exclusions.is_array() {
+        Some(parse_exclusions_from_json_value(
+            raw_exclusions.as_array().unwrap(),
+        ))
+    } else {
+        None
+    }
+}
+
+pub fn parse_exclusions_from_json_value(
+    array_exclusions: &[serde_json::Value],
+) -> Vec<ed25519::PublicKey> {
+    let mut exclusions: Vec<ed25519::PublicKey> = Vec::new();
+    for exclusion in array_exclusions.iter() {
+        exclusions.push(PublicKey::from_base58(exclusion.as_str().unwrap()).unwrap());
+    }
+    exclusions
+}
diff --git a/dal/parsers/identities.rs b/dal/parsers/identities.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9791d4c0f5045d08ce499709ee79857c1676f6c2
--- /dev/null
+++ b/dal/parsers/identities.rs
@@ -0,0 +1,102 @@
+extern crate serde_json;
+extern crate sqlite;
+
+use duniter_crypto::keys::{PublicKey, Signature};
+use duniter_documents::blockchain::v10::documents::identity::IdentityDocumentBuilder;
+use duniter_documents::blockchain::v10::documents::IdentityDocument;
+use duniter_documents::blockchain::DocumentBuilder;
+use duniter_documents::Blockstamp;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum IdentityParseError {
+    WrongFormat(),
+}
+
+pub fn parse_identities(currency: &str, json_datas: &str) -> Option<Vec<IdentityDocument>> {
+    let raw_idties: serde_json::Value = serde_json::from_str(json_datas).unwrap();
+    if raw_idties.is_array() {
+        return Some(
+            parse_identities_from_json_value(currency, raw_idties.as_array().unwrap())
+                .iter()
+                .map(|i| {
+                    i.clone()
+                        .expect("Fatal error : Fail to parse identity from local DB !")
+                })
+                .collect(),
+        );
+    }
+    None
+}
+
+pub fn parse_identities_from_json_value(
+    currency: &str,
+    array_identities: &[serde_json::Value],
+) -> Vec<Result<IdentityDocument, IdentityParseError>> {
+    array_identities
+        .iter()
+        .map(|idty| {
+            let idty_datas: Vec<&str> = idty.as_str().unwrap().split(':').collect();
+            if idty_datas.len() == 4 {
+                let idty_doc_builder = IdentityDocumentBuilder {
+                    currency,
+                    issuer: &PublicKey::from_base58(idty_datas[0]).unwrap(),
+                    blockstamp: &Blockstamp::from_string(idty_datas[2]).unwrap(),
+                    username: idty_datas[3],
+                };
+                let idty_sig = Signature::from_base64(idty_datas[1]).unwrap();
+                //memberships.push(membership_doc_builder.build_with_signature(vec![membership_sig]));
+                Ok(idty_doc_builder.build_with_signature(vec![idty_sig]))
+            } else {
+                Err(IdentityParseError::WrongFormat())
+            }
+        })
+        .collect()
+
+    /*for membership in array_memberships.iter() {
+        let membership_datas: Vec<&str> = membership.as_str().unwrap().split(':').collect();
+        if membership_datas.len() == 5 {
+            let membership_doc_builder = IdentityDocumentBuilder {
+                currency,
+                issuer: &PublicKey::from_base58(membership_datas[0]).unwrap(),
+                blockstamp: &Blockstamp::from_string(membership_datas[2]).unwrap(),
+                membership: membership_type,
+                identity_username: membership_datas[4],
+                identity_blockstamp: &Blockstamp::from_string(membership_datas[3]).unwrap(),
+            };
+            let membership_sig = Signature::from_base64(membership_datas[1]).unwrap();
+            memberships.push(membership_doc_builder.build_with_signature(vec![membership_sig]));
+        }
+    }
+    memberships*/
+}
+
+pub fn parse_compact_identity(
+    currency: &str,
+    source: &serde_json::Value,
+) -> Option<IdentityDocument> {
+    if source.is_string() {
+        let idty_elements: Vec<&str> = source.as_str().unwrap().split(':').collect();
+        let issuer = match PublicKey::from_base58(idty_elements[0]) {
+            Ok(pubkey) => pubkey,
+            Err(_) => return None,
+        };
+        let signature = match Signature::from_base64(idty_elements[1]) {
+            Ok(sig) => sig,
+            Err(_) => return None,
+        };
+        let blockstamp = match Blockstamp::from_string(idty_elements[2]) {
+            Ok(blockstamp) => blockstamp,
+            Err(_) => return None,
+        };
+        let username = idty_elements[3];
+        let idty_doc_builder = IdentityDocumentBuilder {
+            currency,
+            username,
+            blockstamp: &blockstamp,
+            issuer: &issuer,
+        };
+        Some(idty_doc_builder.build_with_signature(vec![signature]))
+    } else {
+        None
+    }
+}
diff --git a/dal/parsers/memberships.rs b/dal/parsers/memberships.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8db1a052ec09720219c62fefef64f77f6529444a
--- /dev/null
+++ b/dal/parsers/memberships.rs
@@ -0,0 +1,66 @@
+extern crate serde_json;
+extern crate sqlite;
+
+use duniter_crypto::keys::{PublicKey, Signature};
+use duniter_documents::blockchain::v10::documents::membership::{
+    MembershipDocumentBuilder, MembershipType,
+};
+use duniter_documents::blockchain::v10::documents::MembershipDocument;
+use duniter_documents::blockchain::DocumentBuilder;
+use duniter_documents::Blockstamp;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum MembershipParseError {
+    WrongFormat(),
+}
+
+pub fn parse_memberships(
+    currency: &str,
+    membership_type: MembershipType,
+    json_datas: &str,
+) -> Option<Vec<MembershipDocument>> {
+    let raw_memberships: serde_json::Value = serde_json::from_str(json_datas).unwrap();
+    if raw_memberships.is_array() {
+        return Some(
+            parse_memberships_from_json_value(
+                currency,
+                membership_type,
+                raw_memberships.as_array().unwrap(),
+            ).iter()
+                .map(|m| {
+                    m.clone()
+                        .expect("Fatal error : Fail to parse membership from local DB !")
+                })
+                .collect(),
+        );
+    }
+    None
+}
+
+pub fn parse_memberships_from_json_value(
+    currency: &str,
+    membership_type: MembershipType,
+    array_memberships: &[serde_json::Value],
+) -> Vec<Result<MembershipDocument, MembershipParseError>> {
+    //let memberships: Vec<MembershipDocument> = Vec::new();
+    array_memberships
+        .iter()
+        .map(|membership| {
+            let membership_datas: Vec<&str> = membership.as_str().unwrap().split(':').collect();
+            if membership_datas.len() == 5 {
+                let membership_doc_builder = MembershipDocumentBuilder {
+                    currency,
+                    issuer: &PublicKey::from_base58(membership_datas[0]).unwrap(),
+                    blockstamp: &Blockstamp::from_string(membership_datas[2]).unwrap(),
+                    membership: membership_type,
+                    identity_username: membership_datas[4],
+                    identity_blockstamp: &Blockstamp::from_string(membership_datas[3]).unwrap(),
+                };
+                let membership_sig = Signature::from_base64(membership_datas[1]).unwrap();
+                Ok(membership_doc_builder.build_with_signature(vec![membership_sig]))
+            } else {
+                Err(MembershipParseError::WrongFormat())
+            }
+        })
+        .collect()
+}
diff --git a/dal/parsers/mod.rs b/dal/parsers/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..49a98a57d01502f01c3412b2cbd6e5643ef8e049
--- /dev/null
+++ b/dal/parsers/mod.rs
@@ -0,0 +1,132 @@
+pub mod blocks;
+pub mod certifications;
+pub mod excluded;
+pub mod identities;
+pub mod memberships;
+pub mod revoked;
+pub mod transactions;
+
+#[cfg(test)]
+mod tests {
+    use super::transactions::*;
+    use duniter_crypto::keys::{PublicKey, Signature};
+    use duniter_documents::blockchain::v10::documents::transaction::*;
+    use duniter_documents::blockchain::DocumentBuilder;
+    use duniter_documents::Blockstamp;
+
+    #[test]
+    fn parse_json_tx() {
+        let tx_json = json!({
+            "version": 10,
+            "currency": "g1",
+            "locktime": 0,
+            "hash": "3424206EF64C69E5F8C3906AAE571E378A498FCDAE0B85E9405A5205D7148EFE",
+            "blockstamp": "112533-000002150F2E805E604D9B31212D079570AAD8D3A4D8BB75F2C15A94A345B6B1",
+            "blockstampTime": 0,
+            "issuers": [
+                "51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2"
+            ],
+            "inputs": [
+                "1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496"
+            ],
+            "outputs": [
+                "1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)"
+            ],
+            "unlocks": [
+                "0:SIG(0)"
+            ],
+            "signatures": [
+                "5olrjFylTCsVq8I5Yr7FpXeviynICyvIwe1yG5N0RJF+VZb+bCFBnLAMpmMCU2qzUvK7z41UXOrMRybXiLa2Dw=="
+            ],
+            "comment": "Merci pour la calligraphie ;) de Liam"
+        });
+
+        let tx_builder = TransactionDocumentBuilder {
+            currency: "g1",
+            blockstamp: &Blockstamp::from_string(
+                "112533-000002150F2E805E604D9B31212D079570AAD8D3A4D8BB75F2C15A94A345B6B1",
+            ).unwrap(),
+            locktime: &0,
+            issuers: &vec![
+                PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2").unwrap(),
+            ],
+            inputs: &vec![
+                TransactionInput::parse_from_str(
+                    "1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496",
+                ).unwrap(),
+            ],
+            outputs: &vec![
+                TransactionOutput::parse_from_str(
+                    "1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)",
+                ).unwrap(),
+            ],
+            unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()],
+            comment: "Merci pour la calligraphie ;) de Liam",
+        };
+
+        assert_eq!(
+            parse_transaction("g1", &tx_json).expect("Fail to parse transaction !"),
+            tx_builder.build_with_signature(vec![Signature::from_base64("5olrjFylTCsVq8I5Yr7FpXeviynICyvIwe1yG5N0RJF+VZb+bCFBnLAMpmMCU2qzUvK7z41UXOrMRybXiLa2Dw==").unwrap()])
+        );
+    }
+
+    #[test]
+    fn parse_json_tx2() {
+        let tx_json = json!({
+            "version": 10,
+            "currency": "g1",
+            "locktime": 0,
+            "hash": "F98BF7A8BF82E76F5B69E70CEF0A07A08BFDB03561955EC57B254DB1E958529C",
+            "blockstamp": "58-00005B9167EBA1E32C6EAD42AE7F72D8F14B765D3C9E47D233B553D47C5AEE0C",
+            "blockstampTime": 1488990541,
+            "issuers": [
+                "FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD"
+            ],
+            "inputs": [
+                "1000:0:D:FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD:1"
+            ],
+            "outputs": [
+                "3:0:SIG(7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz)",
+                "997:0:SIG(FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD)"
+            ],
+            "unlocks": [
+                "0:SIG(0)"
+            ],
+            "signatures": [
+                "VWbvsiybM4L2X5+o+6lIiuKNw5KrD1yGZqmV+lHtA28XoRUFzochSIgfoUqBsTAaYEHY45vSX917LDXudTEzBg=="
+            ],
+            "comment": "Un petit cafe ;-)"
+        });
+
+        let tx_builder = TransactionDocumentBuilder {
+            currency: "g1",
+            blockstamp: &Blockstamp::from_string(
+                "58-00005B9167EBA1E32C6EAD42AE7F72D8F14B765D3C9E47D233B553D47C5AEE0C",
+            ).unwrap(),
+            locktime: &0,
+            issuers: &vec![
+                PublicKey::from_base58("FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD").unwrap(),
+            ],
+            inputs: &vec![
+                TransactionInput::parse_from_str(
+                    "1000:0:D:FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD:1",
+                ).unwrap(),
+            ],
+            outputs: &vec![
+                TransactionOutput::parse_from_str(
+                    "3:0:SIG(7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz)",
+                ).unwrap(),
+                TransactionOutput::parse_from_str(
+                    "997:0:SIG(FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD)",
+                ).unwrap(),
+            ],
+            unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()],
+            comment: "Un petit cafe ;-)",
+        };
+
+        assert_eq!(
+            parse_transaction("g1", &tx_json).expect("Fail to parse transaction !"),
+            tx_builder.build_with_signature(vec![Signature::from_base64("VWbvsiybM4L2X5+o+6lIiuKNw5KrD1yGZqmV+lHtA28XoRUFzochSIgfoUqBsTAaYEHY45vSX917LDXudTEzBg==").unwrap()])
+        );
+    }
+}
diff --git a/dal/parsers/revoked.rs b/dal/parsers/revoked.rs
new file mode 100644
index 0000000000000000000000000000000000000000..dc24d1b2d1df5a3cba065d6b8ea8baec13dedcd5
--- /dev/null
+++ b/dal/parsers/revoked.rs
@@ -0,0 +1,69 @@
+extern crate serde_json;
+
+use duniter_crypto::keys::{ed25519, PublicKey, Signature};
+use duniter_documents::blockchain::v10::documents::revocation::RevocationDocumentBuilder;
+use duniter_documents::blockchain::v10::documents::{IdentityDocument, RevocationDocument};
+use duniter_documents::blockchain::{Document, DocumentBuilder};
+use duniter_wotb::NodeId;
+
+use super::super::identity::DALIdentity;
+use super::super::DuniterDB;
+
+use std::collections::HashMap;
+
+pub fn parse_revocations(
+    currency: &str,
+    db: &DuniterDB,
+    wotb_index: &HashMap<ed25519::PublicKey, NodeId>,
+    block_identities: &HashMap<ed25519::PublicKey, IdentityDocument>,
+    json_datas: &str,
+) -> Option<Vec<RevocationDocument>> {
+    let raw_certifications: serde_json::Value = serde_json::from_str(json_datas).unwrap();
+
+    if raw_certifications.is_array() {
+        Some(parse_revocations_from_json_value(
+            currency,
+            db,
+            wotb_index,
+            block_identities,
+            raw_certifications.as_array().unwrap(),
+        ))
+    } else {
+        None
+    }
+}
+
+pub fn parse_revocations_from_json_value(
+    currency: &str,
+    db: &DuniterDB,
+    wotb_index: &HashMap<ed25519::PublicKey, NodeId>,
+    block_identities: &HashMap<ed25519::PublicKey, IdentityDocument>,
+    array_revocations: &[serde_json::Value],
+) -> Vec<RevocationDocument> {
+    let mut revocations: Vec<RevocationDocument> = Vec::new();
+    for revocation in array_revocations.iter() {
+        let revocations_datas: Vec<&str> = revocation.as_str().unwrap().split(':').collect();
+        if revocations_datas.len() == 2 {
+            let idty_pubkey: ed25519::PublicKey =
+                PublicKey::from_base58(revocations_datas[0]).unwrap();
+            let idty_doc: IdentityDocument = match block_identities.get(&idty_pubkey) {
+                Some(idty_doc) => idty_doc.clone(),
+                None => {
+                    let idty_wotb_id = wotb_index.get(&idty_pubkey).unwrap();
+                    let dal_idty = DALIdentity::get_identity(currency, db, idty_wotb_id).unwrap();
+                    dal_idty.idty_doc
+                }
+            };
+            let revoc_doc_builder = RevocationDocumentBuilder {
+                currency,
+                issuer: &idty_pubkey,
+                identity_username: idty_doc.username(),
+                identity_blockstamp: &idty_doc.blockstamp(),
+                identity_sig: &idty_doc.signatures()[0],
+            };
+            let revoc_sig = Signature::from_base64(revocations_datas[1]).unwrap();
+            revocations.push(revoc_doc_builder.build_with_signature(vec![revoc_sig]));
+        }
+    }
+    revocations
+}
diff --git a/dal/parsers/transactions.rs b/dal/parsers/transactions.rs
new file mode 100644
index 0000000000000000000000000000000000000000..75146df4b1f32e6b842c6024616c1dd35dfbcb3d
--- /dev/null
+++ b/dal/parsers/transactions.rs
@@ -0,0 +1,233 @@
+extern crate serde;
+extern crate serde_json;
+
+use duniter_crypto::keys::{PublicKey, Signature};
+use duniter_documents::blockchain::v10::documents::transaction::{
+    TransactionDocument, TransactionDocumentBuilder, TransactionInput, TransactionInputUnlocks,
+    TransactionOutput,
+};
+use duniter_documents::blockchain::DocumentBuilder;
+use duniter_documents::Blockstamp;
+
+pub fn parse_compact_transactions(
+    currency: &str,
+    json_datas: &str,
+) -> Option<Vec<TransactionDocument>> {
+    let raw_transactions: serde_json::Value =
+        serde_json::from_str(json_datas).expect("Fatal error : fail to jsonifie tx from DB !");
+
+    if raw_transactions.is_array() {
+        let mut transactions = Vec::new();
+        for transaction in raw_transactions.as_array().unwrap() {
+            let transaction_lines: Vec<&str> = transaction
+                .as_str()
+                .expect("Fail to parse tx from DB !")
+                .split('$')
+                .collect();
+            let tx_headers: Vec<&str> = transaction_lines[0].split(':').collect();
+            let issuers_count = tx_headers[2]
+                .parse()
+                .expect("Fail to parse tx header NB_ISSUERS !");
+            let inputs_count = tx_headers[3]
+                .parse()
+                .expect("Fail to parse tx header NB_INPUTS !");
+            let unlocks_count = tx_headers[4]
+                .parse()
+                .expect("Fail to parse tx header NB_UNLOCKS !");
+            let outputs_count = tx_headers[5]
+                .parse()
+                .expect("Fail to parse tx header NB_OUTPUTS !");
+            let has_comment: usize = tx_headers[6]
+                .parse()
+                .expect("Fail to parse tx header HAS_COMMENT !");
+            let locktime = tx_headers[7]
+                .parse()
+                .expect("Fail to parse tx header LOCKTIME !");
+            let blockstamp = Blockstamp::from_string(transaction_lines[1])
+                .expect("Fail to parse tx BLOCKSTAMP !");
+            let mut line = 2;
+            let mut issuers = Vec::new();
+            for _ in 0..issuers_count {
+                issuers.push(
+                    PublicKey::from_base58(transaction_lines[line])
+                        .expect("Fail to parse tx issuer !"),
+                );
+                line += 1;
+            }
+            let mut inputs = Vec::new();
+            for _ in 0..inputs_count {
+                inputs.push(
+                    TransactionInput::parse_from_str(transaction_lines[line])
+                        .expect("Fail to parse tx issuer !"),
+                );
+                line += 1;
+            }
+            let mut unlocks = Vec::new();
+            for _ in 0..unlocks_count {
+                unlocks.push(
+                    TransactionInputUnlocks::parse_from_str(transaction_lines[line])
+                        .expect("Fail to parse tx issuer !"),
+                );
+                line += 1;
+            }
+            let mut outputs = Vec::new();
+            for _ in 0..outputs_count {
+                outputs.push(
+                    TransactionOutput::parse_from_str(transaction_lines[line])
+                        .expect("Fail to parse tx issuer !"),
+                );
+                line += 1;
+            }
+            let mut comment = "";
+            if has_comment == 1 {
+                comment = transaction_lines[line];
+                line += 1;
+            }
+            let mut signatures = Vec::new();
+            for _ in 0..issuers_count {
+                signatures.push(
+                    Signature::from_base64(transaction_lines[line])
+                        .expect("Fail to parse tx signature !"),
+                );
+                line += 1;
+            }
+            let tx_doc_builder = TransactionDocumentBuilder {
+                currency,
+                blockstamp: &blockstamp,
+                locktime: &locktime,
+                issuers: &issuers,
+                inputs: &inputs,
+                unlocks: &unlocks,
+                outputs: &outputs,
+                comment,
+            };
+            transactions.push(tx_doc_builder.build_with_signature(signatures));
+        }
+        Some(transactions)
+    } else {
+        None
+    }
+}
+
+pub fn parse_transaction(
+    currency: &str,
+    source: &serde_json::Value,
+) -> Option<TransactionDocument> {
+    //debug!("transaction={:#?}", source);
+    let blockstamp = match Blockstamp::from_string(source.get("blockstamp")?.as_str()?) {
+        Ok(blockstamp) => blockstamp,
+        Err(_) => {
+            return None;
+        }
+    };
+    let locktime = source.get("locktime")?.as_i64()? as u64;
+    let issuers_array = source.get("issuers")?.as_array()?;
+    let mut issuers = Vec::with_capacity(issuers_array.len());
+    for issuer in issuers_array {
+        match PublicKey::from_base58(issuer.as_str()?) {
+            Ok(pubkey) => issuers.push(pubkey),
+            Err(_) => {
+                return None;
+            }
+        }
+    }
+    let inputs_array = source.get("inputs")?.as_array()?;
+    let mut inputs = Vec::with_capacity(inputs_array.len());
+    for input in inputs_array {
+        let input_str = input.as_str()?;
+        match TransactionInput::parse_from_str(input_str) {
+            Ok(input) => inputs.push(input),
+            Err(_) => {
+                return None;
+            }
+        }
+    }
+    let unlocks_array = source.get("unlocks")?.as_array()?;
+    let mut unlocks = Vec::with_capacity(unlocks_array.len());
+    for unlock in unlocks_array {
+        match TransactionInputUnlocks::parse_from_str(unlock.as_str()?) {
+            Ok(unlock) => unlocks.push(unlock),
+            Err(_) => {
+                return None;
+            }
+        }
+    }
+    let outputs_array = source.get("outputs")?.as_array()?;
+    let mut outputs = Vec::with_capacity(outputs_array.len());
+    for output in outputs_array {
+        match TransactionOutput::parse_from_str(output.as_str()?) {
+            Ok(output) => outputs.push(output),
+            Err(_) => {
+                return None;
+            }
+        }
+    }
+    let signatures_array = source.get("signatures")?.as_array()?;
+    let mut signatures = Vec::with_capacity(signatures_array.len());
+    for signature in signatures_array {
+        match Signature::from_base64(signature.as_str()?) {
+            Ok(signature) => signatures.push(signature),
+            Err(_) => {
+                return None;
+            }
+        }
+    }
+    let comment = source.get("comment")?.as_str()?;
+
+    let tx_doc_builder = TransactionDocumentBuilder {
+        currency,
+        blockstamp: &blockstamp,
+        locktime: &locktime,
+        issuers: &issuers,
+        inputs: &inputs,
+        unlocks: &unlocks,
+        outputs: &outputs,
+        comment,
+    };
+    Some(tx_doc_builder.build_with_signature(signatures))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn parse_compact_tx() {
+        let compact_txs = "[\"TX:10:1:1:1:1:1:0$\
+112533-000002150F2E805E604D9B31212D079570AAD8D3A4D8BB75F2C15A94A345B6B1$\
+51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2$\
+1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496$\
+0:SIG(0)$\
+1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)$\
+Merci pour la calligraphie ;) de Liam$\
+5olrjFylTCsVq8I5Yr7FpXeviynICyvIwe1yG5N0RJF+VZb+bCFBnLAMpmMCU2qzUvK7z41UXOrMRybXiLa2Dw==\"]";
+
+        let tx_builder = TransactionDocumentBuilder {
+            currency: "g1",
+            blockstamp: &Blockstamp::from_string(
+                "112533-000002150F2E805E604D9B31212D079570AAD8D3A4D8BB75F2C15A94A345B6B1",
+            ).unwrap(),
+            locktime: &0,
+            issuers: &vec![
+                PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2").unwrap(),
+            ],
+            inputs: &vec![
+                TransactionInput::parse_from_str(
+                    "1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496",
+                ).unwrap(),
+            ],
+            outputs: &vec![
+                TransactionOutput::parse_from_str(
+                    "1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)",
+                ).unwrap(),
+            ],
+            unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()],
+            comment: "Merci pour la calligraphie ;) de Liam",
+        };
+
+        assert_eq!(
+            parse_compact_transactions("g1", compact_txs).expect("Fail to parse compact transactions !"),
+            vec![tx_builder.build_with_signature(vec![Signature::from_base64("5olrjFylTCsVq8I5Yr7FpXeviynICyvIwe1yG5N0RJF+VZb+bCFBnLAMpmMCU2qzUvK7z41UXOrMRybXiLa2Dw==").unwrap()])]
+        );
+    }
+}
diff --git a/dal/test.db b/dal/test.db
new file mode 100644
index 0000000000000000000000000000000000000000..ab254abc64c4f280bdde96b863cdc6420fddff67
Binary files /dev/null and b/dal/test.db differ
diff --git a/dal/tools.rs b/dal/tools.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9a4ecee0aa5f649b94ccd172c0eee2d326659533
--- /dev/null
+++ b/dal/tools.rs
@@ -0,0 +1,137 @@
+extern crate duniter_wotb;
+
+use duniter_wotb::operations::centrality::{
+    CentralitiesCalculator, UlrikBrandesCentralityCalculator,
+};
+use duniter_wotb::operations::distance::{
+    DistanceCalculator, RustyDistanceCalculator, WotDistance, WotDistanceParameters,
+};
+use duniter_wotb::operations::path::{PathFinder, RustyPathFinder};
+use duniter_wotb::{NodeId, WebOfTrust};
+
+pub static CENTRALITY_CALCULATOR: UlrikBrandesCentralityCalculator =
+    UlrikBrandesCentralityCalculator {};
+pub static DISTANCE_CALCULATOR: RustyDistanceCalculator = RustyDistanceCalculator {};
+pub static PATH_FINDER: RustyPathFinder = RustyPathFinder {};
+
+pub fn get_sentry_requirement(members_count: usize, step_max: u32) -> u32 {
+    match step_max {
+        5 => {
+            if members_count < 33 {
+                2
+            } else if members_count < 244 {
+                3
+            } else if members_count < 1025 {
+                4
+            } else if members_count < 3126 {
+                5
+            } else if members_count < 7777 {
+                6
+            } else {
+                panic!("get_sentry_requirement not define for members_count greater than 7777 !");
+            }
+        }
+        _ => panic!("get_sentry_requirement not define for step_max != 5 !"),
+    }
+}
+
+pub fn calculate_average_density<T: WebOfTrust>(wot: &T) -> usize {
+    let enabled_members = wot.get_enabled();
+    let enabled_members_count = enabled_members.len();
+    let mut count_actives_links: usize = 0;
+    for member in &enabled_members {
+        count_actives_links += wot.issued_count(*member).unwrap();
+    }
+    ((count_actives_links as f32 / enabled_members_count as f32) * 1_000.0) as usize
+}
+
+pub fn compute_distances<T: WebOfTrust + Sync>(
+    wot: &T,
+    sentry_requirement: u32,
+    step_max: u32,
+    x_percent: f64,
+) -> (usize, Vec<usize>, usize, Vec<usize>) {
+    let members_count = wot.get_enabled().len();
+    let mut distances = Vec::new();
+    let mut average_distance: usize = 0;
+    let mut connectivities = Vec::new();
+    let mut average_connectivity: usize = 0;
+    for i in 0..wot.size() {
+        let distance_datas: WotDistance = DISTANCE_CALCULATOR
+            .compute_distance(
+                wot,
+                WotDistanceParameters {
+                    node: NodeId(i),
+                    sentry_requirement,
+                    step_max,
+                    x_percent,
+                },
+            )
+            .expect("Fatal Error: compute_distance return None !");
+        let mut distance = ((f64::from(distance_datas.success)
+            / (x_percent * f64::from(distance_datas.sentries))) * 100.0)
+            as usize;
+        distances.push(distance);
+        average_distance += distance;
+        let mut connectivity =
+            ((f64::from(distance_datas.success - distance_datas.success_at_border)
+                / (x_percent * f64::from(distance_datas.sentries))) * 100.0) as usize;
+        connectivities.push(connectivity);
+        average_connectivity += connectivity;
+    }
+    average_distance /= members_count;
+    average_connectivity /= members_count;
+    (
+        average_distance,
+        distances,
+        average_connectivity,
+        connectivities,
+    )
+}
+
+pub fn calculate_distance_stress_centralities<T: WebOfTrust>(wot: &T, step_max: u32) -> Vec<u64> {
+    CENTRALITY_CALCULATOR.distance_stress_centralities(wot, step_max as usize)
+}
+
+pub fn calculate_centralities_degree<T: WebOfTrust>(wot: &T, step_max: u32) -> Vec<usize> {
+    let wot_size = wot.size();
+    let members_count = wot.get_enabled().len() as u64;
+    let oriented_couples_count: u64 = members_count * (members_count - 1);
+    let mut centralities: Vec<u64> = vec![0; wot_size];
+    for i in 0..wot_size {
+        for j in 0..wot_size {
+            let mut paths = PATH_FINDER.find_paths(wot, NodeId(i), NodeId(j), step_max);
+            if paths.is_empty() {
+                break;
+            }
+            //paths.sort_unstable_by(|a, b| a.len().cmp(&b.len()));
+            let shortest_path_len = paths[0].len();
+            let mut intermediate_members: Vec<NodeId> = Vec::new();
+            if shortest_path_len > 2 {
+                for path in paths {
+                    //if path.len() == shortest_path_len {
+                    for node_id in &path {
+                        if !intermediate_members.contains(node_id) {
+                            intermediate_members.push(*node_id);
+                        }
+                    }
+                    /*} else {
+                        break;
+                    }*/
+                }
+            }
+            let centralities_copy = centralities.clone();
+            for node_id in intermediate_members {
+                let centrality = &centralities_copy[node_id.0];
+                if let Some(tmp) = centralities.get_mut(node_id.0) {
+                    *tmp = *centrality + 1;
+                }
+            }
+        }
+    }
+    let mut relative_centralities = Vec::with_capacity(wot_size);
+    for centrality in centralities {
+        relative_centralities.push((centrality * 100_000 / oriented_couples_count) as usize);
+    }
+    relative_centralities
+}
diff --git a/dal/writers/block.rs b/dal/writers/block.rs
new file mode 100644
index 0000000000000000000000000000000000000000..906dbdfe6a55b372548f6641753bb0de94548260
--- /dev/null
+++ b/dal/writers/block.rs
@@ -0,0 +1,77 @@
+extern crate duniter_crypto;
+extern crate duniter_documents;
+extern crate duniter_wotb;
+extern crate serde;
+extern crate serde_json;
+extern crate sqlite;
+
+use self::duniter_documents::blockchain::v10::documents::BlockDocument;
+use self::duniter_documents::blockchain::Document;
+use super::super::block::DALBlock;
+use super::super::DuniterDB;
+
+pub fn write_network_block(
+    db: &DuniterDB,
+    block: &BlockDocument,
+    fork: usize,
+    isolate: bool,
+    joiners: &Vec<serde_json::Value>,
+    actives: &Vec<serde_json::Value>,
+    leavers: &Vec<serde_json::Value>,
+    revoked: &Vec<serde_json::Value>,
+    certifications: &Vec<serde_json::Value>,
+) {
+    db.0
+        .execute(
+            format!("INSERT INTO blocks (fork, isolate, version, nonce, number, pow_min, time, median_time, members_count, monetary_mass, unit_base, issuers_count, issuers_frame, issuers_frame_var, currency, issuer, signature, hash, previous_hash, inner_hash, dividend, identities, joiners, actives, leavers, revoked, excluded, certifications, transactions) VALUES ({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, '{}', '{}', '{}', '{}', '{}', '{}', {}, '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}');",
+                fork, if isolate { 1 } else { 0 }, 10,
+                block.nonce, block.number, block.pow_min, block.time, block.median_time,
+                block.members_count, block.monetary_mass, block.unit_base, block.issuers_count,
+                block.issuers_frame, block.issuers_frame_var, block.currency, block.issuers[0],
+                block.signatures[0].to_string(), block.hash.unwrap().0.to_string(),
+                block.previous_hash.to_string(), block.inner_hash.unwrap().to_string(),
+                block.dividend.unwrap_or(0),
+                serde_json::to_string(&block.identities).unwrap(),
+                serde_json::to_string(joiners).unwrap(), serde_json::to_string(actives).unwrap(),
+                serde_json::to_string(leavers).unwrap(), serde_json::to_string(revoked).unwrap(),
+                serde_json::to_string(&block.excluded).unwrap(), serde_json::to_string(certifications).unwrap(),
+                serde_json::to_string(&block.transactions).unwrap()
+            ))
+        .unwrap();
+}
+
+pub fn write(db: &DuniterDB, block: &BlockDocument, fork: usize, isolate: bool) {
+    let mut insert = true;
+    if fork == 0 {
+        if let Some(_fork) = DALBlock::get_block_fork(db, &block.blockstamp()) {
+            insert = false;
+            db.0
+                .execute(format!(
+                    "UPDATE blocks SET fork=0 WHERE number={} AND hash='{}';",
+                    block.number,
+                    block.hash.unwrap().0.to_string()
+                ))
+                .unwrap();
+        }
+    }
+
+    if insert {
+        db.0
+            .execute(
+                format!("INSERT INTO blocks (fork, isolate, version, nonce, number, pow_min, time, median_time, members_count, monetary_mass, unit_base, issuers_count, issuers_frame, issuers_frame_var, currency, issuer, signature, hash, previous_hash, inner_hash, dividend, identities, joiners, actives, leavers, revoked, excluded, certifications, transactions) VALUES ({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, '{}', '{}', '{}', '{}', '{}', '{}', {}, '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}');",
+                    fork, if isolate { 1 } else { 0 }, 10,
+                    block.nonce, block.number, block.pow_min, block.time, block.median_time,
+                    block.members_count, block.monetary_mass, block.unit_base, block.issuers_count,
+                    block.issuers_frame, block.issuers_frame_var, block.currency, block.issuers[0],
+                    block.signatures[0].to_string(), block.hash.unwrap().0.to_string(),
+                    block.previous_hash.to_string(), block.inner_hash.unwrap().to_string(),
+                    block.dividend.unwrap_or(0), serde_json::to_string(&block.identities).unwrap(),
+                    serde_json::to_string(&block.joiners).unwrap(), serde_json::to_string(&block.actives).unwrap(),
+                    serde_json::to_string(&block.leavers).unwrap(), serde_json::to_string(&block.revoked).unwrap(),
+                    serde_json::to_string(&block.excluded).unwrap(), serde_json::to_string(&block.certifications).unwrap(),
+                    serde_json::to_string(&block.transactions).unwrap()
+                ),
+            )
+            .unwrap();
+    }
+}
diff --git a/dal/writers/certification.rs b/dal/writers/certification.rs
new file mode 100644
index 0000000000000000000000000000000000000000..511c776612dba820ca59d7e7860580cba3b703a2
--- /dev/null
+++ b/dal/writers/certification.rs
@@ -0,0 +1,53 @@
+extern crate serde;
+extern crate serde_json;
+extern crate sqlite;
+
+use super::super::DuniterDB;
+use duniter_crypto::keys::ed25519;
+use duniter_documents::blockchain::v10::documents::CertificationDocument;
+use duniter_documents::blockchain::Document;
+use duniter_documents::Blockstamp;
+
+pub fn write_certification(
+    cert: &CertificationDocument,
+    db: &DuniterDB,
+    written_blockstamp: Blockstamp,
+    written_timestamp: u64,
+) {
+    let mut cursor = db
+        .0
+        .prepare("SELECT median_time FROM blocks WHERE number=? AND fork=0 LIMIT 1;")
+        .unwrap()
+        .cursor();
+
+    cursor
+        .bind(&[sqlite::Value::Integer(cert.blockstamp().id.0 as i64)])
+        .expect("convert blockstamp to timestamp failure at step 1 !");
+
+    let mut created_timestamp: i64 = 0;
+    if let Some(row) = cursor
+        .next()
+        .expect("convert blockstamp to timestamp failure at step 2 !")
+    {
+        created_timestamp = row[0].as_integer().unwrap();
+    }
+
+    db.0
+        .execute(
+            format!("INSERT INTO certifications (pubkey_from, pubkey_to, created_on, signature, written_on, expires_on, chainable_on) VALUES ('{}', '{}', '{}', '{}', '{}', {}, {});",
+                cert.issuers()[0], cert.target(), cert.blockstamp().id.0, cert.signatures()[0],
+                written_blockstamp.to_string(),
+                created_timestamp+super::super::constants::G1_PARAMS.sig_validity,
+                written_timestamp+super::super::constants::G1_PARAMS.sig_period
+            ))
+        .unwrap();
+}
+
+pub fn remove_certification(from: ed25519::PublicKey, to: ed25519::PublicKey, db: &DuniterDB) {
+    db.0
+        .execute(format!(
+            "DELETE FROM certifications WHERE pubkey_from={} AND pubkey_to={}",
+            from, to
+        ))
+        .unwrap();
+}
diff --git a/dal/writers/identity.rs b/dal/writers/identity.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c000d945cabfc3edf74f155dad765dad2b925d48
--- /dev/null
+++ b/dal/writers/identity.rs
@@ -0,0 +1,34 @@
+extern crate sqlite;
+
+use super::super::identity::DALIdentity;
+use super::super::DuniterDB;
+use duniter_documents::blockchain::Document;
+use duniter_documents::Blockstamp;
+
+pub fn write(
+    idty: &DALIdentity,
+    db: &DuniterDB,
+    _written_blockstamp: Blockstamp,
+    _written_timestamp: u64,
+) {
+    let expired_on = match idty.expired_on {
+        Some(ref tmp) => tmp.to_string(),
+        None => String::from(""),
+    };
+    let revoked_on = match idty.revoked_on {
+        Some(ref tmp) => tmp.to_string(),
+        None => String::from(""),
+    };
+    db.0
+        .execute(
+            format!("INSERT INTO identities (wotb_id, uid, pubkey, hash, sig, state, created_on, joined_on, penultimate_renewed_on, last_renewed_on, expires_on, revokes_on, expired_on, revoked_on) VALUES ({}, '{}', '{}', '{}', '{}', {}, '{}', '{}', '{}', '{}', {}, {}, '{}', '{}');",
+                idty.wotb_id.0, idty.idty_doc.username(), idty.idty_doc.issuers()[0], idty.hash,
+                idty.idty_doc.signatures()[0], idty.state,
+                idty.idty_doc.blockstamp().to_string(),
+                idty.joined_on.to_string(),
+                idty.penultimate_renewed_on.to_string(),
+                idty.last_renewed_on.to_string(),
+                idty.expires_on, idty.revokes_on, expired_on, revoked_on
+            ))
+        .unwrap();
+}
diff --git a/dal/writers/mod.rs b/dal/writers/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..41219969b14c6d6fc9368ea0e3eb77513d41ebd6
--- /dev/null
+++ b/dal/writers/mod.rs
@@ -0,0 +1,3 @@
+pub mod block;
+pub mod certification;
+pub mod identity;