diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/config/ConfigurationOption.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/config/ConfigurationOption.java
index 0c743f172a73522e526ccae233a17ab9121f8cec..53c2de687dd2bb1383c793ba42d20358def6fe07 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/config/ConfigurationOption.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/config/ConfigurationOption.java
@@ -84,7 +84,7 @@ public enum ConfigurationOption implements ConfigOptionDef {
     SITE_URL(
             "duniter4j.site.url",
             n("duniter4j.config.option.site.url.description"),
-            "http://ucoin.io/duniter4j",
+            "https://github.com/duniter/duniter4j",
             URL.class),
 
     ORGANIZATION_NAME(
@@ -143,14 +143,14 @@ public enum ConfigurationOption implements ConfigOptionDef {
     NODE_HOST(
             "duniter4j.node.host",
             n("duniter4j.config.option.node.host.description"),
-            "metab.ucoin.io",
+            "cgeek.fr",
             String.class,
             false),
 
     NODE_PORT(
             "duniter4j.node.port",
             n("duniter4j.config.option.node.port.description"),
-            "9201",
+            "9330",
             Integer.class,
             false),
 
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java
index 4f1bcd236bf23ffc7c45816bcc8e93ded73300e6..ac6e2f870ad5658a62ff92098be699e95962d5aa 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java
@@ -29,6 +29,7 @@ import org.duniter.core.client.model.bma.Error;
 import org.duniter.core.client.model.bma.gson.GsonUtils;
 import org.duniter.core.client.model.local.Peer;
 import org.duniter.core.client.service.exception.HttpBadRequestException;
+import org.duniter.core.client.service.exception.HttpNotFoundException;
 import org.duniter.core.client.service.exception.JsonSyntaxException;
 import org.duniter.core.client.service.exception.PeerConnectionException;
 import org.duniter.core.exception.TechnicalException;
@@ -190,6 +191,8 @@ public class HttpServiceImpl implements HttpService, Closeable, InitializingBean
                 case HttpStatus.SC_UNAUTHORIZED:
                 case HttpStatus.SC_FORBIDDEN:
                     throw new TechnicalException(I18n.t("duniter4j.client.authentication"));
+                case HttpStatus.SC_NOT_FOUND:
+                    throw new HttpNotFoundException(I18n.t("duniter4j.client.notFound", request.toString()));
                 case HttpStatus.SC_BAD_REQUEST:
                     try {
                         Error error = (Error)parseResponse(response, Error.class);
@@ -199,7 +202,7 @@ public class HttpServiceImpl implements HttpService, Closeable, InitializingBean
                         throw new HttpBadRequestException(I18n.t("duniter4j.client.status", response.getStatusLine().toString()));
                     }
                 default:
-                    throw new TechnicalException(I18n.t("duniter4j.client.status", response.getStatusLine().toString()));
+                    throw new TechnicalException(I18n.t("duniter4j.client.status", request.toString(), response.getStatusLine().toString()));
             }
         }
         catch (ConnectException e) {
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java
index a272f1d6ee8bee382fa71a36ba0f2079ed24418e..8516a025b3929591f7e9bf43885e61af042843ed 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java
@@ -30,6 +30,7 @@ import org.duniter.core.client.model.bma.BlockchainParameters;
 import org.duniter.core.client.model.local.Currency;
 import org.duniter.core.client.model.local.Peer;
 import org.duniter.core.client.model.local.Wallet;
+import org.duniter.core.client.service.exception.BlockNotFoundException;
 import org.duniter.core.client.service.exception.PubkeyAlreadyUsedException;
 import org.duniter.core.client.service.exception.UidAlreadyUsedException;
 import org.duniter.core.client.service.exception.UidMatchAnotherPubkeyException;
@@ -71,7 +72,7 @@ public interface BlockchainRemoteService extends Service {
      * @param number
      * @return
      */
-    BlockchainBlock getBlock(long currencyId, long number);
+    BlockchainBlock getBlock(long currencyId, long number) throws BlockNotFoundException;
 
     /**
      * Retrieve the dividend of a block, by id (from 0 to current).
@@ -81,7 +82,7 @@ public interface BlockchainRemoteService extends Service {
      * @param number
      * @return
      */
-    Long getBlockDividend(long currencyId, long number);
+    Long getBlockDividend(long currencyId, long number) throws BlockNotFoundException;
 
     /**
      * Retrieve a block, by id (from 0 to current)
@@ -90,7 +91,7 @@ public interface BlockchainRemoteService extends Service {
      * @param number the block number
      * @return
      */
-    BlockchainBlock getBlock(Peer peer, int number);
+    BlockchainBlock getBlock(Peer peer, int number) throws BlockNotFoundException;
 
     /**
      * Retrieve a block, by id (from 0 to current) as JSON string
@@ -99,7 +100,7 @@ public interface BlockchainRemoteService extends Service {
      * @param number the block number
      * @return
      */
-    String getBlockAsJson(Peer peer, int number);
+    String getBlockAsJson(Peer peer, int number) throws BlockNotFoundException;
 
     /**
      * Retrieve a block, by id (from 0 to current) as JSON string
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java
index 3fd751cd93defc0231fa3588d7341c15ca44d93a..490b3548b2bc62095896da73d4c37777d706ae3d 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java
@@ -32,10 +32,7 @@ import org.duniter.core.client.model.local.Identity;
 import org.duniter.core.client.model.local.Peer;
 import org.duniter.core.client.model.local.Wallet;
 import org.duniter.core.client.service.ServiceLocator;
-import org.duniter.core.client.service.exception.HttpBadRequestException;
-import org.duniter.core.client.service.exception.PubkeyAlreadyUsedException;
-import org.duniter.core.client.service.exception.UidAlreadyUsedException;
-import org.duniter.core.client.service.exception.UidMatchAnotherPubkeyException;
+import org.duniter.core.client.service.exception.*;
 import org.duniter.core.exception.TechnicalException;
 import org.duniter.core.service.CryptoService;
 import org.duniter.core.util.ObjectUtils;
@@ -143,35 +140,51 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
     }
 
     @Override
-    public BlockchainBlock getBlock(long currencyId, long number) {
-        // get blockchain parameter
+    public BlockchainBlock getBlock(long currencyId, long number) throws BlockNotFoundException  {
         String path = String.format(URL_BLOCK, number);
-        BlockchainBlock result = executeRequest(currencyId, path, BlockchainBlock.class);
-        return result;
+        try {
+            return executeRequest(currencyId, path, BlockchainBlock.class);
+        }
+        catch(HttpNotFoundException e) {
+            throw new BlockNotFoundException(String.format("Block #%s not found", number));
+        }
     }
 
     @Override
-    public Long getBlockDividend(long currencyId, long number) {
-        // get blockchain parameter
+    public Long getBlockDividend(long currencyId, long number) throws BlockNotFoundException {
         String path = String.format(URL_BLOCK, number);
-        String json = executeRequest(currencyId, path, String.class);
-        return getDividendFromBlockJson(json);
+        try {
+            String json = executeRequest(currencyId, path, String.class);
+            return getDividendFromBlockJson(json);
+        }
+        catch(HttpNotFoundException e) {
+            throw new BlockNotFoundException(String.format("Block #%s not found", number));
+        }
     }
 
 
     @Override
-    public BlockchainBlock getBlock(Peer peer, int number) {
-        // get blockchain parameter
+    public BlockchainBlock getBlock(Peer peer, int number) throws BlockNotFoundException {
+        // Get block from number
         String path = String.format(URL_BLOCK, number);
-        BlockchainBlock result = executeRequest(peer, path, BlockchainBlock.class);
-        return result;
+        try {
+            return executeRequest(peer, path, BlockchainBlock.class);
+        }
+        catch(HttpNotFoundException e) {
+            throw new BlockNotFoundException(String.format("Block #%s not found on peer [%s]", number, peer));
+        }
     }
 
     @Override
     public String getBlockAsJson(Peer peer, int number) {
         // get blockchain parameter
         String path = String.format(URL_BLOCK, number);
-        return executeRequest(peer, path, String.class);
+        try {
+            return executeRequest(peer, path, String.class);
+        }
+        catch(HttpNotFoundException e) {
+            throw new BlockNotFoundException(String.format("Block #%s not found on peer [%s]", number, peer));
+        }
     }
 
     @Override
@@ -278,6 +291,7 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
             throw new TechnicalException("Unable to get last UD from server");
         }
         return lastUD.longValue();
+
     }
 
     /**
@@ -424,8 +438,7 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
 
         // search blockchain membership
         try {
-            BlockchainMemberships result = executeRequest(currencyId, path, BlockchainMemberships.class);
-            return result;
+            return executeRequest(currencyId, path, BlockchainMemberships.class);
         } catch (HttpBadRequestException e) {
             log.debug("No member matching this pubkey or uid: " + uidOrPubkey);
             return null;
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/BlockNotFoundException.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/BlockNotFoundException.java
new file mode 100644
index 0000000000000000000000000000000000000000..6d9ec1ec33c3292716522b69d1975102a9648a87
--- /dev/null
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/BlockNotFoundException.java
@@ -0,0 +1,49 @@
+package org.duniter.core.client.service.exception;
+
+/*
+ * #%L
+ * UCoin Java :: Core Client API
+ * %%
+ * Copyright (C) 2014 - 2016 EIS
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program.  If not, see
+ * <http://www.gnu.org/licenses/gpl-3.0.html>.
+ * #L%
+ */
+
+import org.duniter.core.exception.BusinessException;
+
+/**
+ * Created by eis on 11/02/15.
+ */
+public class BlockNotFoundException extends BusinessException {
+
+    private static final long serialVersionUID = -5260280401104018980L;
+
+    public BlockNotFoundException() {
+        super();
+    }
+
+    public BlockNotFoundException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public BlockNotFoundException(String message) {
+        super(message);
+    }
+
+    public BlockNotFoundException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/HttpNotFoundException.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/HttpNotFoundException.java
new file mode 100644
index 0000000000000000000000000000000000000000..3aeaaa6f0702fd30934160c74c19a93279de486f
--- /dev/null
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/HttpNotFoundException.java
@@ -0,0 +1,49 @@
+package org.duniter.core.client.service.exception;
+
+/*
+ * #%L
+ * UCoin Java :: Core Client API
+ * %%
+ * Copyright (C) 2014 - 2016 EIS
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program.  If not, see
+ * <http://www.gnu.org/licenses/gpl-3.0.html>.
+ * #L%
+ */
+
+import org.duniter.core.exception.BusinessException;
+
+/**
+ * Created by eis on 11/02/15.
+ */
+public class HttpNotFoundException extends BusinessException {
+
+    private static final long serialVersionUID = -5260280401104018980L;
+
+    public HttpNotFoundException() {
+        super();
+    }
+
+    public HttpNotFoundException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public HttpNotFoundException(String message) {
+        super(message);
+    }
+
+    public HttpNotFoundException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_en_GB.properties b/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_en_GB.properties
index 944871b69c621d834800ffc13805b16b8b4d6e39..248b16f292e44931725b5969f49819a380a6fd16 100644
--- a/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_en_GB.properties
+++ b/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_en_GB.properties
@@ -3,6 +3,7 @@ duniter4j.client.core.connect=Could not connect to Duniter node [%s]
 duniter4j.client.core.emptyResponse=
 duniter4j.client.core.invalidResponse=
 duniter4j.client.core.timeout=
+duniter4j.client.notFound=Resource non found [%s]
 duniter4j.client.status=Http request error\: %s
 duniter4j.config=
 duniter4j.config.option.basedir.description=
diff --git a/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_fr_FR.properties b/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_fr_FR.properties
index 150dd8c9320d407d81893f712dc79ee0b982919f..94c99f6ee34f8adbe9bfbbd48e1b9e1d6d36607f 100644
--- a/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_fr_FR.properties
+++ b/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_fr_FR.properties
@@ -3,7 +3,8 @@ duniter4j.client.core.connect=Echec de la connection au noeud Duniter [%s]
 duniter4j.client.core.emptyResponse=
 duniter4j.client.core.invalidResponse=
 duniter4j.client.core.timeout=
-duniter4j.client.status=Echec de requete HTTP \: %s
+duniter4j.client.notFound=Ressource non trouvée [%s]
+duniter4j.client.status=Echec de requete HTTP [%s] \: %s
 duniter4j.config=
 duniter4j.config.option.basedir.description=
 duniter4j.config.option.cache.directory.description=
diff --git a/duniter4j-core-shared/src/main/java/org/duniter/core/model/NullProgressionModel.java b/duniter4j-core-shared/src/main/java/org/duniter/core/model/NullProgressionModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..6eafb6c4596d0b1a0ca1ad85fd1bbb9311e54433
--- /dev/null
+++ b/duniter4j-core-shared/src/main/java/org/duniter/core/model/NullProgressionModel.java
@@ -0,0 +1,113 @@
+package org.duniter.core.model;
+
+/*
+ * #%L
+ * SIH-Adagio :: Synchro Server WebApp
+ * $Id:$
+ * $HeadURL:$
+ * %%
+ * Copyright (C) 2012 - 2014 Ifremer
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program.  If not, see
+ * <http://www.gnu.org/licenses/gpl-3.0.html>.
+ * #L%
+ */
+
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.Serializable;
+
+public class NullProgressionModel implements ProgressionModel, Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    public NullProgressionModel() {
+        super();
+    }
+
+    @Override
+    public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
+    }
+
+    @Override
+    public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+    }
+
+    @Override
+    public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
+    }
+
+    @Override
+    public synchronized String getMessage() {
+        return null;
+    }
+
+    @Override
+    public synchronized void setTask(String task) {
+    }
+
+    @Override
+    public synchronized String getTask() {
+        return null;
+    }
+
+    @Override
+    public synchronized void setMessage(String progressionMessage) {
+    }
+
+    @Override
+    public synchronized void setTotal(int total) {
+    }
+
+    @Override
+    public int getTotal() {
+        return 0;
+    }
+
+    @Override
+    public synchronized void setCurrent(int current) {
+    }
+
+    @Override
+    public synchronized int getCurrent() {
+        return 0;
+    }
+
+    @Override
+    public synchronized void increment() {}
+
+    @Override
+    public synchronized void increment(int increment){}
+
+    @Override
+    public synchronized void increment(String message) {}
+
+    public boolean isCancel() {
+        return false;
+    }
+
+    @Override
+    public void cancel() {}
+
+    @Override
+    public synchronized Status getStatus() {
+        return null;
+    }
+
+    @Override
+    public synchronized void setStatus(Status progressionStatus) {
+    }
+
+}
diff --git a/duniter4j-elasticsearch/pom.xml b/duniter4j-elasticsearch/pom.xml
index 201c5b8bf965dd32fe6668a4fb1d2758b66316d6..8473fcda6b98c9777a0bfa879054024fbd04d018 100644
--- a/duniter4j-elasticsearch/pom.xml
+++ b/duniter4j-elasticsearch/pom.xml
@@ -27,7 +27,7 @@
     <duniter4j-elasticsearch.config>${project.basedir}/src/test/resources/duniter4j-elasticsearch-test.properties</duniter4j-elasticsearch.config>
 
     <assembly.skip>false</assembly.skip>
-    <cesium.download.url>https://github.com/duniter/cesium/releases/download/${cesium.version}/cesium-web-${cesium.version}.zip</cesium.download.url>
+    <cesium.download.url>https://github.com/duniter/cesium/releases/download/v${cesium.version}/cesium-v${cesium.version}-web.zip</cesium.download.url>
   </properties>
 
   <dependencies>
@@ -393,7 +393,9 @@
                 <phase>integration-test</phase>
                 <configuration>
                   <mainClass>org.elasticsearch.bootstrap.Elasticsearch</mainClass>
-                  <arguments>start</arguments>
+                  <arguments>
+                    <argument>start</argument>
+                  </arguments>
                   <includeProjectDependencies>false</includeProjectDependencies>
                   <includePluginDependencies>true</includePluginDependencies>
                   <systemProperties>
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/Plugin.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/Plugin.java
index 73c9f28828c61d45042be5776da28a9bbb1deff3..c660a140240b0230ea2346329904291616842f6e 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/Plugin.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/Plugin.java
@@ -25,9 +25,9 @@ package org.duniter.elasticsearch;
 import com.google.common.collect.Lists;
 import org.duniter.elasticsearch.action.RestModule;
 import org.duniter.elasticsearch.node.DuniterNode;
-import org.duniter.elasticsearch.threadpool.ThreadPool;
 import org.duniter.elasticsearch.security.SecurityModule;
 import org.duniter.elasticsearch.service.ServiceModule;
+import org.duniter.elasticsearch.threadpool.ThreadPool;
 import org.elasticsearch.common.component.LifecycleComponent;
 import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.inject.Module;
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/PluginSettings.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/PluginSettings.java
index 1c9d46517ae630cf8fa0c1e34285999dc598691a..9590391789b7eeadd6c7c4b44b293802a72ba436 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/PluginSettings.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/PluginSettings.java
@@ -161,6 +161,10 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> {
         return settings.getAsInt("duniter.bulk.size", 1000);
     }
 
+    public int getNodeForkResyncWindow() {
+        return settings.getAsInt("duniter.fork.resync.window", 100);
+    }
+
     public String getDefaultStringAnalyzer() {
         return settings.get("duniter.string.analyzer", "english");
     }
@@ -181,6 +185,14 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> {
         return settings.getAsBoolean("duniter.dev.enable", false);
     }
 
+    public int getNodeRetryCount() {
+        return settings.getAsInt("duniter.retry.count", 5);
+    }
+
+    public int getNodeRetryWaitDuration() {
+        return settings.getAsInt("duniter.retry.waitDuration", 5000);
+    }
+
     public Peer checkAndGetPeer() {
         if (StringUtils.isBlank(getNodeBmaHost())) {
             logger.error("ERROR: node host is required");
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/cli/action/IndexerCliAction.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/cli/action/IndexerCliAction.java
index b79bda9f63376edc6011ef5ebef48e46142f1538..5220383c2343d76ebfad5c27917241646449a6dd 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/cli/action/IndexerCliAction.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/cli/action/IndexerCliAction.java
@@ -51,7 +51,7 @@ public class IndexerCliAction {
                         @Override
                         public void handleMessage(String message) {
                             String currencyName = GsonUtils.getValueFromJSONAsString(message, "blockchain");
-                            *///blockIndexerService.indexBlockAsJson(peer, message, true /*refresh*/, true /*wait*/);
+                            *///blockIndexerService.indexLastBlockFromJson(peer, message, true /*refresh*/, true /*wait*/);
                             //blockIndexerService.indexCurrentBlockAsJson(currencyName, message, true /*wait*/);
                /*         }
                     });
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/exception/InvalidFormatException.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/exception/InvalidFormatException.java
index 4d47e5141b06ff7678ebc3f211e3f819f55a5cb0..f55ff99d9432fe907d50531b23bf972d901c9cd2 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/exception/InvalidFormatException.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/exception/InvalidFormatException.java
@@ -22,7 +22,6 @@ package org.duniter.elasticsearch.exception;
  * #L%
  */
 
-import org.duniter.core.exception.BusinessException;
 import org.elasticsearch.rest.RestStatus;
 
 /**
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/node/DuniterNode.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/node/DuniterNode.java
index 80be1d95cea2f3afb2fceae8b4330c6ae52505f7..842a505ff8cdbb5ebce3acbcd21192d0b8ff3a32 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/node/DuniterNode.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/node/DuniterNode.java
@@ -30,9 +30,13 @@ import org.duniter.core.util.websocket.WebsocketClientEndpoint;
 import org.duniter.elasticsearch.PluginSettings;
 import org.duniter.elasticsearch.service.*;
 import org.duniter.elasticsearch.threadpool.ThreadPool;
+import org.elasticsearch.action.admin.indices.stats.ShardStats;
+import org.elasticsearch.cluster.health.ClusterHealthStatus;
 import org.elasticsearch.common.component.AbstractLifecycleComponent;
 import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.inject.Injector;
+import org.elasticsearch.common.logging.ESLogger;
+import org.elasticsearch.common.logging.Loggers;
 import org.elasticsearch.common.settings.Settings;
 
 /**
@@ -43,6 +47,7 @@ public class DuniterNode extends AbstractLifecycleComponent<DuniterNode> {
     private final PluginSettings pluginSettings;
     private final ThreadPool threadPool;
     private final Injector injector;
+    private final static ESLogger logger = Loggers.getLogger("node");
 
     @Inject
     public DuniterNode(Settings settings, PluginSettings pluginSettings, ThreadPool threadPool, final Injector injector) {
@@ -50,16 +55,18 @@ public class DuniterNode extends AbstractLifecycleComponent<DuniterNode> {
         this.pluginSettings = pluginSettings;
         this.threadPool = threadPool;
         this.injector = injector;
-
     }
 
     @Override
     protected void doStart() {
-        threadPool.scheduleOnStarted(() -> {
+        threadPool.scheduleOnClusterHealthStatus(() -> {
             createIndices();
 
-            synchronize();
-        });
+            // Waiting cluster back to GREEN or YELLOW state, before synchronize
+            threadPool.scheduleOnClusterHealthStatus(() -> {
+                synchronize();
+            }, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN);
+        }, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN);
     }
 
     @Override
@@ -106,7 +113,6 @@ public class DuniterNode extends AbstractLifecycleComponent<DuniterNode> {
             if (logger.isInfoEnabled()) {
                 logger.info("Checking Duniter indices...");
             }
-
             injector.getInstance(RegistryService.class).createIndexIfNotExists();
             injector.getInstance(MarketService.class).createIndexIfNotExists();
             injector.getInstance(MessageService.class).createIndexIfNotExists();
@@ -129,7 +135,7 @@ public class DuniterNode extends AbstractLifecycleComponent<DuniterNode> {
 
             // Index blocks (and listen if new block appear)
             injector.getInstance(BlockchainService.class)
-                    //.indexLastBlocks(peer)
+                    .indexLastBlocks(peer)
                     .listenAndIndexNewBlock(peer);
 
         }
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/AbstractService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/AbstractService.java
index 3ffc3aae4aba7e3e5517839bad1df7a015c971da..ab820f0760d1c97daaa325f75e622332d1eaa7f9 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/AbstractService.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/AbstractService.java
@@ -30,6 +30,7 @@ import com.google.common.collect.ImmutableSet;
 import com.google.gson.JsonSyntaxException;
 import org.duniter.core.beans.Bean;
 import org.duniter.core.client.model.elasticsearch.Record;
+import org.duniter.core.client.service.exception.HttpBadRequestException;
 import org.duniter.core.exception.TechnicalException;
 import org.duniter.core.service.CryptoService;
 import org.duniter.core.util.StringUtils;
@@ -47,16 +48,15 @@ import org.elasticsearch.action.get.GetResponse;
 import org.elasticsearch.client.Client;
 import org.elasticsearch.client.Requests;
 import org.elasticsearch.common.bytes.BytesArray;
-import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.logging.ESLogger;
 import org.elasticsearch.common.logging.Loggers;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentFactory;
+import org.nuiton.i18n.I18n;
 
 import java.io.*;
 import java.util.Objects;
 import java.util.Set;
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
@@ -73,21 +73,29 @@ public abstract class AbstractService implements Bean {
     protected final PluginSettings pluginSettings;
     protected final ObjectMapper objectMapper;
     protected final CryptoService cryptoService;
+    protected final int retryCount;
+    protected final int retryWaitDuration;
 
-    public AbstractService(Client client, PluginSettings pluginSettings, CryptoService cryptoService) {
-        this.logger = Loggers.getLogger(getClass());
+    public AbstractService(String loggerName, Client client, PluginSettings pluginSettings, CryptoService cryptoService) {
+        this.logger = Loggers.getLogger(loggerName);
         this.client = client;
         this.pluginSettings = pluginSettings;
         this.cryptoService = cryptoService;
         this.objectMapper = new ObjectMapper();
+        this.retryCount = pluginSettings.getNodeRetryCount();
+        this.retryWaitDuration = pluginSettings.getNodeRetryWaitDuration();
+    }
+
+    public AbstractService(String loggerName, Client client, PluginSettings pluginSettings) {
+        this(loggerName, client, pluginSettings, null);
     }
 
     public AbstractService(Client client, PluginSettings pluginSettings) {
-        this.logger = Loggers.getLogger(getClass());
-        this.client = client;
-        this.pluginSettings = pluginSettings;
-        this.cryptoService = null;
-        this.objectMapper = new ObjectMapper();
+        this(client, pluginSettings, null);
+    }
+
+    public AbstractService(Client client, PluginSettings pluginSettings, CryptoService cryptoService) {
+        this("duniter", client, pluginSettings, cryptoService);
     }
 
     /* -- protected methods  -- */
@@ -368,4 +376,37 @@ public abstract class AbstractService implements Bean {
             return line;
         }
     }
+
+    protected <T> T executeWithRetry(RetryFunction<T> retryFunction) throws TechnicalException{
+        int retry = 0;
+        while (retry < retryCount) {
+            try {
+                return retryFunction.execute();
+            } catch (TechnicalException e) {
+                retry++;
+
+                if (retry == retryCount) {
+                    throw e;
+                }
+
+                if (logger.isDebugEnabled()) {
+                    logger.debug(I18n.t("duniter4j.removeServiceUtils.waitThenRetry", e.getMessage(), retry, retryCount));
+                }
+
+                try {
+                    Thread.sleep(retryWaitDuration); // waiting
+                } catch (InterruptedException e2) {
+                    throw new TechnicalException(e2);
+                }
+            }
+        }
+
+        throw new TechnicalException("Error while trying to execute a function with retry");
+    }
+
+    public interface RetryFunction<T> {
+
+        T execute() throws TechnicalException;
+    }
+
 }
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java
index 590d18a6061c8c261bdb2e63f8ed4204f6277ee2..a847e4780a166cdd8a215d619e529a2eb0c7043c 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java
@@ -35,16 +35,18 @@ import org.duniter.core.client.model.bma.gson.JsonAttributeParser;
 import org.duniter.core.client.model.local.Peer;
 import org.duniter.core.client.service.bma.BlockchainRemoteService;
 import org.duniter.core.client.service.bma.NetworkRemoteService;
+import org.duniter.core.client.service.exception.BlockNotFoundException;
 import org.duniter.core.client.service.exception.HttpBadRequestException;
 import org.duniter.core.client.service.exception.JsonSyntaxException;
 import org.duniter.core.exception.TechnicalException;
+import org.duniter.core.model.NullProgressionModel;
 import org.duniter.core.model.ProgressionModel;
 import org.duniter.core.model.ProgressionModelImpl;
 import org.duniter.core.util.CollectionUtils;
 import org.duniter.core.util.ObjectUtils;
 import org.duniter.core.util.StringUtils;
 import org.duniter.elasticsearch.PluginSettings;
-import org.duniter.elasticsearch.exception.*;
+import org.duniter.elasticsearch.exception.DuplicateIndexIdException;
 import org.duniter.elasticsearch.threadpool.ThreadPool;
 import org.elasticsearch.action.ActionFuture;
 import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
@@ -57,6 +59,7 @@ import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.action.search.SearchType;
 import org.elasticsearch.client.Client;
+import org.elasticsearch.cluster.health.ClusterHealthStatus;
 import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException;
 import org.elasticsearch.common.xcontent.XContentBuilder;
@@ -83,18 +86,25 @@ public class BlockchainService extends AbstractService {
 
     private static final int SYNC_MISSING_BLOCK_MAX_RETRY = 5;
 
+    private final ProgressionModel nullProgressionModel = new NullProgressionModel();
+
     private BlockchainRemoteService blockchainRemoteService;
     private RegistryService registryService;
+    private ThreadPool threadPool;
 
     private JsonAttributeParser blockNumberParser = new JsonAttributeParser("number");
     private JsonAttributeParser blockCurrencyParser = new JsonAttributeParser("currency");
+    private JsonAttributeParser blockHashParser = new JsonAttributeParser("hash");
+    private JsonAttributeParser blockPreviousHashParser = new JsonAttributeParser("previousHash");
 
     private Gson gson;
 
     @Inject
-    public BlockchainService(Client client, PluginSettings settings, ThreadPool threadPool, final ServiceLocator serviceLocator){
-        super(client, settings);
+    public BlockchainService(Client client, PluginSettings settings, ThreadPool threadPool,
+                             final ServiceLocator serviceLocator){
+        super("duniter.blockchain", client, settings);
         this.gson = GsonUtils.newBuilder().create();
+        this.threadPool = threadPool;
         threadPool.scheduleOnStarted(() -> {
             blockchainRemoteService = serviceLocator.getBlockchainRemoteService();
         });
@@ -107,17 +117,14 @@ public class BlockchainService extends AbstractService {
 
     public BlockchainService listenAndIndexNewBlock(Peer peer){
         blockchainRemoteService.addNewBlockListener(peer, message -> {
-            indexBlockAsJson(peer, message, true /*refresh*/, true /*wait*/);
-
-            // Update the current block
-            indexCurrentBlockAsJson(message,  false /*wait*/);
-
+            indexLastBlockFromJson(peer, message);
         });
         return this;
     }
 
     public BlockchainService indexLastBlocks(Peer peer) {
-        return indexLastBlocks(peer, new ProgressionModelImpl());
+        indexLastBlocks(peer, nullProgressionModel);
+        return this;
     }
 
     public BlockchainService indexLastBlocks(Peer peer, ProgressionModel progressionModel) {
@@ -132,15 +139,13 @@ public class BlockchainService extends AbstractService {
             BlockchainParameters parameter = blockchainRemoteService.getParameters(peer);
             if (parameter == null) {
                 progressionModel.setStatus(ProgressionModel.Status.FAILED);
-                logger.error(String.format("Could not connect to node [%s]",
-                        peer.getUrl()));
+                logger.error(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.remoteParametersError",peer));
                 return this;
             }
             String currencyName = parameter.getCurrency();
 
-            progressionModel.setTask(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.task", currencyName, peer.getHost(), peer.getPort()));
-            logger.info(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.task",
-                    currencyName, pluginSettings.getNodeBmaHost(), pluginSettings.getNodeBmaPort()));
+            progressionModel.setTask(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.task", currencyName, peer));
+            logger.info(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.task", currencyName, peer));
 
             // Create index blockchain if need
             if (!registryService.isCurrencyExists(currencyName)) {
@@ -148,63 +153,80 @@ public class BlockchainService extends AbstractService {
             }
 
             // Check if index exists
-            createIndexIfNotExists(currencyName);
+            createIndexIfNotExists(currencyName, true/*wait cluster health*/);
 
             // Then index all blocks
-            BlockchainBlock currentBlock = blockchainRemoteService.getCurrentBlock(peer);
-
-            if (currentBlock != null) {
-                int maxBlockNumber = currentBlock.getNumber();
+            BlockchainBlock peerCurrentBlock = blockchainRemoteService.getCurrentBlock(peer);
 
-                // DEV mode
-                if (pluginSettings.isDevMode() && maxBlockNumber > 5000) {
-                    maxBlockNumber = 5000;
-                }
+            if (peerCurrentBlock != null) {
+                final int peerCurrentBlockNumber = peerCurrentBlock.getNumber();
 
                 // Get the last indexed block number
                 int startNumber = 0;
 
-                int currentBlockNumber = -1;
+                // Check if a previous sync has been done
                 BlockchainBlock indexedCurrentBlock = getCurrentBlock(currencyName);
                 if (indexedCurrentBlock != null && indexedCurrentBlock.getNumber() != null) {
-                    currentBlockNumber = indexedCurrentBlock.getNumber();
+                    int indexedCurrentBlockNumber = indexedCurrentBlock.getNumber();
 
-                    // Previous block could have been not indexed : so start at the max(number)
-                    indexedCurrentBlock = getBlockById(currencyName, currentBlockNumber);
-                    // If exists on blockchain, so can use it
+                    // Make sure this block has been indexed by its number (not only with _id='current')
+                    indexedCurrentBlock = getBlockById(currencyName, indexedCurrentBlockNumber);
+
+                    // If current block exists on index, by _id=number AND _id=current
+                    // then keep it and sync only next blocks
                     if (indexedCurrentBlock != null) {
-                        startNumber = currentBlockNumber + 1;
+                        startNumber = indexedCurrentBlockNumber + 1;
                     }
                 }
 
-                // Before to start at '0' (first block), try to use the max(number)
+                // When current block not found,
+                // try to use the max(number), because block with _id='current' may not has been indexed
                 if (startNumber <= 1 ){
                     startNumber = getMaxBlockNumber(currencyName) + 1;
                 }
 
-                if (startNumber <= maxBlockNumber) {
+                // If some block has been already indexed: detect and resolve fork
+                if (startNumber > 0) {
+                    String peerStartPreviousHash;
+                    try {
+                        BlockchainBlock peerStartBlock = blockchainRemoteService.getBlock(peer, startNumber - 1);
+                        peerStartPreviousHash = peerStartBlock.getHash();
+                    }
+                    catch(BlockNotFoundException e) {
+                        // block not exists: use a fake hash for fork detection (will force to compare previous blocks)
+                        peerStartPreviousHash = "--";
+                    }
+                    boolean resolved = detectAndResolveFork(peer, currencyName, peerStartPreviousHash, startNumber - 1);
+                    if (!resolved) {
+                        // Bad blockchain ! skipping sync
+                        logger.error(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.invalidBlockchain", currencyName, peer));
+                        return this;
+                    }
+                }
+
+                if (startNumber <= peerCurrentBlockNumber) {
                     Collection<String> missingBlocks = bulkIndex
-                            ? indexBlocksUsingBulk(peer, currencyName, startNumber, maxBlockNumber, progressionModel)
-                            : indexBlocksNoBulk(peer, currencyName, startNumber, maxBlockNumber, progressionModel);
+                            ? indexBlocksUsingBulk(peer, currencyName, startNumber, peerCurrentBlockNumber, progressionModel)
+                            : indexBlocksNoBulk(peer, currencyName, startNumber, peerCurrentBlockNumber, progressionModel);
 
                     // If some blocks are missing, try to get it using other peers
                     if (CollectionUtils.isNotEmpty(missingBlocks)) {
                         progressionModel.setTask(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task", currencyName));
-                        missingBlocks = indexMissingBlocksFromOtherPeers(peer, currentBlock, missingBlocks, 1);
+                        missingBlocks = indexMissingBlocksFromOtherPeers(peer, peerCurrentBlock, missingBlocks, 1);
                     }
 
                     if (CollectionUtils.isEmpty(missingBlocks)) {
-                        logger.info(String.format("All blocks indexed [%s ms]", (System.currentTimeMillis() - timeStart)));
+                        logger.info(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.succeed", currencyName, peer, (System.currentTimeMillis() - timeStart)));
                         progressionModel.setStatus(ProgressionModel.Status.SUCCESS);
                     }
                     else {
-                        logger.warn(String.format("Could not indexed all blocks. Missing %s blocks.", missingBlocks.size()));
+                        logger.warn(String.format("[%s] [%s] Could not indexed all blocks. Missing %s blocks.", currencyName, peer, missingBlocks.size()));
                         progressionModel.setStatus(ProgressionModel.Status.FAILED);
                     }
                 }
                 else {
                     if (logger.isDebugEnabled()) {
-                        logger.debug(String.format("Current block from peer [%s] is #%s. Index is up to date.", peer.getUrl(), maxBlockNumber));
+                        logger.debug(String.format("[%s] [%s] Already up to date at block #%s.", currencyName, peer, peerCurrentBlockNumber));
                     }
                     progressionModel.setStatus(ProgressionModel.Status.SUCCESS);
                 }
@@ -226,9 +248,14 @@ public class BlockchainService extends AbstractService {
         return super.existsIndex(currencyName);
     }
 
-    public BlockchainService createIndexIfNotExists(String currencyName) {
+    public BlockchainService createIndexIfNotExists(String currencyName, boolean waitClusterHealth) {
         if (!existsIndex(currencyName)) {
             createIndex(currencyName);
+
+            // when wait cluster state
+            if (waitClusterHealth) {
+                threadPool.waitClusterHealthStatus(ClusterHealthStatus.GREEN, ClusterHealthStatus.YELLOW);
+            }
         }
         return this;
     }
@@ -344,7 +371,7 @@ public class BlockchainService extends AbstractService {
      * @param number the block number
      * @param json block as JSON
      */
-    public void indexBlockAsJson(String currencyName, int number, byte[] json, boolean refresh, boolean wait) {
+    public BlockchainService indexBlockFromJson(String currencyName, int number, byte[] json, boolean refresh, boolean wait) {
         ObjectUtils.checkNotNull(json);
         ObjectUtils.checkArgument(json.length > 0);
 
@@ -361,26 +388,54 @@ public class BlockchainService extends AbstractService {
         else {
             indexRequest.execute().actionGet();
         }
+
+        return this;
+    }
+
+    /**
+     * Index the given block, as the last (current) block. This will check is a fork has occur, and apply a rollback so.
+     * @param peer a source peer
+     * @param json block as json
+     */
+    public BlockchainService indexLastBlockFromJson(Peer peer, String json) {
+        ObjectUtils.checkNotNull(json);
+        ObjectUtils.checkArgument(json.length() > 0);
+
+        indexBlockFromJson(peer, json, true /*refresh*/, true /*is current*/, true/*check fork*/, true/*wait*/);
+
+        return this;
     }
 
     /**
      *
      * @param json block as json
-     * @param refresh is a existing block ?
+     * @param refresh Could be an existing block ?
      * @param wait need to wait until processed ?
      */
-    public void indexBlockAsJson(Peer peer, String json, boolean refresh, boolean wait) {
+    public BlockchainService indexBlockFromJson(Peer peer, String json, boolean refresh, boolean isCurrent, boolean detectFork, boolean wait) {
         ObjectUtils.checkNotNull(json);
         ObjectUtils.checkArgument(json.length() > 0);
 
         String currencyName = blockCurrencyParser.getValueAsString(json);
         int number = blockNumberParser.getValueAsInt(json);
+        String hash = blockHashParser.getValueAsString(json);
 
-        logger.info(I18n.t("duniter4j.blockIndexerService.indexBlock", currencyName, peer, number));
+        logger.info(I18n.t("duniter4j.blockIndexerService.indexBlock", currencyName, peer, number, hash));
         if (logger.isTraceEnabled()) {
             logger.trace(json);
         }
 
+        // Detecting fork and rollback is necessary
+        if (detectFork) {
+            String previousHash = blockPreviousHashParser.getValueAsString(json);
+            boolean resolved = detectAndResolveFork(peer, currencyName, previousHash, number - 1);
+            if (!resolved) {
+                // Bad blockchain ! Skipping block indexation
+                logger.error(I18n.t("duniter4j.blockIndexerService.detectFork.invalidBlockchain", currencyName, peer, number, hash));
+                return this;
+            }
+        }
+
         // Preparing indexBlocksFromNode
         IndexRequestBuilder indexRequest = client.prepareIndex(currencyName, BLOCK_TYPE)
                 .setId(String.valueOf(number))
@@ -394,6 +449,13 @@ public class BlockchainService extends AbstractService {
         else {
             indexRequest.execute().actionGet();
         }
+
+        // Update current
+        if (isCurrent) {
+            indexCurrentBlockFromJson(currencyName, json, true /*wait*/);
+        }
+
+        return this;
     }
 
     /**
@@ -410,29 +472,16 @@ public class BlockchainService extends AbstractService {
         // WARN: must use GSON, to have same JSON result (e.g identities and joiners field must be converted into String)
         String json = gson.toJson(currentBlock);
 
-        indexCurrentBlockAsJson(currentBlock.getCurrency(), json, wait);
+        indexCurrentBlockFromJson(currentBlock.getCurrency(), json, wait);
     }
 
-    /**
-     *
-     * @param currentBlockJson block as JSON
-     * @pram wait need to wait until block processed ?
-     */
-    public void indexCurrentBlockAsJson(String json, boolean wait) {
-        ObjectUtils.checkNotNull(json);
-        ObjectUtils.checkArgument(json.length() > 0);
-
-        String currencyName = blockCurrencyParser.getValueAsString(json);
-
-        indexCurrentBlockAsJson(currencyName, json, wait);
-    }
    /**
     *
     * @param currencyName
-    * @param currentBlockJson block as JSON
+    * @param json block as JSON
     * @pram wait need to wait until block processed ?
     */
-    public void indexCurrentBlockAsJson(String currencyName, String json, boolean wait) {
+    public void indexCurrentBlockFromJson(String currencyName, String json, boolean wait) {
         ObjectUtils.checkNotNull(json);
         ObjectUtils.checkArgument(json.length() > 0);
         ObjectUtils.checkArgument(StringUtils.isNotBlank(currencyName));
@@ -554,6 +603,11 @@ public class BlockchainService extends AbstractService {
                     .field("type", "string")
                     .endObject()
 
+                    // previous hash
+                    .startObject("previousHash")
+                    .field("type", "string")
+                    .endObject()
+
                     // membercount
                     .startObject("memberCount")
                     .field("type", "integer")
@@ -597,13 +651,13 @@ public class BlockchainService extends AbstractService {
         // Execute query
         try {
             SearchResponse searchResponse = searchRequest.execute().actionGet();
-            List<BlockchainBlock> currencies = toBlocks(searchResponse, false);
-            if (CollectionUtils.isEmpty(currencies)) {
+            List<BlockchainBlock> blocks = toBlocks(searchResponse, false);
+            if (CollectionUtils.isEmpty(blocks)) {
                 return null;
             }
 
             // Return the unique result
-            return CollectionUtils.extractSingleton(currencies);
+            return CollectionUtils.extractSingleton(blocks);
         }
         catch(JsonSyntaxException e) {
             throw new TechnicalException(String.format("Error while getting indexed block #%s for blockchain [%s]", blockId, currencyName), e);
@@ -670,12 +724,12 @@ public class BlockchainService extends AbstractService {
 
             try {
                 String blockAsJson = blockchainRemoteService.getBlockAsJson(peer, curNumber);
-                indexBlockAsJson(currencyName, curNumber, blockAsJson.getBytes(), false, true /*wait*/);
+                indexBlockFromJson(currencyName, curNumber, blockAsJson.getBytes(), false, true /*wait*/);
 
                 // If last block
                 if (curNumber == lastNumber - 1) {
                     // update the current block
-                    indexCurrentBlockAsJson(currencyName, blockAsJson, true /*wait*/);
+                    indexCurrentBlockFromJson(currencyName, blockAsJson, true /*wait*/);
                 }
             }
             catch(Throwable t) {
@@ -707,10 +761,11 @@ public class BlockchainService extends AbstractService {
 
             String[] blocksAsJson = null;
             try {
-                blocksAsJson = blockchainRemoteService.getBlocksAsJson(peer, batchSize, batchFirstNumber);
-            } catch(HttpBadRequestException e) {
+                final int batchFirstNumberFinal = batchFirstNumber;
+                blocksAsJson = executeWithRetry(()->blockchainRemoteService.getBlocksAsJson(peer, batchSize, batchFirstNumberFinal));
+            } catch(TechnicalException e) {
                 if (logger.isDebugEnabled()) {
-                    logger.debug(String.format("Error while getting blocks from #%s (count=%s): %s. Skipping blocks.", batchFirstNumber, batchSize, e.getMessage()));
+                    logger.debug(String.format("[%s] [%s] Error while getting blocks from #%s (count=%s): %s. Skipping blocks.",currencyName, peer, batchFirstNumber, batchSize, e.getMessage()));
                 }
             }
 
@@ -778,11 +833,11 @@ public class BlockchainService extends AbstractService {
 
             // Report progress
             reportIndexBlocksProgress(progressionModel, currencyName, peer, firstNumber, lastNumber, batchFirstNumber);
-
+            batchFirstNumber++; // increment for next loop
         }
 
         if (StringUtils.isNotBlank(currentBlockJson)) {
-            indexCurrentBlockAsJson(currencyName, currentBlockJson, false);
+            indexCurrentBlockFromJson(currencyName, currentBlockJson, false);
         }
 
         return missingBlockNumbers;
@@ -860,7 +915,7 @@ public class BlockchainService extends AbstractService {
                             }
 
                             // Index the missing block
-                            indexBlockAsJson(currencyName, blockNumber, blockAsJson.getBytes(), false, true/*wait*/);
+                            indexBlockFromJson(currencyName, blockNumber, blockAsJson.getBytes(), false, true/*wait*/);
 
                             // Remove this block number from the final missing list
                             newMissingBlocks.remove(blockNumber);
@@ -922,4 +977,104 @@ public class BlockchainService extends AbstractService {
         }
 
     }
+
+    protected boolean isBlockIndexed(String currencyName, int number, String hash) {
+        // Check if previous block exists
+        BlockchainBlock block = getBlockByIdStr(currencyName, String.valueOf(number));
+        boolean blockExists = block != null;
+        if (!blockExists) {
+            return blockExists;
+        }
+        return block.getHash() != null && block.getHash().equals(hash);
+    }
+
+    protected boolean detectAndResolveFork(Peer peer, final String currencyName, final String hash, final int number){
+        int forkResyncWindow = pluginSettings.getNodeForkResyncWindow();
+        String forkOriginHash = hash;
+        int forkOriginNumber = number;
+        boolean sameBlockIndexed = isBlockIndexed(currencyName, forkOriginNumber, forkOriginHash);
+        while (!sameBlockIndexed && forkOriginNumber > 0) {
+
+            if (!sameBlockIndexed && logger.isInfoEnabled()) {
+                logger.info(I18n.t("duniter4j.blockIndexerService.detectFork.invalidBlock", currencyName, peer, forkOriginNumber, forkOriginHash));
+            }
+            forkOriginNumber -= forkResyncWindow;
+            if (forkOriginNumber < 0) {
+                forkOriginNumber = 0;
+            }
+
+            // Get remote block (with auto-retry)
+            try {
+                final int currentNumberFinal = forkOriginNumber;
+                String testBlock = executeWithRetry(() ->
+                    blockchainRemoteService.getBlockAsJson(peer, currentNumberFinal));
+                forkOriginHash = blockHashParser.getValueAsString(testBlock);
+
+                // Check is exists on ES index
+                sameBlockIndexed = isBlockIndexed(currencyName, forkOriginNumber, forkOriginHash);
+            } catch (TechnicalException e) {
+                logger.warn(I18n.t("duniter4j.blockIndexerService.detectFork.remoteBlockNotFound", currencyName, peer, forkOriginNumber, e.getMessage()));
+                sameBlockIndexed = false; // continue (go back again)
+            }
+        }
+
+        if (!sameBlockIndexed) {
+            return false; // sync could not be done (bad blockchain: no common blocks !)
+        }
+
+        if (forkOriginNumber < number) {
+            logger.info(I18n.t("duniter4j.blockIndexerService.detectFork.resync", currencyName, peer, forkOriginNumber));
+            // Remove some previous block
+            deleteBlocksFromNumber(currencyName, forkOriginNumber/*from*/, number+forkResyncWindow/*to*/);
+
+            // Re-indexing blocks
+            indexBlocksUsingBulk(peer, currencyName, forkOriginNumber/*from*/, number, nullProgressionModel);
+        }
+
+        return true; // sync OK
+    }
+
+    /**
+     * Delete blocks from a start number (using bulk)
+     * @param currencyName
+     * @param fromNumber
+     */
+    protected void deleteBlocksFromNumber(String currencyName, int fromNumber, int toNumber) {
+
+        int bulkSize = pluginSettings.getIndexBulkSize();
+
+        BulkRequestBuilder bulkRequest = client.prepareBulk();
+        for (int i=fromNumber; i<=toNumber; i++) {
+
+            bulkRequest.add(
+                client.prepareDelete(currencyName, BLOCK_TYPE, String.valueOf(i))
+            );
+
+            // Flush the bulk if not empty
+            if ((fromNumber - i % bulkSize) == 0) {
+                flushDeleteBulk(bulkRequest);
+                bulkRequest = client.prepareBulk();
+            }
+        }
+
+        // last flush
+        flushDeleteBulk(bulkRequest);
+    }
+
+    protected void flushDeleteBulk(BulkRequestBuilder bulkRequest) {
+        if (bulkRequest.numberOfActions() > 0) {
+            BulkResponse bulkResponse = bulkRequest.get();
+            // If failures, continue but save missing blocks
+            if (bulkResponse.hasFailures()) {
+                // process failures by iterating through each bulk response item
+                for (BulkItemResponse itemResponse : bulkResponse) {
+                    boolean skip = !itemResponse.isFailed();
+                    if (!skip) {
+                        int itemNumber = Integer.parseInt(itemResponse.getId());
+                        logger.debug(String.format("Error while deleting block #%s: %s. Skipping this deletion.", itemNumber, itemResponse.getFailureMessage()));
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/HistoryService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/HistoryService.java
index 3995e2d363af61909b90ef9d72124339db02c605..06e9b37ac67eaed43b1d3e67d416bad5fbb3fe5e 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/HistoryService.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/HistoryService.java
@@ -50,7 +50,7 @@ public class HistoryService extends AbstractService {
 
     @Inject
     public HistoryService(Client client, PluginSettings settings, CryptoService cryptoService) {
-        super(client, settings, cryptoService);
+        super("gchange." + INDEX, client, settings, cryptoService);
     }
 
     /**
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MarketService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MarketService.java
index 67d50dd9f321fb030ced759b169d9b5fad3051ec..08a8e0ac569e7b14f2d974d466ffd3a1c48e4e27 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MarketService.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MarketService.java
@@ -56,7 +56,7 @@ public class MarketService extends AbstractService {
 
     @Inject
     public MarketService(Client client, PluginSettings settings, CryptoService cryptoService, WotRemoteService wotRemoteService) {
-        super(client, settings, cryptoService);
+        super("gchange." + INDEX, client, settings, cryptoService);
         this.wotRemoteService = wotRemoteService;
     }
 
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MessageService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MessageService.java
index b201a228bd43874bec311dc55ebb3510d1e3c53d..632702c8a65ece046693d472979cac25d369b308 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MessageService.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MessageService.java
@@ -59,7 +59,7 @@ public class MessageService extends AbstractService {
 
     @Inject
     public MessageService(Client client, PluginSettings settings, CryptoService cryptoService) {
-        super(client, settings, cryptoService);
+        super("gchange." + INDEX, client, settings, cryptoService);
     }
 
     /**
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/RegistryService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/RegistryService.java
index a12c15b24e96d3093ac6b86236bbacfae2aa00a5..826c7efe2e39f95c84e7b8b5714cf02bb646a50d 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/RegistryService.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/RegistryService.java
@@ -87,7 +87,7 @@ public class RegistryService extends AbstractService {
                            WotRemoteService wotRemoteService,
                            CryptoService cryptoService,
                            BlockchainRemoteService blockchainRemoteService) {
-        super(client, settings, cryptoService);
+        super("gchange." + INDEX, client, settings, cryptoService);
         gson = GsonUtils.newBuilder().create();
         this.blockchainRemoteService = blockchainRemoteService;
     }
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/ServiceModule.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/ServiceModule.java
index 8dd1a7c9db1a4721a9af84d7c1f91975429b0d65..0342ebce2a0e090180bb8ee8d488e1d2ac3cb561 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/ServiceModule.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/ServiceModule.java
@@ -25,18 +25,15 @@ package org.duniter.elasticsearch.service;
 import org.duniter.core.beans.Bean;
 import org.duniter.core.client.dao.CurrencyDao;
 import org.duniter.core.client.dao.PeerDao;
-import org.duniter.core.client.dao.mem.MemoryCurrencyDaoImpl;
-import org.duniter.core.client.dao.mem.MemoryPeerDaoImpl;
 import org.duniter.core.client.service.DataContext;
 import org.duniter.core.client.service.HttpService;
-import org.duniter.core.client.service.HttpServiceImpl;
-import org.duniter.core.client.service.bma.*;
+import org.duniter.core.client.service.bma.BlockchainRemoteService;
+import org.duniter.core.client.service.bma.NetworkRemoteService;
+import org.duniter.core.client.service.bma.TransactionRemoteService;
+import org.duniter.core.client.service.bma.WotRemoteService;
 import org.duniter.core.client.service.local.CurrencyService;
-import org.duniter.core.client.service.local.CurrencyServiceImpl;
 import org.duniter.core.client.service.local.PeerService;
-import org.duniter.core.client.service.local.PeerServiceImpl;
 import org.duniter.core.service.CryptoService;
-import org.duniter.core.service.Ed25519CryptoServiceImpl;
 import org.duniter.elasticsearch.PluginSettings;
 import org.elasticsearch.common.inject.AbstractModule;
 import org.elasticsearch.common.inject.Module;
@@ -66,6 +63,7 @@ public class ServiceModule extends AbstractModule implements Module {
         bindWithLocator(CurrencyDao.class);
         bindWithLocator(PeerDao.class);
         bindWithLocator(DataContext.class);
+
 /*
         bindWithLocator(BlockchainRemoteServiceImpl.class);
         bindWithLocator(NetworkRemoteServiceImpl.class);
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/UserService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/UserService.java
index 37fa19ca51e49c467e9925a269d72a1cb5c76c73..0a8086b902f802ac6b4227641984eef4df1f0de6 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/UserService.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/UserService.java
@@ -55,7 +55,7 @@ public class UserService extends AbstractService {
     public UserService(Client client,
                        PluginSettings settings,
                        CryptoService cryptoService) {
-        super(client, settings,cryptoService);
+        super("gchange." + INDEX, client, settings,cryptoService);
     }
 
     /**
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java
index 8ca23af5a9d97c078bd550878a6800cd50b939b4..b024cbc0d1e1dffe5ff41e47597f77044f1785d1 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java
@@ -22,23 +22,28 @@ package org.duniter.elasticsearch.threadpool;
  * #L%
  */
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
+import org.elasticsearch.action.admin.cluster.stats.ClusterStatsRequestBuilder;
+import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.cluster.health.ClusterHealthStatus;
 import org.elasticsearch.common.component.AbstractLifecycleComponent;
 import org.elasticsearch.common.component.Lifecycle;
 import org.elasticsearch.common.component.LifecycleComponent;
 import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.inject.Injector;
+import org.elasticsearch.common.logging.ESLogger;
+import org.elasticsearch.common.logging.Loggers;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.unit.TimeValue;
 import org.elasticsearch.common.util.concurrent.EsAbortPolicy;
 import org.elasticsearch.common.util.concurrent.EsExecutors;
 import org.elasticsearch.transport.TransportService;
+import org.nuiton.i18n.I18n;
 
 import java.util.List;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.*;
 
 /**
  * Manage thread pool, to execute tasks asynchronously.
@@ -48,6 +53,7 @@ public class ThreadPool extends AbstractLifecycleComponent<ThreadPool> {
 
     private ScheduledThreadPoolExecutor scheduler = null;
     private Injector injector;
+    private ESLogger logger = Loggers.getLogger("threadpool");
 
     private final List<Runnable> afterStartedCommands;
 
@@ -94,16 +100,30 @@ public class ThreadPool extends AbstractLifecycleComponent<ThreadPool> {
     /**
      * Schedules an action when node is started (all services and modules ready)
      *
-     * @param command the action to take
+     * @param job the action to execute when node started
      * @return a ScheduledFuture who's get will return when the task is complete and throw an exception if it is canceled
      */
-    public void scheduleOnStarted(Runnable command) {
-        /*if (lifecycle.state() == Lifecycle.State.INITIALIZED ) {
-            afterStartedCommands.add(command);
-        }
-        else {*/
-            scheduleAfterServiceState(TransportService.class, Lifecycle.State.STARTED, command);
-       // }
+    public void scheduleOnStarted(Runnable job) {
+        Preconditions.checkNotNull(job);
+        scheduleAfterServiceState(TransportService.class, Lifecycle.State.STARTED, job);
+    }
+
+    /**
+     * Schedules an action when cluster is ready
+     *
+     * @param job the action to execute
+     * @param expectedStatus expected health status, to run the job
+     * @return a ScheduledFuture who's get will return when the task is complete and throw an exception if it is canceled
+     */
+    public void scheduleOnClusterHealthStatus(Runnable job, ClusterHealthStatus... expectedStatus) {
+        Preconditions.checkNotNull(job);
+
+        scheduleOnStarted(() -> {
+            if (waitClusterHealthStatus(expectedStatus)) {
+                // continue
+                job.run();
+            }
+        });
     }
 
     /**
@@ -131,7 +151,13 @@ public class ThreadPool extends AbstractLifecycleComponent<ThreadPool> {
 
     /* -- protected methods  -- */
 
-    protected <T extends LifecycleComponent<T>> ScheduledFuture<?> scheduleAfterServiceState(Class<T> waitingServiceClass, final Lifecycle.State waitingState, final Runnable job) {
+    protected <T extends LifecycleComponent<T>> ScheduledFuture<?> scheduleAfterServiceState(Class<T> waitingServiceClass,
+                                                                                             final Lifecycle.State waitingState,
+                                                                                             final Runnable job) {
+        Preconditions.checkNotNull(waitingServiceClass);
+        Preconditions.checkNotNull(waitingState);
+        Preconditions.checkNotNull(job);
+
         final T service = injector.getInstance(waitingServiceClass);
         return schedule(() -> {
             while(service.lifecycleState() != waitingState) {
@@ -147,94 +173,39 @@ public class ThreadPool extends AbstractLifecycleComponent<ThreadPool> {
         }, TimeValue.timeValueSeconds(10));
     }
 
+    public boolean waitClusterHealthStatus(ClusterHealthStatus... expectedStatus) {
+        Preconditions.checkNotNull(expectedStatus);
+        Preconditions.checkArgument(expectedStatus.length > 0);
 
-    /*public void resetAllData() {
-        //resetAllCurrencies();
-        //resetDataBlocks();
-        //resetMarketRecords();
-        //resetRegistry();
-    }
-
-    public void resetAllCurrencies() {
-        currencyRegistryService.deleteAllCurrencies();
-    }
-
-    public void resetDataBlocks() {
-        BlockchainRemoteService blockchainService = serviceLocator.getBlockchainRemoteService();
-        Peer peer = checkConfigAndGetPeer(pluginSettings);
-
-        try {
-            // Get the blockchain name from node
-            BlockchainParameters parameter = blockchainService.getParameters(peer);
-            if (parameter == null) {
-                logger.error(String.format("Could not connect to node [%s:%s]",
-                        pluginSettings.getNodeBmaHost(), pluginSettings.getNodeBmaPort()));
-                return;
-            }
-            String currencyName = parameter.getCurrency();
-
-            logger.info(String.format("Reset data for index [%s]", currencyName));
-
-            // Delete then create index on blockchain
-            boolean indexExists = blockBlockchainService.existsIndex(currencyName);
-            if (indexExists) {
-                blockBlockchainService.deleteIndex(currencyName);
-                blockBlockchainService.createIndex(currencyName);
+        Client client = injector.getInstance(Client.class);
+        ClusterStatsRequestBuilder statsRequest = client.admin().cluster().prepareClusterStats();
+        ClusterStatsResponse stats = null;
+        boolean canContinue = false;
+        boolean firstTry = true;
+        while (!canContinue) {
+            try {
+                if (stats != null) Thread.sleep(100); // wait 100 ms
+                stats = statsRequest.execute().get();
+                for (ClusterHealthStatus status: expectedStatus) {
+                    if (stats.getStatus() == status) {
+                        if (!firstTry && logger.isDebugEnabled()) {
+                            logger.debug(I18n.t("duniter4j.threadPool.clusterHealthStatus.changed", status.name()));
+                        }
+                        canContinue = true;
+                        break;
+                    }
+                }
+                firstTry = false;
+            } catch (ExecutionException e) {
+                // Continue
+            } catch (InterruptedException e) {
+                return false; // stop
             }
-
-
-            logger.info(String.format("Successfully reset data for index [%s]", currencyName));
-        } catch(Exception e) {
-            logger.error("Error during reset data: " + e.getMessage(), e);
         }
-    }
 
-    public void resetMarketRecords() {
-        try {
-            // Delete then create index on records
-            boolean indexExists = recordMarketService.existsIndex();
-            if (indexExists) {
-                recordMarketService.deleteIndex();
-            }
-            logger.info(String.format("Successfully reset market records"));
-
-            categoryMarketService.createIndex();
-            categoryMarketService.initCategories();
-            logger.info(String.format("Successfully re-initialized market categories data"));
-
-        } catch(Exception e) {
-            logger.error("Error during reset market records: " + e.getMessage(), e);
-        }
+        return canContinue;
     }
 
-    public void resetRegistry() {
-        try {
-            // Delete then create index on records
-            if (recordRegistryService.existsIndex()) {
-                recordRegistryService.deleteIndex();
-            }
-            recordRegistryService.createIndex();
-            logger.info(String.format("Successfully reset registry records"));
-
-
-            if (categoryRegistryService.existsIndex()) {
-                categoryRegistryService.deleteIndex();
-            }
-            categoryRegistryService.createIndex();
-            categoryRegistryService.initCategories();
-            logger.info(String.format("Successfully re-initialized registry categories"));
-
-            if (citiesRegistryService.existsIndex()) {
-                citiesRegistryService.deleteIndex();
-            }
-            citiesRegistryService.initCities();
-            logger.info(String.format("Successfully re-initialized registry cities"));
-
-        } catch(Exception e) {
-            logger.error("Error during reset registry records: " + e.getMessage(), e);
-        }
-    }*/
-
     /* -- internal methods -- */
 
     class LoggingRunnable implements Runnable {
diff --git a/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_en_GB.properties b/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_en_GB.properties
index f1e0263f4b085ee3026df8d9c68b3f971767f435..a6067b359c9b1b3288467e75f3b34faaa2ce093d 100644
--- a/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_en_GB.properties
+++ b/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_en_GB.properties
@@ -1,9 +1,16 @@
 duniter4j-elasticsearch.config=
-duniter4j.blockIndexerService.indexBlock=
-duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task=
-duniter4j.blockIndexerService.indexLastBlocks.progress=
-duniter4j.blockIndexerService.indexLastBlocks.stopped=
-duniter4j.blockIndexerService.indexLastBlocks.task=
+duniter4j.blockIndexerService.detectFork.invalidBlock=[%s] [%s] Detecting fork\: block \#%s -> new hash [%s]
+duniter4j.blockIndexerService.detectFork.invalidBlockchain=[%s] [%s] Peer has another blockchain (no common blocks \!). Skipping block \#%s - hash [%s].
+duniter4j.blockIndexerService.detectFork.remoteBlockNotFound=[%s] [%s] Unable to get block \#%s from peer\: %s
+duniter4j.blockIndexerService.detectFork.resync=[%s] [%s] Rollback index from block \#%s, and resync
+duniter4j.blockIndexerService.indexBlock=[%s] [%s] Indexing block \#%s - hash [%s]
+duniter4j.blockIndexerService.indexLastBlocks.invalidBlockchain=
+duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task=Indexing missing blocks of [%s] from other peers
+duniter4j.blockIndexerService.indexLastBlocks.progress=[%s] [%s] Indexing block \#%s / %s (%s%%)...
+duniter4j.blockIndexerService.indexLastBlocks.remoteParametersError=[%s] Error when calling [/blockchain/parameters]\: %s
+duniter4j.blockIndexerService.indexLastBlocks.stopped=[%s] [%s] Indexing last block - stopped
+duniter4j.blockIndexerService.indexLastBlocks.succeed=[%s] [%s] All blocks indexed [%s ms]
+duniter4j.blockIndexerService.indexLastBlocks.task=[%s] [%s] Indexing last blocks...
 duniter4j.config.option.basedir.description=
 duniter4j.config.option.data.directory.description=
 duniter4j.config.option.elasticsearch.bulk.enable.description=
@@ -31,5 +38,7 @@ duniter4j.executor.task.waitingExecution=
 duniter4j.job.stopped=
 duniter4j.job.stopping=
 duniter4j.job.success=
-duniter4j.task.issuer.system=
-duniter4j.task.starting=
+duniter4j.removeServiceUtils.waitThenRetry=
+duniter4j.task.issuer.system=System
+duniter4j.task.starting=Starting task...
+duniter4j.threadPool.clusterHealthStatus.changed=
diff --git a/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_fr_FR.properties b/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_fr_FR.properties
index f1e0263f4b085ee3026df8d9c68b3f971767f435..1ed787a11c6d3a2ab895f504f3a0940cdd8bc226 100644
--- a/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_fr_FR.properties
+++ b/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_fr_FR.properties
@@ -1,9 +1,16 @@
 duniter4j-elasticsearch.config=
-duniter4j.blockIndexerService.indexBlock=
-duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task=
-duniter4j.blockIndexerService.indexLastBlocks.progress=
-duniter4j.blockIndexerService.indexLastBlocks.stopped=
-duniter4j.blockIndexerService.indexLastBlocks.task=
+duniter4j.blockIndexerService.detectFork.invalidBlock=[%s] [%s] Detecting fork\: block \#%s -> new hash [%s]
+duniter4j.blockIndexerService.detectFork.invalidBlockchain=[%s] [%s] Peer has another blockchain (no common blocks \!). Skipping block \#%s - hash [%s].
+duniter4j.blockIndexerService.detectFork.remoteBlockNotFound=[%s] [%s] Unable to get block \#%s from peer\: %s
+duniter4j.blockIndexerService.detectFork.resync=[%s] [%s] Rollback index from block \#%s, and resync
+duniter4j.blockIndexerService.indexBlock=[%s] [%s] Indexing block \#%s - hash [%s]
+duniter4j.blockIndexerService.indexLastBlocks.invalidBlockchain=
+duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task=Indexing missing blocks of [%s] from other peers
+duniter4j.blockIndexerService.indexLastBlocks.progress=[%s] [%s] Indexing block \#%s / %s (%s%%)...
+duniter4j.blockIndexerService.indexLastBlocks.remoteParametersError=[%s] Error when calling [/blockchain/parameters]\: %s
+duniter4j.blockIndexerService.indexLastBlocks.stopped=[%s] [%s] Indexing last block - stopped
+duniter4j.blockIndexerService.indexLastBlocks.succeed=[%s] [%s] All blocks indexed [%s ms]
+duniter4j.blockIndexerService.indexLastBlocks.task=[%s] [%s] Indexing last blocks...
 duniter4j.config.option.basedir.description=
 duniter4j.config.option.data.directory.description=
 duniter4j.config.option.elasticsearch.bulk.enable.description=
@@ -31,5 +38,8 @@ duniter4j.executor.task.waitingExecution=
 duniter4j.job.stopped=
 duniter4j.job.stopping=
 duniter4j.job.success=
-duniter4j.task.issuer.system=
-duniter4j.task.starting=
+duniter4j.removeServiceUtils.waitThenRetry=Remote request failed [%s]. Waiting then retry [%s/%s]...
+duniter4j.task.issuer.system=Système
+duniter4j.task.starting=Démarrage du traitement...
+duniter4j.threadPool.clusterHealthStatus.changed=Cluster health status changed to [%s]. Executing pending job...
+uniter4j.blockIndexerService.indexLastBlocks.invalidBlockchain=[%s] [%s] Peer has another blockchain (no common blocks \!). Skipping last blocks indexation.
diff --git a/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_en_GB.properties b/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_en_GB.properties
deleted file mode 100644
index 77a2c0aec9ea89542b8ee93664c4e0ae9b67298e..0000000000000000000000000000000000000000
--- a/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_en_GB.properties
+++ /dev/null
@@ -1,51 +0,0 @@
-duniter4j-elasticsearch.config=
-duniter4j.blockIndexerService.indexBlock=[%s] [%s] Indexing block \#%s
-duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task=Indexing missing blocks of [%s] from other peers
-duniter4j.blockIndexerService.indexLastBlocks.progress=[%s] [%s] Indexing block \#%s / %s (%s%%)...
-duniter4j.blockIndexerService.indexLastBlocks.stopped=[%s] [%s] Indexing last block - stopped
-duniter4j.blockIndexerService.indexLastBlocks.task=Indexing last blocks of [%s] from peer [%s\:%s]...
-duniter4j.config.option.basedir.description=
-duniter4j.config.option.cache.directory.description=
-duniter4j.config.option.data.directory.description=
-duniter4j.config.option.elasticsearch.bulk.enable.description=
-duniter4j.config.option.elasticsearch.bulk.size.description=
-duniter4j.config.option.elasticsearch.cluster.name.description=
-duniter4j.config.option.elasticsearch.embedded.enable.description=
-duniter4j.config.option.elasticsearch.host.description=
-duniter4j.config.option.elasticsearch.local.description=
-duniter4j.config.option.i18n.directory.description=
-duniter4j.config.option.i18n.locale.description=
-duniter4j.config.option.index.parallel_processing.description=
-duniter4j.config.option.node.elasticsearch.cluster.name.description=
-duniter4j.config.option.node.elasticsearch.clusterName.description=
-duniter4j.config.option.node.elasticsearch.embeddeb.description=
-duniter4j.config.option.node.elasticsearch.embeddeb.http.description=
-duniter4j.config.option.node.elasticsearch.embeddeb.local.description=
-duniter4j.config.option.node.elasticsearch.embedded.enable.description=
-duniter4j.config.option.node.elasticsearch.embedded.http.enable.description=
-duniter4j.config.option.node.elasticsearch.embedded.local.description=
-duniter4j.config.option.node.elasticsearch.host.description=
-duniter4j.config.option.node.elasticsearch.http.enable.description=
-duniter4j.config.option.node.elasticsearch.local.clusterName.description=
-duniter4j.config.option.node.elasticsearch.local.description=
-duniter4j.config.option.node.elasticsearch.port.description=
-duniter4j.config.option.node.elasticsearch.protocol.description=
-duniter4j.config.option.node.elasticsearch.rest.host.description=
-duniter4j.config.option.node.elasticsearch.rest.port.description=
-duniter4j.config.option.node.elasticsearch.rest.protocol.description=
-duniter4j.config.option.node.elasticsearch.rest.url.description=
-duniter4j.config.option.node.host.description=
-duniter4j.config.option.node.port.description=
-duniter4j.config.option.node.protocol.description=
-duniter4j.config.option.plugins.directory.description=
-duniter4j.config.option.taskExecutor.queueCapacity.description=
-duniter4j.config.option.tasks.queueCapacity.description=
-duniter4j.config.option.tmp.directory.description=
-duniter4j.config.option.version.description=
-duniter4j.config.parse.error=
-duniter4j.executor.task.waitingExecution=
-duniter4j.job.stopped=
-duniter4j.job.stopping=
-duniter4j.job.success=
-duniter4j.task.issuer.system=System
-duniter4j.task.starting=Starting task...
diff --git a/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_fr_FR.properties b/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_fr_FR.properties
deleted file mode 100644
index 9a9c287b5aa7adc634d189df50b6c1c0c63c3236..0000000000000000000000000000000000000000
--- a/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_fr_FR.properties
+++ /dev/null
@@ -1,51 +0,0 @@
-duniter4j-elasticsearch.config=
-duniter4j.blockIndexerService.indexBlock=[%s] [%s] Indexing block \#%s
-duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task=Indexing missing blocks of [%s] from other peers
-duniter4j.blockIndexerService.indexLastBlocks.progress=[%s] [%s] Indexing block \#%s / %s (%s%%)...
-duniter4j.blockIndexerService.indexLastBlocks.stopped=[%s] [%s] Indexing last block - stopped
-duniter4j.blockIndexerService.indexLastBlocks.task=Indexing last blocks of [%s] from peer [%s\:%s]...
-duniter4j.config.option.basedir.description=
-duniter4j.config.option.cache.directory.description=
-duniter4j.config.option.data.directory.description=
-duniter4j.config.option.elasticsearch.bulk.enable.description=
-duniter4j.config.option.elasticsearch.bulk.size.description=
-duniter4j.config.option.elasticsearch.cluster.name.description=
-duniter4j.config.option.elasticsearch.embedded.enable.description=
-duniter4j.config.option.elasticsearch.host.description=
-duniter4j.config.option.elasticsearch.local.description=
-duniter4j.config.option.i18n.directory.description=
-duniter4j.config.option.i18n.locale.description=
-duniter4j.config.option.index.parallel_processing.description=
-duniter4j.config.option.node.elasticsearch.cluster.name.description=
-duniter4j.config.option.node.elasticsearch.clusterName.description=
-duniter4j.config.option.node.elasticsearch.embeddeb.description=
-duniter4j.config.option.node.elasticsearch.embeddeb.http.description=
-duniter4j.config.option.node.elasticsearch.embeddeb.local.description=
-duniter4j.config.option.node.elasticsearch.embedded.enable.description=
-duniter4j.config.option.node.elasticsearch.embedded.http.enable.description=
-duniter4j.config.option.node.elasticsearch.embedded.local.description=
-duniter4j.config.option.node.elasticsearch.host.description=
-duniter4j.config.option.node.elasticsearch.http.enable.description=
-duniter4j.config.option.node.elasticsearch.local.clusterName.description=
-duniter4j.config.option.node.elasticsearch.local.description=
-duniter4j.config.option.node.elasticsearch.port.description=
-duniter4j.config.option.node.elasticsearch.protocol.description=
-duniter4j.config.option.node.elasticsearch.rest.host.description=
-duniter4j.config.option.node.elasticsearch.rest.port.description=
-duniter4j.config.option.node.elasticsearch.rest.protocol.description=
-duniter4j.config.option.node.elasticsearch.rest.url.description=
-duniter4j.config.option.node.host.description=
-duniter4j.config.option.node.port.description=
-duniter4j.config.option.node.protocol.description=
-duniter4j.config.option.plugins.directory.description=
-duniter4j.config.option.taskExecutor.queueCapacity.description=
-duniter4j.config.option.tasks.queueCapacity.description=
-duniter4j.config.option.tmp.directory.description=
-duniter4j.config.option.version.description=
-duniter4j.config.parse.error=
-duniter4j.executor.task.waitingExecution=
-duniter4j.job.stopped=
-duniter4j.job.stopping=
-duniter4j.job.success=
-duniter4j.task.issuer.system=Système
-duniter4j.task.starting=Démarrage du traitement...
diff --git a/duniter4j-elasticsearch/src/test/es-home/config/elasticsearch.yml b/duniter4j-elasticsearch/src/test/es-home/config/elasticsearch.yml
index 54ccf34ddf381f34abc31f327276c0870a52a7e4..c72e3748928a8ab471ab4e3700c57deebb90ff84 100644
--- a/duniter4j-elasticsearch/src/test/es-home/config/elasticsearch.yml
+++ b/duniter4j-elasticsearch/src/test/es-home/config/elasticsearch.yml
@@ -15,13 +15,13 @@
 # Use a descriptive name for your cluster:
 #
 # cluster.name: my-application
-cluster.name: duniter4j-elasticsearch
+cluster.name: duniter4j-elasticsearch-TEST
 #
 # ------------------------------------ Node ------------------------------------
 #
 # Use a descriptive name for the node:
 #
-# node.name: node-1
+node.name: EIS-DEV
 #
 # Add custom attributes to the node:
 #
@@ -53,13 +53,13 @@ cluster.name: duniter4j-elasticsearch
 # Set the bind address to a specific IP (IPv4 or IPv6):
 #
 # network.host: 192.168.0.1
-#network.host: 192.168.0.28
+network.host: 192.168.0.28
 #
 # Set a custom port for HTTP:
 #
 # http.port: 9200
 
-#http.port: 9200
+http.port: 9203
 
 http.cors.allow-origin: "/.*/"
 http.cors.enabled: true
@@ -73,7 +73,7 @@ http.cors.enabled: true
 # Pass an initial list of hosts to perform discovery when new node is started:
 # The default list of hosts is ["127.0.0.1", "[::1]"]
 #
-# discovery.zen.ping.unicast.hosts: ["host1", "host2"]
+discovery.zen.ping.unicast.hosts: ["192.168.0.5", "192.168.0.28"]
 #discovery.zen.ping.unicast.hosts: ["127.0.0.1", ""]
 #
 # Prevent the "split brain" by configuring the majority of nodes (total number of nodes / 2 + 1):
@@ -100,7 +100,7 @@ http.cors.enabled: true
 #
 # Require explicit names when deleting indices:
 #
-# action.destructive_requires_name: true
+action.destructive_requires_name: true
 
 security.manager.enabled: false
 
@@ -111,6 +111,8 @@ security.manager.enabled: false
 
 duniter.host: 192.168.0.5
 duniter.port: 9201
+#duniter.host: 192.168.0.28
+#duniter.port: 9202
 
 duniter.string.analyzer: french
 
diff --git a/pom.xml b/pom.xml
index 963d3a2141a60c2a3ada8b0671b906c3ed046b00..b4a8415175100b7f8db3edb41b0be696469272bd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
     <jna.version>4.1.0</jna.version>
     <tyrus.version>1.12</tyrus.version>
 
-    <cesium.version>0.2.1</cesium.version>
+    <cesium.version>0.2.12</cesium.version>
 
     <nuitonConfigVersion>3.0-rc-4</nuitonConfigVersion>
     <nuitonI18nVersion>3.5</nuitonI18nVersion>