diff --git a/ethereumj/.gitgnore b/ethereumj/.gitgnore
new file mode 100644
index 0000000000..9cff80e071
--- /dev/null
+++ b/ethereumj/.gitgnore
@@ -0,0 +1,6 @@
+.idea
+target
+database
+logs
+target
+*.iml
\ No newline at end of file
diff --git a/ethereumj/README.md b/ethereumj/README.md
new file mode 100644
index 0000000000..54da91b4f7
--- /dev/null
+++ b/ethereumj/README.md
@@ -0,0 +1,4 @@
+## EthereumJ
+
+### Relevant Articles:
+- [Introduction to EthereumJ](http://www.baeldung.com/intro-to-ethereumj)
\ No newline at end of file
diff --git a/ethereumj/pom.xml b/ethereumj/pom.xml
new file mode 100644
index 0000000000..c9f5924d7a
--- /dev/null
+++ b/ethereumj/pom.xml
@@ -0,0 +1,110 @@
+
+
+ 4.0.0
+ com.baeldung.ethereumj
+ ethereumj
+ war
+ 1.0.0
+ ethereumj
+
+
+ UTF-8
+ 1.8
+ 8.5.4
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.5.6.RELEASE
+
+
+
+
+ Ethereum
+ Ethereum
+ https://dl.bintray.com/ethereum/maven/
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ 1.5.6.RELEASE
+ test
+
+
+
+
+ org.ethereum
+ ethereumj-core
+ 1.5.0-RELEASE
+
+
+
+
+ javax.servlet
+ jstl
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.5.0
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ ethereumj
+
+
+
+
+ integration
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ integration-test
+
+ test
+
+
+
+ none
+
+
+ */EthControllerTestOne.java
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ethereumj/src/main/java/com/baeldung/ethereumj/ApplicationMain.java b/ethereumj/src/main/java/com/baeldung/ethereumj/ApplicationMain.java
new file mode 100644
index 0000000000..4735548bd1
--- /dev/null
+++ b/ethereumj/src/main/java/com/baeldung/ethereumj/ApplicationMain.java
@@ -0,0 +1,16 @@
+package com.baeldung.ethereumj;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.web.support.SpringBootServletInitializer;
+
+@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
+@SpringBootApplication
+public class ApplicationMain extends SpringBootServletInitializer {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ApplicationMain.class, args);
+ }
+}
\ No newline at end of file
diff --git a/ethereumj/src/main/java/com/baeldung/ethereumj/Constants.java b/ethereumj/src/main/java/com/baeldung/ethereumj/Constants.java
new file mode 100644
index 0000000000..919958be35
--- /dev/null
+++ b/ethereumj/src/main/java/com/baeldung/ethereumj/Constants.java
@@ -0,0 +1,9 @@
+package com.baeldung.ethereumj;
+
+public class Constants {
+
+ public static final String ENDPOINT_ONE = "/api/get/bestblock/";
+ public static final String ENDPOINT_TWO = "/api/get/difficulty/";
+ public static final String RESPONSE_TYPE ="application/json/";
+
+}
diff --git a/ethereumj/src/main/java/com/baeldung/ethereumj/beans/EthBean.java b/ethereumj/src/main/java/com/baeldung/ethereumj/beans/EthBean.java
new file mode 100644
index 0000000000..7680473c6e
--- /dev/null
+++ b/ethereumj/src/main/java/com/baeldung/ethereumj/beans/EthBean.java
@@ -0,0 +1,25 @@
+package com.baeldung.ethereumj.beans;
+
+import com.baeldung.ethereumj.listeners.EthListener;
+import org.ethereum.core.Block;
+import org.ethereum.facade.Ethereum;
+import org.ethereum.facade.EthereumFactory;
+
+import java.math.BigInteger;
+
+public class EthBean {
+ private Ethereum ethereum;
+
+ public void start() {
+ this.ethereum = EthereumFactory.createEthereum();
+ this.ethereum.addListener(new EthListener(ethereum));
+ }
+
+ public Block getBestBlock() {
+ return this.ethereum.getBlockchain().getBestBlock();
+ }
+
+ public BigInteger getTotalDifficulty() {
+ return this.ethereum.getBlockchain().getTotalDifficulty();
+ }
+}
\ No newline at end of file
diff --git a/ethereumj/src/main/java/com/baeldung/ethereumj/config/EthConfig.java b/ethereumj/src/main/java/com/baeldung/ethereumj/config/EthConfig.java
new file mode 100644
index 0000000000..8180cc3ce2
--- /dev/null
+++ b/ethereumj/src/main/java/com/baeldung/ethereumj/config/EthConfig.java
@@ -0,0 +1,18 @@
+package com.baeldung.ethereumj.config;
+
+import com.baeldung.ethereumj.beans.EthBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.Executors;
+
+@Configuration
+public class EthConfig {
+
+ @Bean
+ EthBean ethBeanConfig() throws Exception {
+ EthBean eBean = new EthBean();
+ Executors.newSingleThreadExecutor().submit(eBean::start);
+ return eBean;
+ }
+}
\ No newline at end of file
diff --git a/ethereumj/src/main/java/com/baeldung/ethereumj/controllers/EthController.java b/ethereumj/src/main/java/com/baeldung/ethereumj/controllers/EthController.java
new file mode 100644
index 0000000000..8240d60e30
--- /dev/null
+++ b/ethereumj/src/main/java/com/baeldung/ethereumj/controllers/EthController.java
@@ -0,0 +1,44 @@
+package com.baeldung.ethereumj.controllers;
+
+import com.baeldung.ethereumj.Constants;
+import com.baeldung.ethereumj.beans.EthBean;
+import com.baeldung.ethereumj.transfer.EthResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.ServletContext;
+
+@RestController
+public class EthController {
+
+ @Autowired
+ EthBean ethBean;
+ @Autowired
+ private ServletContext servletContext;
+ private Logger l = LoggerFactory.getLogger(EthController.class);
+
+ @RequestMapping(Constants.ENDPOINT_ONE)
+ public EthResponse getBestBlock() {
+ l.debug("Request received - fetching best block.");
+ EthResponse r = new EthResponse();
+ r.setResponse(ethBean.getBestBlock().toString());
+ return r;
+ }
+
+ @RequestMapping(Constants.ENDPOINT_TWO)
+ public EthResponse getTotalDifficulty() {
+ l.debug("Request received - calculating total difficulty.");
+ EthResponse r = new EthResponse();
+ r.setResponse(ethBean.getTotalDifficulty().toString());
+ return r;
+ }
+
+ @PostConstruct
+ public void showIt() {
+ l.debug(servletContext.getContextPath());
+ }
+}
diff --git a/ethereumj/src/main/java/com/baeldung/ethereumj/listeners/EthListener.java b/ethereumj/src/main/java/com/baeldung/ethereumj/listeners/EthListener.java
new file mode 100644
index 0000000000..c3a5143fdb
--- /dev/null
+++ b/ethereumj/src/main/java/com/baeldung/ethereumj/listeners/EthListener.java
@@ -0,0 +1,71 @@
+package com.baeldung.ethereumj.listeners;
+
+import org.ethereum.core.Block;
+import org.ethereum.core.TransactionReceipt;
+import org.ethereum.facade.Ethereum;
+import org.ethereum.listener.EthereumListenerAdapter;
+import org.ethereum.util.BIUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.List;
+
+public class EthListener extends EthereumListenerAdapter {
+
+ private Logger l = LoggerFactory.getLogger(EthListener.class);
+ private Ethereum ethereum;
+ private boolean syncDone = false;
+ private static final int thou = 1000;
+
+ private void out(String t) {
+ l.info(t);
+ }
+
+ private String calcNetHashRate(Block block) {
+ String response = "Net hash rate not available";
+ if (block.getNumber() > thou) {
+ long timeDelta = 0;
+ for (int i = 0; i < thou; ++i) {
+ Block parent = ethereum
+ .getBlockchain()
+ .getBlockByHash(block.getParentHash());
+ timeDelta += Math.abs(block.getTimestamp() - parent.getTimestamp());
+ }
+ response = String.valueOf(block
+ .getDifficultyBI()
+ .divide(BIUtil.toBI(timeDelta / thou))
+ .divide(new BigInteger("1000000000"))
+ .doubleValue()) + " GH/s";
+ }
+ return response;
+ }
+
+ public EthListener(Ethereum ethereum) {
+ this.ethereum = ethereum;
+ }
+
+ @Override
+ public void onBlock(Block block, List receipts) {
+ if (syncDone) {
+ out("Net hash rate: " + calcNetHashRate(block));
+ out("Block difficulty: " + block.getDifficultyBI().toString());
+ out("Block transactions: " + block.getTransactionsList().toString());
+ out("Best block (last block): " + ethereum
+ .getBlockchain()
+ .getBestBlock().toString());
+ out("Total difficulty: " + ethereum
+ .getBlockchain()
+ .getTotalDifficulty().toString());
+ }
+ }
+
+ @Override
+ public void onSyncDone(SyncState state) {
+ out("onSyncDone " + state);
+ if (!syncDone) {
+ out(" ** SYNC DONE ** ");
+ syncDone = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ethereumj/src/main/java/com/baeldung/ethereumj/transfer/EthResponse.java b/ethereumj/src/main/java/com/baeldung/ethereumj/transfer/EthResponse.java
new file mode 100644
index 0000000000..e8cfb3113b
--- /dev/null
+++ b/ethereumj/src/main/java/com/baeldung/ethereumj/transfer/EthResponse.java
@@ -0,0 +1,14 @@
+package com.baeldung.ethereumj.transfer;
+
+public class EthResponse {
+
+ private String response;
+
+ public String getResponse() {
+ return response;
+ }
+
+ public void setResponse(String response) {
+ this.response = response;
+ }
+}
diff --git a/ethereumj/src/main/resources/application.properties b/ethereumj/src/main/resources/application.properties
new file mode 100644
index 0000000000..033e543fe8
--- /dev/null
+++ b/ethereumj/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+server.servlet-path=/
+server.port=8080
\ No newline at end of file
diff --git a/ethereumj/src/test/java/com/baeldung/ethereumj/controllers/EthControllerTestOne.java b/ethereumj/src/test/java/com/baeldung/ethereumj/controllers/EthControllerTestOne.java
new file mode 100644
index 0000000000..9298c34ec2
--- /dev/null
+++ b/ethereumj/src/test/java/com/baeldung/ethereumj/controllers/EthControllerTestOne.java
@@ -0,0 +1,72 @@
+package com.baeldung.ethereumj.controllers;
+
+import com.baeldung.ethereumj.ApplicationMain;
+import com.baeldung.ethereumj.Constants;
+import com.baeldung.ethereumj.transfer.EthResponse;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.context.embedded.LocalServerPort;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.*;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.web.client.RestTemplate;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = ApplicationMain.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
+@TestPropertySource(properties = "server.port=8080")
+public class EthControllerTestOne {
+
+ @LocalServerPort
+ int port;
+
+ private RestTemplate restTemplate = new RestTemplate();
+
+ private String url(String uri) {
+ String s = "http://localhost:" + port + uri;
+ System.out.println(s);
+ return s;
+ }
+
+ @Before
+ public void setup() {
+ restTemplate = new RestTemplate();
+ }
+
+ @Test()
+ public void bestBlockTest() throws Exception {
+
+ Thread.sleep(20000);
+
+ EthResponse a = restTemplate.getForObject(url(Constants.ENDPOINT_ONE), EthResponse.class);
+ assertNotNull(a);
+
+ ResponseEntity b = restTemplate.exchange(
+ url(Constants.ENDPOINT_ONE),
+ HttpMethod.GET, new HttpEntity(null, new HttpHeaders()), EthResponse.class);
+
+ assertTrue("Status 200?", b.getStatusCode().equals(HttpStatus.OK));
+ System.out.println("Status 200?: " + b.getStatusCode().equals(HttpStatus.OK));
+ assertTrue("Dynamic data returned?", b.hasBody());
+ System.out.println("Dynamic data returned?: " + b.hasBody());
+ }
+
+ @Test()
+ public void difficultyTest() throws Exception {
+
+ Thread.sleep(20000);
+
+ ResponseEntity a = restTemplate.exchange(
+ url(Constants.ENDPOINT_TWO),
+ HttpMethod.GET, new HttpEntity(null, new HttpHeaders()), EthResponse.class);
+
+ assertTrue("Status 200?", a.getStatusCode().equals(HttpStatus.OK));
+ System.out.println("Status 200?: " + a.getStatusCode().equals(HttpStatus.OK));
+ assertTrue("Dynamic data returned?", a.hasBody());
+ System.out.println("Dynamic data returned?: " + a.hasBody());
+ }
+}
diff --git a/pom.xml b/pom.xml
index c501dddd3c..11737938a9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,6 +50,8 @@
deltaspike
dozer
+ ethereumj
+
feign