区块链源码研究
目前看了一哈一个简易区块链的源码,下面贴贴自己的研究结果:
-------------------------------------------------------------------------------------------
-----------------------------------Block.java---------------------------------------------
-------------------------------------------------------------------------------------------
package com.fpfpp.server.blockchain;
public class Block {
//索引值
private int index;
//上一条记录的hash值
private String previousHash;
//插入block时的时间戳
private long timestamp;
//插入的数据
private String data;
//计算得出的当前的hash值
private String hash;
public Block() {
}
public Block(int index, String previousHash, long timestamp, String data, String hash) {
this.index = index;
this.previousHash = previousHash;
this.timestamp = timestamp;
this.data = data;
this.hash = hash;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getPreviousHash() {
return previousHash;
}
public void setPreviousHash(String previousHash) {
this.previousHash = previousHash;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getHash() {
return hash;
}
public void setHash(String hash) {
this.hash = hash;
}
}
-------------------------------------------------------------------------------------------
-----------------------------------BlockService.java-------------------------------------
-------------------------------------------------------------------------------------------
package com.fpfpp.server.blockchain;
import java.util.ArrayList;
import java.util.List;
public class BlockService {
//用来保存所有数据的区块链表
private List<Block> blockChain;
public BlockService() {
this.blockChain = new ArrayList<Block>();
blockChain.add(this.getFristBlock());
}
//非常原始的。就时把previousHash加上时间戳,加上数据。然后算出hash值。
private String calculateHash(int index, String previousHash, long timestamp, String data) {
StringBuilder builder = new StringBuilder(index);
builder.append(previousHash).append(timestamp).append(data);
return CryptoUtil.getSHA256(builder.toString());
}
//获取插入的最后一个区块
public Block getLatestBlock() {
return blockChain.get(blockChain.size() - 1);
}
//获取第一个区块
private Block getFristBlock() {
return new Block(1, "0", System.currentTimeMillis(), "Hello Block", "aa212344fc10ea0a2cb885078fa9bc2354e55efc81be8f56b66e4a837157662e");
}
//产生下一个区块
public Block generateNextBlock(String blockData) {
Block previousBlock = this.getLatestBlock();
int nextIndex = previousBlock.getIndex() + 1;
long nextTimestamp = System.currentTimeMillis();
String nextHash = calculateHash(nextIndex, previousBlock.getHash(), nextTimestamp, blockData);
return new Block(nextIndex, previousBlock.getHash(), nextTimestamp, blockData, nextHash);
}
public void addBlock(Block newBlock) {
if (isValidNewBlock(newBlock, getLatestBlock())) {
blockChain.add(newBlock);
}
}
//比较新区块是否有效区块。
private boolean isValidNewBlock(Block newBlock, Block previousBlock) {
if (previousBlock.getIndex() + 1 != newBlock.getIndex()) {
System.out.println("invalid index");
return false;
} else if (!previousBlock.getHash().equals(newBlock.getPreviousHash())) {
System.out.println("invalid previoushash");
return false;
} else {
String hash = calculateHash(newBlock.getIndex(), newBlock.getPreviousHash(), newBlock.getTimestamp(),
newBlock.getData());
if (!hash.equals(newBlock.getHash())) {
System.out.println("invalid hash: " + hash + " " + newBlock.getHash());
return false;
}
}
return true;
}
public void replaceChain(List<Block> newBlocks) {
if (isValidBlocks(newBlocks) && newBlocks.size() > blockChain.size()) {
blockChain = newBlocks;
} else {
System.out.println("Received blockchain invalid");
}
}
private boolean isValidBlocks(List<Block> newBlocks) {
//校验第一个区块是否一致.
Block fristBlock = newBlocks.get(0);
if (fristBlock.equals(getFristBlock())) {
return false;
}
//再依次校验所有的区块是否一致。
for (int i = 1; i < newBlocks.size(); i++) {
if (isValidNewBlock(newBlocks.get(i), fristBlock)) {
fristBlock = newBlocks.get(i);
} else {
return false;
}
}
return true;
}
public List<Block> getBlockChain() {
return blockChain;
}
}
-------------------------------------------------------------------------------------------
-----------------------------------CryptoUtil.java----------------------------------------
-------------------------------------------------------------------------------------------
package com.fpfpp.server.blockchain;
import java.security.MessageDigest;
public class CryptoUtil {
private CryptoUtil() {
}
//加密字符串成hash值。
public static String getSHA256(String str) {
MessageDigest messageDigest;
String encodeStr = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(str.getBytes("UTF-8"));
encodeStr = byte2Hex(messageDigest.digest());
} catch (Exception e) {
System.out.println("getSHA256 is error" + e.getMessage());
}
return encodeStr;
}
private static String byte2Hex(byte[] bytes) {
StringBuilder builder = new StringBuilder();
String temp;
for (int i = 0; i < bytes.length; i++) {
temp = Integer.toHexString(bytes[i] & 0xFF);
if (temp.length() == 1) {
builder.append("0");
}
builder.append(temp);
}
return builder.toString();
}
}
-------------------------------------------------------------------------------------------
-----------------------------------HTTPService.java-------------------------------------
-------------------------------------------------------------------------------------------
package com.fpfpp.server.blockchain;
import com.alibaba.fastjson.JSON;
import org.java_websocket.WebSocket;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.InetSocketAddress;
public class HTTPService {
private BlockService blockService;
private P2PService p2pService;
public HTTPService(BlockService blockService, P2PService p2pService) {
this.blockService = blockService;
this.p2pService = p2pService;
}
public void initHTTPServer(int port) {
try {
// Server server = new Server(port);
// System.out.println("listening http port on: " + port);
// ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
// context.setContextPath("/");
// server.setHandler(context);
// context.addServlet(new ServletHolder(new BlocksServlet()), "/blocks");
// context.addServlet(new ServletHolder(new MineBlockServlet()), "/mineBlock");
// context.addServlet(new ServletHolder(new PeersServlet()), "/peers");
// context.addServlet(new ServletHolder(new AddPeerServlet()), "/addPeer");
// server.start();
// server.join();
} catch (Exception e) {
System.out.println("init http server is error:" + e.getMessage());
}
}
private class BlocksServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
resp.getWriter().println(JSON.toJSONString(blockService.getBlockChain()));
}
}
private class AddPeerServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
String peer = req.getParameter("peer");
p2pService.connectToPeer(peer);
resp.getWriter().print("ok");
}
}
private class PeersServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
for (WebSocket socket : p2pService.getSockets()) {
InetSocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();
resp.getWriter().print(remoteSocketAddress.getHostName() + ":" + remoteSocketAddress.getPort());
}
}
}
private class MineBlockServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
String data = req.getParameter("data");
Block newBlock = blockService.generateNextBlock(data);
blockService.addBlock(newBlock);
p2pService.broatcast(p2pService.responseLatestMsg());
String s = JSON.toJSONString(newBlock);
System.out.println("block added: " + s);
resp.getWriter().print(s);
}
}
}
-------------------------------------------------------------------------------------------
-----------------------------------Message.java-----------------------------------------
-------------------------------------------------------------------------------------------
package com.fpfpp.server.blockchain;
import java.io.Serializable;
public class Message implements Serializable{
private int type;
private String data;
public Message() {
}
public Message(int type) {
this.type = type;
}
public Message(int type, String data) {
this.type = type;
this.data = data;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
-------------------------------------------------------------------------------------------
-----------------------------------P2PService.java----------------------------------------
-------------------------------------------------------------------------------------------
package com.fpfpp.server.blockchain;
import com.alibaba.fastjson.JSON;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.handshake.ServerHandshake;
import org.java_websocket.server.WebSocketServer;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class P2PService {
private List<WebSocket> sockets;
private BlockService blockService;
private final static int QUERY_LATEST = 0;
private final static int QUERY_ALL = 1;
private final static int RESPONSE_BLOCKCHAIN = 2;
public P2PService(BlockService blockService) {
this.blockService = blockService;
this.sockets = new ArrayList<WebSocket>();
}
//初始化一个P2P的server,用传入的port做端口进行服务
public void initP2PServer(int port) {
final WebSocketServer socket = new WebSocketServer(new InetSocketAddress(port)) {
//打开端口时触发
public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) {
write(webSocket, queryChainLengthMsg());
sockets.add(webSocket);
}
//关闭端口时触发
public void onClose(WebSocket webSocket, int i, String s, boolean b) {
System.out.println("connection failed to peer:" + webSocket.getRemoteSocketAddress());
sockets.remove(webSocket);
}
//接受消息时触发
public void onMessage(WebSocket webSocket, String s) {
handleMessage(webSocket, s);
}
//消息出错时触发
public void onError(WebSocket webSocket, Exception e) {
System.out.println("connection failed to peer:" + webSocket.getRemoteSocketAddress());
sockets.remove(webSocket);
}
//服务开始时触发
public void onStart() {
}
};
socket.start();
System.out.println("listening websocket p2p port on: " + port);
}
//
private void handleMessage(WebSocket webSocket, String s) {
try {
Message message = JSON.parseObject(s, Message.class);
System.out.println("Received message" + JSON.toJSONString(message));
switch (message.getType()) {
case QUERY_LATEST:
write(webSocket, responseLatestMsg());
break;
case QUERY_ALL:
write(webSocket, responseChainMsg());
break;
case RESPONSE_BLOCKCHAIN:
handleBlockChainResponse(message.getData());
break;
}
} catch (Exception e) {
System.out.println("hanle message is error:" + e.getMessage());
}
}
private void handleBlockChainResponse(String message) {
List<Block> receiveBlocks = JSON.parseArray(message, Block.class);
Collections.sort(receiveBlocks, new Comparator<Block>() {
public int compare(Block o1, Block o2) {
return o1.getIndex() - o1.getIndex();
}
});
Block latestBlockReceived = receiveBlocks.get(receiveBlocks.size() - 1);
Block latestBlock = blockService.getLatestBlock();
if (latestBlockReceived.getIndex() > latestBlock.getIndex()) {
if (latestBlock.getHash().equals(latestBlockReceived.getPreviousHash())) {
System.out.println("We can append the received block to our chain");
blockService.addBlock(latestBlockReceived);
broatcast(responseLatestMsg());
} else if (receiveBlocks.size() == 1) {
System.out.println("We have to query the chain from our peer");
broatcast(queryAllMsg());
} else {
blockService.replaceChain(receiveBlocks);
}
} else {
System.out.println("received blockchain is not longer than received blockchain. Do nothing");
}
}
public void connectToPeer(String peer) {
try {
final WebSocketClient socket = new WebSocketClient(new URI(peer)) {
@Override
public void onOpen(ServerHandshake serverHandshake) {
write(this, queryChainLengthMsg());
sockets.add(this);
}
@Override
public void onMessage(String s) {
handleMessage(this, s);
}
@Override
public void onClose(int i, String s, boolean b) {
System.out.println("connection failed");
sockets.remove(this);
}
@Override
public void onError(Exception e) {
System.out.println("connection failed");
sockets.remove(this);
}
};
socket.connect();
} catch (URISyntaxException e) {
System.out.println("p2p connect is error:" + e.getMessage());
}
}
private void write(WebSocket ws, String message) {
ws.send(message);
}
public void broatcast(String message) {
for (WebSocket socket : sockets) {
this.write(socket, message);
}
}
private String queryAllMsg() {
return JSON.toJSONString(new Message(QUERY_ALL));
}
private String queryChainLengthMsg() {
return JSON.toJSONString(new Message(QUERY_LATEST));
}
private String responseChainMsg() {
return JSON.toJSONString(new Message(RESPONSE_BLOCKCHAIN, JSON.toJSONString(blockService.getBlockChain())));
}
public String responseLatestMsg() {
Block[] blocks = {blockService.getLatestBlock()};
return JSON.toJSONString(new Message(RESPONSE_BLOCKCHAIN, JSON.toJSONString(blocks)));
}
public List<WebSocket> getSockets() {
return sockets;
}
}
---------------------------------------------------------------------------------------
简单来说,区块链,就是一种对一个block的加密
不过是因为消耗了计算能力来获取特定的加密字符串,也就是要求sha码前16位全是0,
当矿工挖到矿以后,调用addPeers接口,发布自己挖到的矿,然后再通过peers2peers的方式广播出去。
技术本身没啥奇怪的。
结果又被疯狂炒作。
这个疯狂的结果是啥?想割中国的羊毛想疯了?这种算术的加密字符串应该不算是啥有效货币哈。