diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/elasticsearch/MessageRecord.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/elasticsearch/MessageRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..660ea84985b7be84c54bcd04315a4b39a2f688cf
--- /dev/null
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/elasticsearch/MessageRecord.java
@@ -0,0 +1,51 @@
+package org.duniter.core.client.model.elasticsearch;
+
+/*
+ * #%L
+ * Duniter4j :: 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%
+ */
+
+/**
+ * Created by blavenie on 01/03/16.
+ */
+public class MessageRecord extends Record {
+
+    public static final String PROPERTY_TIME="time";
+    public static final String PROPERTY_MESSAGE="message";
+
+    private Integer time;
+    private String message;
+
+    public Integer getTime() {
+        return time;
+    }
+
+    public void setTime(Integer time) {
+        this.time = time;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/action/RestModule.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/action/RestModule.java
index fdbff9e287eab47c40059cc18d2338f90128a4fd..8ef4f7a8c09f5977f4b139c47eae55178ce000ff 100644
--- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/action/RestModule.java
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/action/RestModule.java
@@ -23,6 +23,7 @@ package org.duniter.elasticsearch.action;
  */
 
 import org.duniter.elasticsearch.action.currency.RestCurrencyIndexAction;
+import org.duniter.elasticsearch.action.market.RestMarketCommentIndexAction;
 import org.duniter.elasticsearch.action.market.RestMarketRecordIndexAction;
 import org.duniter.elasticsearch.action.registry.RestRegistryRecordIndexAction;
 import org.duniter.elasticsearch.action.security.RestSecurityAuthAction;
@@ -35,6 +36,7 @@ public class RestModule extends AbstractModule implements Module {
     @Override protected void configure() {
         bind(RestCurrencyIndexAction.class).asEagerSingleton();
         bind(RestMarketRecordIndexAction.class).asEagerSingleton();
+        bind(RestMarketCommentIndexAction.class).asEagerSingleton();
         bind(RestRegistryRecordIndexAction.class).asEagerSingleton();
 
         bind(RestSecurityGetChallengeAction.class).asEagerSingleton();
diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/action/market/RestMarketCommentIndexAction.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/action/market/RestMarketCommentIndexAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..d43148bc299060125628dbcdf3967f843ca61cf2
--- /dev/null
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/action/market/RestMarketCommentIndexAction.java
@@ -0,0 +1,68 @@
+package org.duniter.elasticsearch.action.market;
+
+/*
+ * #%L
+ * duniter4j-elasticsearch-plugin
+ * %%
+ * 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;
+import org.duniter.elasticsearch.service.MarketService;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.common.inject.Inject;
+import org.elasticsearch.common.logging.ESLogger;
+import org.elasticsearch.common.logging.ESLoggerFactory;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.rest.*;
+
+import static org.elasticsearch.rest.RestRequest.Method.POST;
+import static org.elasticsearch.rest.RestStatus.BAD_REQUEST;
+import static org.elasticsearch.rest.RestStatus.OK;
+
+public class RestMarketCommentIndexAction extends BaseRestHandler {
+
+    private static final ESLogger log = ESLoggerFactory.getLogger(RestMarketCommentIndexAction.class.getName());
+
+    private MarketService service;
+
+    @Inject
+    public RestMarketCommentIndexAction(Settings settings, RestController controller, Client client, MarketService service) {
+        super(settings, controller, client);
+        controller.registerHandler(POST, "/market/comment", this);
+        this.service = service;
+    }
+
+    @Override
+    protected void handleRequest(final RestRequest request, RestChannel restChannel, Client client) throws Exception {
+
+        try {
+            String recordId = service.indexCommentFromJson(request.content().toUtf8());
+
+            restChannel.sendResponse(new BytesRestResponse(OK, recordId));
+        }
+        catch(BusinessException e) {
+            log.error(e.getMessage(), e);
+            restChannel.sendResponse(new BytesRestResponse(BAD_REQUEST, String.format("{error: {ucode: 'XXX', message:'%s'}}", e.getMessage())));
+        }
+        catch(Exception e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+
+}
\ No newline at end of file
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 d3ba09d2ab433c947e1c8a0dd071cb75d7dce551..2840c839a79d1b37ce91344997ddbc57229e8c74 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
@@ -26,6 +26,7 @@ import org.duniter.core.client.model.local.Peer;
 import org.duniter.elasticsearch.PluginSettings;
 import org.duniter.elasticsearch.service.BlockchainService;
 import org.duniter.elasticsearch.service.MarketService;
+import org.duniter.elasticsearch.service.MessageService;
 import org.duniter.elasticsearch.service.RegistryService;
 import org.duniter.elasticsearch.threadpool.ThreadPool;
 import org.elasticsearch.common.component.AbstractLifecycleComponent;
@@ -85,6 +86,9 @@ public class DuniterNode extends AbstractLifecycleComponent<DuniterNode> {
                     .deleteIndex()
                     .createIndexIfNotExists()
                     .fillRecordCategories();
+            injector.getInstance(MessageService.class)
+                    .deleteIndex()
+                    .createIndexIfNotExists();
 
             injector.getInstance(BlockchainService.class)
                     .indexLastBlocks(peer);
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 15f20772f0d8df32b90089f8e16fc9a93a374d61..1795ce20d0ca4f110c68f22e8ad1bb892f52b16c 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
@@ -54,6 +54,7 @@ public class MarketService extends AbstractService {
     public static final String INDEX = "market";
     public static final String RECORD_CATEGORY_TYPE = "category";
     public static final String RECORD_TYPE = "record";
+    public static final String RECORD_COMMENT_TYPE = "comment";
 
     private static final String CATEGORIES_BULK_CLASSPATH_FILE = "market-categories-bulk-insert.json";
     private static final String JSON_STRING_PROPERTY_REGEX = "[,]?[\"\\s\\n\\r]*%s[\"]?[\\s\\n\\r]*:[\\s\\n\\r]*\"[^\"]+\"";
@@ -114,6 +115,7 @@ public class MarketService extends AbstractService {
         createIndexRequestBuilder.setSettings(indexSettings);
         createIndexRequestBuilder.addMapping(RECORD_CATEGORY_TYPE, createRecordCategoryType());
         createIndexRequestBuilder.addMapping(RECORD_TYPE, createRecordType());
+        createIndexRequestBuilder.addMapping(RECORD_COMMENT_TYPE, createRecordCommentType());
         createIndexRequestBuilder.execute().actionGet();
 
         return this;
@@ -185,6 +187,50 @@ public class MarketService extends AbstractService {
         return response.getId();
     }
 
+    public String indexCommentFromJson(String commentJson) {
+
+        try {
+            JsonNode actualObj = objectMapper.readTree(commentJson);
+            Set<String> fieldNames = Sets.newHashSet(actualObj.fieldNames());
+            if (!fieldNames.contains(Record.PROPERTY_ISSUER)
+                    || !fieldNames.contains(Record.PROPERTY_SIGNATURE)) {
+                throw new InvalidFormatException(String.format("Invalid comment JSON format. Required fields [%s,%s]",
+                        Record.PROPERTY_ISSUER, Record.PROPERTY_SIGNATURE));
+            }
+            String issuer = actualObj.get(Record.PROPERTY_ISSUER).asText();
+            String signature = actualObj.get(Record.PROPERTY_SIGNATURE).asText();
+
+            String recordNoSign = commentJson.replaceAll(String.format(JSON_STRING_PROPERTY_REGEX, Record.PROPERTY_SIGNATURE), "")
+                    .replaceAll(String.format(JSON_STRING_PROPERTY_REGEX, Record.PROPERTY_HASH), "");
+
+            if (!cryptoService.verify(recordNoSign, signature, issuer)) {
+                throw new InvalidSignatureException("Invalid signature for JSON string: " + recordNoSign);
+            }
+
+            // TODO : check if issuer is a valid member
+            //wotRemoteService.getRequirments();
+
+            if (logger.isDebugEnabled()) {
+                logger.debug(String.format("Indexing a comment from issuer [%s]", issuer.substring(0, 8)));
+            }
+
+        }
+        catch(IOException | JsonSyntaxException e) {
+            throw new InvalidFormatException("Invalid comment JSON: " + e.getMessage(), e);
+        }
+
+        // Preparing indexBlocksFromNode
+        IndexRequestBuilder indexRequest = client.prepareIndex(INDEX, RECORD_COMMENT_TYPE)
+                .setSource(commentJson);
+
+        // Execute indexBlocksFromNode
+        IndexResponse response = indexRequest
+                .setRefresh(false)
+                .execute().actionGet();
+
+        return response.getId();
+    }
+
     public void fillRecordCategories() {
         if (logger.isDebugEnabled()) {
             logger.debug(String.format("[%s/%s] Fill data", INDEX, RECORD_CATEGORY_TYPE));
@@ -315,10 +361,10 @@ public class MarketService extends AbstractService {
                     .field("type", "nested")
                     .field("dynamic", "false")
                         .startObject("properties")
-                            .startObject("file") // src
+                            .startObject("file") // file
                                 .field("type", "attachment")
-                                .startObject("fields") // src
-                                    .startObject("content") // title
+                                .startObject("fields")
+                                    .startObject("content") // content
                                         .field("index", "no")
                                     .endObject()
                                     .startObject("title") // title
@@ -326,11 +372,11 @@ public class MarketService extends AbstractService {
                                         .field("store", "yes")
                                         .field("analyzer", stringAnalyzer)
                                     .endObject()
-                                    .startObject("author") // title
+                                    .startObject("author") // author
                                         .field("type", "string")
                                         .field("store", "no")
                                     .endObject()
-                                    .startObject("content_type") // title
+                                    .startObject("content_type") // content_type
                                         .field("store", "yes")
                                     .endObject()
                                 .endObject()
@@ -376,4 +422,50 @@ public class MarketService extends AbstractService {
         }
     }
 
+    public XContentBuilder createRecordCommentType() {
+        String stringAnalyzer = pluginSettings.getDefaultStringAnalyzer();
+
+        try {
+            XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject(RECORD_COMMENT_TYPE)
+                    .startObject("properties")
+
+                    // issuer
+                    .startObject("issuer")
+                    .field("type", "string")
+                    .field("index", "not_analyzed")
+                    .endObject()
+
+                    // time
+                    .startObject("time")
+                    .field("type", "integer")
+                    .endObject()
+
+                    // message
+                    .startObject("message")
+                    .field("type", "string")
+                    .field("analyzer", stringAnalyzer)
+                    .endObject()
+
+                    // record
+                    .startObject("record")
+                    .field("type", "string")
+                    .field("index", "not_analyzed")
+                    .endObject()
+
+                    // reply to
+                    .startObject("reply_to")
+                    .field("type", "string")
+                    .field("index", "not_analyzed")
+                    .endObject()
+
+                    .endObject()
+                    .endObject().endObject();
+
+            return mapping;
+        }
+        catch(IOException ioe) {
+            throw new TechnicalException(String.format("Error while getting mapping for index [%s/%s]: %s", INDEX, RECORD_COMMENT_TYPE, ioe.getMessage()), ioe);
+        }
+    }
+
 }
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
new file mode 100644
index 0000000000000000000000000000000000000000..1f0a236953576772c028a6ef730abf79ba118722
--- /dev/null
+++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MessageService.java
@@ -0,0 +1,239 @@
+package org.duniter.elasticsearch.service;
+
+/*
+ * #%L
+ * UCoin Java Client :: Core API
+ * %%
+ * Copyright (C) 2014 - 2015 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 com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.Sets;
+import com.google.gson.JsonSyntaxException;
+import org.duniter.core.client.model.elasticsearch.MessageRecord;
+import org.duniter.core.client.service.bma.WotRemoteService;
+import org.duniter.core.exception.TechnicalException;
+import org.duniter.core.service.CryptoService;
+import org.duniter.elasticsearch.PluginSettings;
+import org.duniter.elasticsearch.exception.InvalidFormatException;
+import org.duniter.elasticsearch.exception.InvalidSignatureException;
+import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
+import org.elasticsearch.action.index.IndexRequestBuilder;
+import org.elasticsearch.action.index.IndexResponse;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.common.inject.Inject;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentFactory;
+
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ * Created by Benoit on 30/03/2015.
+ */
+public class MessageService extends AbstractService {
+
+    public static final String INDEX = "message";
+    public static final String RECORD_TYPE = "record";
+
+    private static final String JSON_STRING_PROPERTY_REGEX = "[,]?[\"\\s\\n\\r]*%s[\"]?[\\s\\n\\r]*:[\\s\\n\\r]*\"[^\"]+\"";
+
+    private CryptoService cryptoService;
+    private WotRemoteService wotRemoteService;
+
+    @Inject
+    public MessageService(Client client, PluginSettings settings, CryptoService cryptoService, WotRemoteService wotRemoteService) {
+        super(client, settings);
+        this.cryptoService = cryptoService;
+        this.wotRemoteService = wotRemoteService;
+    }
+
+    /**
+     * Delete blockchain index, and all data
+     * @throws JsonProcessingException
+     */
+    public MessageService deleteIndex() {
+        deleteIndexIfExists(INDEX);
+        return this;
+    }
+
+
+    public boolean existsIndex() {
+        return super.existsIndex(INDEX);
+    }
+
+    /**
+     * Create index need for blockchain registry, if need
+     */
+    public MessageService createIndexIfNotExists() {
+        try {
+            if (!existsIndex(INDEX)) {
+                createIndex();
+            }
+        }
+        catch(JsonProcessingException e) {
+            throw new TechnicalException(String.format("Error while creating index [%s]", INDEX));
+        }
+
+        return this;
+    }
+
+    /**
+     * Create index need for category registry
+     * @throws JsonProcessingException
+     */
+    public MessageService createIndex() throws JsonProcessingException {
+        logger.info(String.format("Creating index [%s/%s]", INDEX, RECORD_TYPE));
+
+        CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(INDEX);
+        Settings indexSettings = Settings.settingsBuilder()
+                .put("number_of_shards", 2)
+                .put("number_of_replicas", 1)
+                //.put("analyzer", createDefaultAnalyzer())
+                .build();
+        createIndexRequestBuilder.setSettings(indexSettings);
+        createIndexRequestBuilder.addMapping(RECORD_TYPE, createRecordType());
+        createIndexRequestBuilder.execute().actionGet();
+
+        return this;
+    }
+
+    public String indexRecordFromJson(String recordJson) {
+
+        try {
+            JsonNode actualObj = objectMapper.readTree(recordJson);
+            Set<String> fieldNames = Sets.newHashSet(actualObj.fieldNames());
+            if (!fieldNames.contains(MessageRecord.PROPERTY_ISSUER)
+                    || !fieldNames.contains(MessageRecord.PROPERTY_SIGNATURE)) {
+                throw new InvalidFormatException(String.format("Invalid record JSON format. Required fields [%s,%s]", MessageRecord.PROPERTY_ISSUER, MessageRecord.PROPERTY_SIGNATURE));
+            }
+            String issuer = actualObj.get(MessageRecord.PROPERTY_ISSUER).asText();
+
+            String signature = actualObj.get(MessageRecord.PROPERTY_SIGNATURE).asText();
+
+            String recordNoSign = recordJson.replaceAll(String.format(JSON_STRING_PROPERTY_REGEX, MessageRecord.PROPERTY_SIGNATURE), "");
+
+            if (!cryptoService.verify(recordNoSign, signature, issuer)) {
+                throw new InvalidSignatureException("Invalid signature for JSON string: " + recordNoSign);
+            }
+
+            // TODO : check if issuer is a valid member
+            //wotRemoteService.getRequirments();
+
+            if (logger.isDebugEnabled()) {
+                logger.debug(String.format("Indexing a record from issuer [%s]", issuer.substring(0, 8)));
+            }
+
+        }
+        catch(IOException | JsonSyntaxException e) {
+            throw new InvalidFormatException("Invalid record JSON: " + e.getMessage(), e);
+        }
+
+        // Preparing indexBlocksFromNode
+        IndexRequestBuilder indexRequest = client.prepareIndex(INDEX, RECORD_TYPE)
+                .setSource(recordJson);
+
+        // Execute indexBlocksFromNode
+        IndexResponse response = indexRequest
+                .setRefresh(false)
+                .execute().actionGet();
+
+        return response.getId();
+    }
+
+    /* -- Internal methods -- */
+
+    public XContentBuilder createRecordType() {
+        String stringAnalyzer = pluginSettings.getDefaultStringAnalyzer();
+
+        try {
+            XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject(RECORD_TYPE)
+                    .startObject("properties")
+
+                    // issuer
+                    .startObject("issuer")
+                    .field("type", "string")
+                    .field("index", "not_analyzed")
+                    .endObject()
+
+                    // time
+                    .startObject("time")
+                    .field("type", "integer")
+                    .endObject()
+
+                    // message
+                    .startObject("message")
+                    .field("type", "string")
+                    .field("analyzer", stringAnalyzer)
+                    .endObject()
+
+                    // pictures
+                    .startObject("pictures")
+                    .field("type", "nested")
+                    .field("dynamic", "false")
+                    .startObject("properties")
+                    .startObject("file") // file
+                    .field("type", "attachment")
+                    .startObject("fields")
+                    .startObject("content") // content
+                    .field("index", "no")
+                    .endObject()
+                    .startObject("title") // title
+                    .field("type", "string")
+                    .field("store", "yes")
+                    .field("analyzer", stringAnalyzer)
+                    .endObject()
+                    .startObject("author") // author
+                    .field("type", "string")
+                    .field("store", "no")
+                    .endObject()
+                    .startObject("content_type") // content_type
+                    .field("store", "yes")
+                    .endObject()
+                    .endObject()
+                    .endObject()
+                    .endObject()
+                    .endObject()
+
+                    // picturesCount
+                    .startObject("picturesCount")
+                    .field("type", "integer")
+                    .endObject()
+
+                    // tags
+                    .startObject("tags")
+                    .field("type", "completion")
+                    .field("search_analyzer", "simple")
+                    .field("analyzer", "simple")
+                    .field("preserve_separators", "false")
+                    .endObject()
+
+                    .endObject()
+                    .endObject().endObject();
+
+            return mapping;
+        }
+        catch(IOException ioe) {
+            throw new TechnicalException(String.format("Error while getting mapping for index [%s/%s]: %s", INDEX, RECORD_TYPE, ioe.getMessage()), ioe);
+        }
+    }
+
+}
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 33ec0d97419612e2e2fea4d59fad5c954ec53494..c22f32c32b5035c65adb12d10117bdb3fb7bca20 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
@@ -51,6 +51,7 @@ public class ServiceModule extends AbstractModule implements Module {
         bind(RegistryService.class);
         bind(MarketService.class);
         bind(BlockchainService.class);
+        bind(MessageService.class);
 
         // Duniter Client API beans
         bindWithLocator(BlockchainRemoteService.class);
diff --git a/duniter4j-elasticsearch/src/test/es-home/logs/elasticsearch.log b/duniter4j-elasticsearch/src/test/es-home/logs/elasticsearch.log
index cad8e5cc32772c0a002edf563f3ad66e73badb58..b4ac2d53153d538efb45c3e9384bdeef80555932 100644
--- a/duniter4j-elasticsearch/src/test/es-home/logs/elasticsearch.log
+++ b/duniter4j-elasticsearch/src/test/es-home/logs/elasticsearch.log
@@ -360,7 +360,7 @@ Caused by: java.security.AccessControlException: access denied ("java.io.FilePer
 [2016-06-17 14:25:28,367][INFO ][org.duniter.elasticsearch.service.ServiceLocator] Starting ServiceLocator [OK]
 [2016-06-17 14:25:30,498][INFO ][node                     ] [Shriek] initialized
 [2016-06-17 14:25:30,498][INFO ][node                     ] [Shriek] starting ...
-[2016-06-17 14:25:30,507][DEBUG][org.duniter.elasticsearch.job.BlockIndexer] Starting indexing blocks from node [cgeek.fr:9330]...
+[2016-06-17 14:25:30,507][DEBUG][org.duniter.elasticsearch.job.ThreadPool] Starting indexing blocks from node [cgeek.fr:9330]...
 [2016-06-17 14:25:30,530][ERROR][bootstrap                ] [Shriek] Exception
 java.lang.NullPointerException
 	at org.elasticsearch.action.support.master.TransportMasterNodeAction$AsyncSingleAction.<init>(TransportMasterNodeAction.java:129)
@@ -375,10 +375,10 @@ java.lang.NullPointerException
 	at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:56)
 	at org.duniter.elasticsearch.service.AbstractService.existsIndex(AbstractService.java:124)
 	at org.duniter.elasticsearch.service.registry.CurrencyRegistryService.deleteAllCurrencies(CurrencyRegistryService.java:292)
-	at org.duniter.elasticsearch.job.BlockIndexer.resetAllCurrencies(BlockIndexer.java:116)
-	at org.duniter.elasticsearch.job.BlockIndexer.resetAllData(BlockIndexer.java:109)
-	at org.duniter.elasticsearch.job.BlockIndexer.start(BlockIndexer.java:87)
-	at org.duniter.elasticsearch.job.BlockIndexer.start(BlockIndexer.java:26)
+	at org.duniter.elasticsearch.job.ThreadPool.resetAllCurrencies(BlockIndexer.java:116)
+	at org.duniter.elasticsearch.job.ThreadPool.resetAllData(BlockIndexer.java:109)
+	at org.duniter.elasticsearch.job.ThreadPool.start(BlockIndexer.java:87)
+	at org.duniter.elasticsearch.job.ThreadPool.start(BlockIndexer.java:26)
 	at org.elasticsearch.node.Node.start(Node.java:255)
 	at org.elasticsearch.bootstrap.Bootstrap.start(Bootstrap.java:206)
 	at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:272)
@@ -403,7 +403,7 @@ java.lang.NullPointerException
 [2016-06-17 14:26:22,683][INFO ][org.duniter.elasticsearch.service.ServiceLocator] Starting ServiceLocator [OK]
 [2016-06-17 14:26:23,933][INFO ][node                     ] [Hank Pym] initialized
 [2016-06-17 14:26:23,933][INFO ][node                     ] [Hank Pym] starting ...
-[2016-06-17 14:26:23,942][DEBUG][org.duniter.elasticsearch.job.BlockIndexer] Starting indexing blocks from node [cgeek.fr:9330]...
+[2016-06-17 14:26:23,942][DEBUG][org.duniter.elasticsearch.job.ThreadPool] Starting indexing blocks from node [cgeek.fr:9330]...
 [2016-06-17 14:26:23,956][ERROR][bootstrap                ] [Hank Pym] Exception
 java.lang.NullPointerException
 	at org.elasticsearch.action.support.master.TransportMasterNodeAction$AsyncSingleAction.<init>(TransportMasterNodeAction.java:129)
@@ -418,10 +418,10 @@ java.lang.NullPointerException
 	at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:56)
 	at org.duniter.elasticsearch.service.AbstractService.existsIndex(AbstractService.java:124)
 	at org.duniter.elasticsearch.service.registry.CurrencyRegistryService.deleteAllCurrencies(CurrencyRegistryService.java:292)
-	at org.duniter.elasticsearch.job.BlockIndexer.resetAllCurrencies(BlockIndexer.java:116)
-	at org.duniter.elasticsearch.job.BlockIndexer.resetAllData(BlockIndexer.java:109)
-	at org.duniter.elasticsearch.job.BlockIndexer.start(BlockIndexer.java:87)
-	at org.duniter.elasticsearch.job.BlockIndexer.start(BlockIndexer.java:26)
+	at org.duniter.elasticsearch.job.ThreadPool.resetAllCurrencies(BlockIndexer.java:116)
+	at org.duniter.elasticsearch.job.ThreadPool.resetAllData(BlockIndexer.java:109)
+	at org.duniter.elasticsearch.job.ThreadPool.start(BlockIndexer.java:87)
+	at org.duniter.elasticsearch.job.ThreadPool.start(BlockIndexer.java:26)
 	at org.elasticsearch.node.Node.start(Node.java:255)
 	at org.elasticsearch.bootstrap.Bootstrap.start(Bootstrap.java:206)
 	at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:272)
@@ -446,7 +446,7 @@ java.lang.NullPointerException
 [2016-06-17 14:26:46,794][INFO ][org.duniter.elasticsearch.service.ServiceLocator] Starting ServiceLocator [OK]
 [2016-06-17 14:26:47,742][INFO ][node                     ] [Deadly Ernest] initialized
 [2016-06-17 14:26:47,743][INFO ][node                     ] [Deadly Ernest] starting ...
-[2016-06-17 14:28:14,538][DEBUG][org.duniter.elasticsearch.job.BlockIndexer] Starting indexing blocks from node [cgeek.fr:9330]...
+[2016-06-17 14:28:14,538][DEBUG][org.duniter.elasticsearch.job.ThreadPool] Starting indexing blocks from node [cgeek.fr:9330]...
 [2016-06-17 14:28:44,333][ERROR][bootstrap                ] [Deadly Ernest] Exception
 java.lang.NullPointerException
 	at org.elasticsearch.action.support.master.TransportMasterNodeAction$AsyncSingleAction.<init>(TransportMasterNodeAction.java:129)
@@ -461,10 +461,10 @@ java.lang.NullPointerException
 	at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:56)
 	at org.duniter.elasticsearch.service.AbstractService.existsIndex(AbstractService.java:124)
 	at org.duniter.elasticsearch.service.registry.CurrencyRegistryService.deleteAllCurrencies(CurrencyRegistryService.java:292)
-	at org.duniter.elasticsearch.job.BlockIndexer.resetAllCurrencies(BlockIndexer.java:116)
-	at org.duniter.elasticsearch.job.BlockIndexer.resetAllData(BlockIndexer.java:109)
-	at org.duniter.elasticsearch.job.BlockIndexer.start(BlockIndexer.java:87)
-	at org.duniter.elasticsearch.job.BlockIndexer.start(BlockIndexer.java:26)
+	at org.duniter.elasticsearch.job.ThreadPool.resetAllCurrencies(BlockIndexer.java:116)
+	at org.duniter.elasticsearch.job.ThreadPool.resetAllData(BlockIndexer.java:109)
+	at org.duniter.elasticsearch.job.ThreadPool.start(BlockIndexer.java:87)
+	at org.duniter.elasticsearch.job.ThreadPool.start(BlockIndexer.java:26)
 	at org.elasticsearch.node.Node.start(Node.java:255)
 	at org.elasticsearch.bootstrap.Bootstrap.start(Bootstrap.java:206)
 	at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:272)
@@ -489,7 +489,7 @@ java.lang.NullPointerException
 [2016-06-17 14:33:26,094][INFO ][org.duniter.elasticsearch.service.ServiceLocator] Starting ServiceLocator [OK]
 [2016-06-17 14:33:27,148][INFO ][node                     ] [Benny Beckley] initialized
 [2016-06-17 14:33:27,153][INFO ][node                     ] [Benny Beckley] starting ...
-[2016-06-17 14:33:27,157][DEBUG][org.duniter.elasticsearch.job.BlockIndexer] Starting indexing blocks from node [cgeek.fr:9330]...
+[2016-06-17 14:33:27,157][DEBUG][org.duniter.elasticsearch.job.ThreadPool] Starting indexing blocks from node [cgeek.fr:9330]...
 [2016-06-17 14:33:27,478][INFO ][transport                ] [Benny Beckley] publish_address {127.0.0.1:9300}, bound_addresses {[::1]:9300}, {127.0.0.1:9300}
 [2016-06-17 14:33:27,488][INFO ][discovery                ] [Benny Beckley] elasticsearch/ERtxwf1iRrGMEdv5AlmsTw
 [2016-06-17 14:33:30,605][INFO ][cluster.service          ] [Benny Beckley] new_master {Benny Beckley}{ERtxwf1iRrGMEdv5AlmsTw}{127.0.0.1}{127.0.0.1:9300}, reason: zen-disco-join(elected_as_master, [0] joins received)
@@ -516,7 +516,7 @@ java.lang.NullPointerException
 [2016-06-17 14:38:52,617][INFO ][org.duniter.elasticsearch.service.ServiceLocator] Starting ServiceLocator [OK]
 [2016-06-17 14:38:55,540][INFO ][node                     ] [Abyss] initialized
 [2016-06-17 14:38:55,540][INFO ][node                     ] [Abyss] starting ...
-[2016-06-17 14:38:55,543][DEBUG][org.duniter.elasticsearch.job.BlockIndexer] Starting indexing blocks from node [cgeek.fr:9330]...
+[2016-06-17 14:38:55,543][DEBUG][org.duniter.elasticsearch.job.ThreadPool] Starting indexing blocks from node [cgeek.fr:9330]...
 [2016-06-17 14:38:55,556][ERROR][bootstrap                ] [Abyss] Exception
 java.lang.NullPointerException
 	at org.elasticsearch.action.support.master.TransportMasterNodeAction$AsyncSingleAction.<init>(TransportMasterNodeAction.java:129)
@@ -531,10 +531,10 @@ java.lang.NullPointerException
 	at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:56)
 	at org.duniter.elasticsearch.service.AbstractService.existsIndex(AbstractService.java:124)
 	at org.duniter.elasticsearch.service.registry.CurrencyRegistryService.deleteAllCurrencies(CurrencyRegistryService.java:292)
-	at org.duniter.elasticsearch.job.BlockIndexer.resetAllCurrencies(BlockIndexer.java:116)
-	at org.duniter.elasticsearch.job.BlockIndexer.resetAllData(BlockIndexer.java:109)
-	at org.duniter.elasticsearch.job.BlockIndexer.start(BlockIndexer.java:87)
-	at org.duniter.elasticsearch.job.BlockIndexer.start(BlockIndexer.java:26)
+	at org.duniter.elasticsearch.job.ThreadPool.resetAllCurrencies(BlockIndexer.java:116)
+	at org.duniter.elasticsearch.job.ThreadPool.resetAllData(BlockIndexer.java:109)
+	at org.duniter.elasticsearch.job.ThreadPool.start(BlockIndexer.java:87)
+	at org.duniter.elasticsearch.job.ThreadPool.start(BlockIndexer.java:26)
 	at org.elasticsearch.node.Node.start(Node.java:255)
 	at org.elasticsearch.bootstrap.Bootstrap.start(Bootstrap.java:206)
 	at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:272)
@@ -548,3 +548,75 @@ java.lang.NullPointerException
 [2016-06-17 14:38:55,582][INFO ][node                     ] [Abyss] stopped
 [2016-06-17 14:38:55,582][INFO ][node                     ] [Abyss] closing ...
 [2016-06-17 14:38:55,597][INFO ][node                     ] [Abyss] closed
+[2016-06-17 16:12:04,866][INFO ][node                     ] [David Cannon] version[2.3.3], pid[20539], build[NA/NA]
+[2016-06-17 16:12:04,866][INFO ][node                     ] [David Cannon] initializing ...
+[2016-06-17 16:12:04,887][ERROR][bootstrap                ] Exception
+java.lang.ExceptionInInitializerError
+	at org.apache.lucene.codecs.Codec.reloadCodecs(Codec.java:133)
+	at org.elasticsearch.plugins.PluginsService.reloadLuceneSPI(PluginsService.java:454)
+	at org.elasticsearch.plugins.PluginsService.loadBundles(PluginsService.java:430)
+	at org.elasticsearch.plugins.PluginsService.<init>(PluginsService.java:129)
+	at org.elasticsearch.node.Node.<init>(Node.java:158)
+	at org.elasticsearch.node.Node.<init>(Node.java:140)
+	at org.elasticsearch.node.NodeBuilder.build(NodeBuilder.java:143)
+	at org.elasticsearch.bootstrap.Bootstrap.setup(Bootstrap.java:178)
+	at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:270)
+	at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:35)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+	at java.lang.reflect.Method.invoke(Method.java:606)
+	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:294)
+	at java.lang.Thread.run(Thread.java:745)
+Caused by: java.lang.IllegalArgumentException: An SPI class of type org.apache.lucene.codecs.Codec with name 'Lucene54' does not exist.  You need to add the corresponding JAR file supporting this SPI to your classpath.  The current classpath supports the following names: []
+	at org.apache.lucene.util.NamedSPILoader.lookup(NamedSPILoader.java:114)
+	at org.apache.lucene.codecs.Codec$Holder.<clinit>(Codec.java:60)
+	... 16 more
+[2016-06-17 16:15:53,526][INFO ][node                     ] [Sun Girl] version[2.3.3], pid[21922], build[NA/NA]
+[2016-06-17 16:15:53,526][INFO ][node                     ] [Sun Girl] initializing ...
+[2016-06-17 16:15:53,543][ERROR][bootstrap                ] Exception
+java.lang.ExceptionInInitializerError
+	at org.apache.lucene.codecs.Codec.reloadCodecs(Codec.java:133)
+	at org.elasticsearch.plugins.PluginsService.reloadLuceneSPI(PluginsService.java:454)
+	at org.elasticsearch.plugins.PluginsService.loadBundles(PluginsService.java:430)
+	at org.elasticsearch.plugins.PluginsService.<init>(PluginsService.java:129)
+	at org.elasticsearch.node.Node.<init>(Node.java:158)
+	at org.elasticsearch.node.Node.<init>(Node.java:140)
+	at org.elasticsearch.node.NodeBuilder.build(NodeBuilder.java:143)
+	at org.elasticsearch.bootstrap.Bootstrap.setup(Bootstrap.java:178)
+	at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:270)
+	at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:35)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+	at java.lang.reflect.Method.invoke(Method.java:606)
+	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:294)
+	at java.lang.Thread.run(Thread.java:745)
+Caused by: java.lang.IllegalArgumentException: An SPI class of type org.apache.lucene.codecs.Codec with name 'Lucene54' does not exist.  You need to add the corresponding JAR file supporting this SPI to your classpath.  The current classpath supports the following names: []
+	at org.apache.lucene.util.NamedSPILoader.lookup(NamedSPILoader.java:114)
+	at org.apache.lucene.codecs.Codec$Holder.<clinit>(Codec.java:60)
+	... 16 more
+[2016-06-17 16:16:36,983][INFO ][node                     ] [Maverick] version[2.3.3], pid[22012], build[NA/NA]
+[2016-06-17 16:16:36,983][INFO ][node                     ] [Maverick] initializing ...
+[2016-06-17 16:16:37,001][ERROR][bootstrap                ] Exception
+java.lang.ExceptionInInitializerError
+	at org.apache.lucene.codecs.Codec.reloadCodecs(Codec.java:133)
+	at org.elasticsearch.plugins.PluginsService.reloadLuceneSPI(PluginsService.java:454)
+	at org.elasticsearch.plugins.PluginsService.loadBundles(PluginsService.java:430)
+	at org.elasticsearch.plugins.PluginsService.<init>(PluginsService.java:129)
+	at org.elasticsearch.node.Node.<init>(Node.java:158)
+	at org.elasticsearch.node.Node.<init>(Node.java:140)
+	at org.elasticsearch.node.NodeBuilder.build(NodeBuilder.java:143)
+	at org.elasticsearch.bootstrap.Bootstrap.setup(Bootstrap.java:178)
+	at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:270)
+	at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:35)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+	at java.lang.reflect.Method.invoke(Method.java:606)
+	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:294)
+	at java.lang.Thread.run(Thread.java:745)
+Caused by: java.lang.IllegalArgumentException: An SPI class of type org.apache.lucene.codecs.Codec with name 'Lucene54' does not exist.  You need to add the corresponding JAR file supporting this SPI to your classpath.  The current classpath supports the following names: []
+	at org.apache.lucene.util.NamedSPILoader.lookup(NamedSPILoader.java:114)
+	at org.apache.lucene.codecs.Codec$Holder.<clinit>(Codec.java:60)
+	... 16 more