Skip to content

Commit 9726d60

Browse files
committed
Blockchain implementation in Java 90% complete
1 parent fcc1491 commit 9726d60

File tree

6 files changed

+362
-21
lines changed

6 files changed

+362
-21
lines changed

src/main/java/com/rampatra/blockchain/Block.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package com.rampatra.blockchain;
22

3+
import java.io.Serializable;
4+
35
/**
46
* @author rampatra
57
* @since 2019-03-05
68
*/
7-
public class Block {
9+
public class Block implements Serializable {
810

911
private int index;
1012
private String previousHash;

src/main/java/com/rampatra/blockchain/Blockchain.java

+40-20
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,70 @@
33
import java.nio.charset.StandardCharsets;
44
import java.security.MessageDigest;
55
import java.security.NoSuchAlgorithmException;
6-
import java.util.ArrayList;
76
import java.util.Date;
87
import java.util.List;
8+
import java.util.ListIterator;
99

1010
/**
1111
* @author rampatra
1212
* @since 2019-03-05
1313
*/
14-
public class Blockchain { // TODO: P2P
14+
public class Blockchain {
1515

16-
private List<Block> blockchain;
16+
private List<Block> blocks;
1717
private int difficulty;
1818

19-
public Blockchain(List<Block> blockchain, int difficulty) {
20-
this.blockchain = blockchain;
19+
public Blockchain(List<Block> blocks, int difficulty) {
20+
this.blocks = blocks;
2121
this.difficulty = difficulty;
22-
this.blockchain.add(getGenesisBlock("Blockchain in Java"));
22+
this.blocks.add(getGenesisBlock());
2323
}
2424

25-
public List<Block> getBlockchain() {
26-
return blockchain;
25+
public List<Block> getBlocks() {
26+
return blocks;
2727
}
2828

29-
public void mine(String data) {
30-
Block previousBlock = blockchain.get(blockchain.size() - 1);
29+
public int getSize() {
30+
return blocks.size();
31+
}
32+
33+
public Block getLatestBlock() {
34+
if (blocks.isEmpty()) return null;
35+
36+
return blocks.get(blocks.size() - 1);
37+
}
38+
39+
public void addBlock(Block block) {
40+
blocks.add(block);
41+
}
42+
43+
public Block mine(String data) {
44+
Block previousBlock = getLatestBlock();
3145
Block nextBlock = getNextBlock(previousBlock, data);
32-
46+
3347
if (isValidNextBlock(previousBlock, nextBlock)) {
34-
blockchain.add(nextBlock);
48+
blocks.add(nextBlock);
49+
return nextBlock;
3550
} else {
3651
throw new RuntimeException("Invalid block");
3752
}
3853
}
3954

40-
private Block getGenesisBlock(String data) {
55+
public boolean isValidChain() {
56+
ListIterator<Block> listIterator = blocks.listIterator();
57+
listIterator.next();
58+
while (listIterator.hasPrevious() && listIterator.hasNext()) {
59+
if (!isValidNextBlock(listIterator.previous(), listIterator.next())) {
60+
return false;
61+
}
62+
}
63+
return true;
64+
}
65+
66+
private Block getGenesisBlock() {
4167
final long timestamp = new Date().getTime();
4268
int nonce = 0;
69+
String data = "Blockchain in Java";
4370
String hash;
4471
while (!isValidHashDifficulty(hash = calculateHashForBlock(0, "0", timestamp, data, nonce))) {
4572
nonce++;
@@ -108,11 +135,4 @@ private static String bytesToHex(byte[] hash) {
108135
}
109136
return hexString.toString();
110137
}
111-
112-
public static void main(String[] args) {
113-
Blockchain blockchain = new Blockchain(new ArrayList<>(), 3);
114-
blockchain.mine("12");
115-
blockchain.mine("26");
116-
System.out.println("Blockchain: " + blockchain.getBlockchain());
117-
}
118138
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.rampatra.blockchain;
2+
3+
import java.io.Serializable;
4+
5+
/**
6+
* @author rampatra
7+
* @since 2019-03-10
8+
*/
9+
public class Message implements Serializable {
10+
11+
enum MessageType {
12+
REQUEST_LATEST_BLOCK,
13+
RECEIVE_LATEST_BLOCK,
14+
REQUEST_BLOCKCHAIN,
15+
RECEIVE_BLOCKCHAIN
16+
}
17+
18+
private MessageType messageType;
19+
private Block latestBlock;
20+
private Blockchain blockchain;
21+
22+
23+
public MessageType getMessageType() {
24+
return messageType;
25+
}
26+
27+
public Block getLatestBlock() {
28+
return latestBlock;
29+
}
30+
31+
public Blockchain getBlockchain() {
32+
return blockchain;
33+
}
34+
35+
public static final class MessageBuilder {
36+
private MessageType messageType;
37+
private Block latestBlock;
38+
private Blockchain blockchain;
39+
40+
private MessageBuilder() {
41+
}
42+
43+
public static MessageBuilder aMessage() {
44+
return new MessageBuilder();
45+
}
46+
47+
public MessageBuilder withMessageType(MessageType messageType) {
48+
this.messageType = messageType;
49+
return this;
50+
}
51+
52+
public MessageBuilder withLatestBlock(Block latestBlock) {
53+
this.latestBlock = latestBlock;
54+
return this;
55+
}
56+
57+
public MessageBuilder withBlockchain(Blockchain blockchain) {
58+
this.blockchain = blockchain;
59+
return this;
60+
}
61+
62+
public Message build() {
63+
Message message = new Message();
64+
message.latestBlock = this.latestBlock;
65+
message.blockchain = this.blockchain;
66+
message.messageType = this.messageType;
67+
return message;
68+
}
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package com.rampatra.blockchain;
2+
3+
import java.io.IOException;
4+
import java.io.ObjectInputStream;
5+
import java.io.ObjectOutputStream;
6+
import java.net.Socket;
7+
8+
/**
9+
* @author rampatra
10+
* @since 2019-03-10
11+
*/
12+
public class MessageHandler implements Runnable {
13+
14+
ObjectInputStream in;
15+
ObjectOutputStream out;
16+
Peer peer;
17+
18+
MessageHandler(Socket client, Peer peer) {
19+
try {
20+
in = new ObjectInputStream(client.getInputStream());
21+
out = new ObjectOutputStream(client.getOutputStream());
22+
this.peer = peer;
23+
} catch (IOException e) {
24+
throw new RuntimeException(e);
25+
}
26+
}
27+
28+
@Override
29+
public void run() {
30+
Message message;
31+
try {
32+
while ((message = (Message) in.readObject()) != null) {
33+
handleMessage(message);
34+
}
35+
in.close();
36+
out.close();
37+
} catch (Exception e) {
38+
throw new RuntimeException(e);
39+
}
40+
}
41+
42+
private void handleMessage(Message message) {
43+
Message.MessageType type = message.getMessageType();
44+
switch (type) {
45+
case REQUEST_LATEST_BLOCK:
46+
sendMessage(Message.MessageBuilder
47+
.aMessage()
48+
.withMessageType(Message.MessageType.RECEIVE_LATEST_BLOCK)
49+
.withLatestBlock(peer.getBlockchain().getLatestBlock())
50+
.build());
51+
break;
52+
case RECEIVE_LATEST_BLOCK:
53+
handleLatestBlock(message.getLatestBlock());
54+
break;
55+
case REQUEST_BLOCKCHAIN:
56+
sendMessage(Message.MessageBuilder
57+
.aMessage()
58+
.withMessageType(Message.MessageType.RECEIVE_BLOCKCHAIN)
59+
.withBlockchain(peer.getBlockchain())
60+
.build());
61+
break;
62+
case RECEIVE_BLOCKCHAIN:
63+
handleBlockchain(message.getBlockchain());
64+
break;
65+
default:
66+
throw new RuntimeException("Unknown message type");
67+
}
68+
}
69+
70+
private void sendMessage(Message message) {
71+
try {
72+
out.writeObject(message);
73+
} catch (IOException e) {
74+
throw new RuntimeException(e);
75+
}
76+
}
77+
78+
private void handleLatestBlock(Block latestBlock) {
79+
Block latestBlockWithCurrentPeer = peer.getBlockchain().getLatestBlock();
80+
81+
if (latestBlock.getPreviousHash().equals(latestBlockWithCurrentPeer.getHash())) {
82+
peer.getBlockchain().addBlock(latestBlock);
83+
} else if (latestBlock.getIndex() > latestBlockWithCurrentPeer.getIndex()) {
84+
sendMessage(Message.MessageBuilder
85+
.aMessage()
86+
.withMessageType(Message.MessageType.REQUEST_BLOCKCHAIN)
87+
.build());
88+
}
89+
}
90+
91+
private void handleBlockchain(Blockchain blockchain) {
92+
if (blockchain.isValidChain() && blockchain.getSize() > peer.getBlockchain().getSize()) {
93+
peer.setBlockchain(blockchain);
94+
}
95+
}
96+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.rampatra.blockchain;
2+
3+
import java.util.ArrayList;
4+
import java.util.Iterator;
5+
import java.util.List;
6+
7+
/**
8+
* @author rampatra
9+
* @since 2019-03-09
10+
*/
11+
public class P2P {
12+
13+
private static List<Peer> peers = new ArrayList<>();
14+
private static int lastUsedPort = 4000;
15+
16+
public static Peer addPeer(Blockchain blockchain) {
17+
Peer peer = new Peer(blockchain, lastUsedPort++);
18+
peers.add(peer);
19+
return peer;
20+
}
21+
22+
public static void removePeer(Peer peer) {
23+
Iterator<Peer> iterator = peers.iterator();
24+
while (iterator.hasNext()) {
25+
if (iterator.next().equals(peer)) {
26+
peer.stopServer();
27+
iterator.remove();
28+
break;
29+
}
30+
}
31+
}
32+
33+
public static List<Peer> getPeers() {
34+
return peers;
35+
}
36+
}

0 commit comments

Comments
 (0)