区块链JAVA描述版
2018-01-21 本文已影响0人
钱佳
不知不觉,又到了周末,已经很久没有写东西了,最近看了很多关于区块链的东西,但是简易的入门的很少,于是,我想着写一篇能让小白快速理解最基础的代码。
区块链概述
网上有很多关于这方面的文章和历史,这里有几个问题简单描述一下:
比特币是一个分布式记账系统,既然是记账,那么数据记在哪儿呢?答案是,记在千千万万个网络的节点上。
分布式记账,要明白几个问题:
一致性的问题?
多种原因可能造成不一致,比如
- 每台机器的算力是不一样的,计算有快有慢
- 当我和你都收到一笔交易A的时候,我要记这一笔账,你也要记,一切顺利的情况下,我们都记成功了,账本也都是一致的结果,那么如果由于网络问题,你没收到这一笔交易,怎么办?
区块链系统是这样处理的,全网所有的机器都会有一个确认过程,这个确认的过程就是校验交易合法的过程,你遗失了这一笔交易A,最后你算出来的区块和别人不一样,你就白白付出了努力,结果不被认可!
共同造假的问题?
比特币可不可能有造假的问题?当然有,当全网参与记账的节点有51%参与造假,记账就是不对的,当前比特币就有这样的算力中心化的问题。
账记在哪儿?过程怎样?
用户提交一笔交易到网络,网络各个矿工节点(参与记账的)收到了这一笔交易,不会立即记账,而是把这笔交易标记到下一个区块,当准备好出新的区块的时候,矿工需要先算一道题算出一个值,这个值是表示你经过千辛万苦参与了这一次记账,然后把区块信息(包含交易信息,上一个区块的hash,proof算出的答案),提交到网络,所有节点的矿工发现来了一个新的区块,立即停下算题的脚步,看一下这个区块是不是工作在最长链,如果是,校验一下,如果成功,则确认。
proof瞎写会怎样?
接着上面的问题说,如果我没有算这个题,直接瞎写一个答案,提交出去,别的矿工看了,校验了一把,发现你是扯淡的,你算出来的这个区块就丢掉,永远不会被确认。
代码实现:
扯淡了那么久,还是开始写一段代码,更直观。
Block定义
package com.xingchuan.study.blockchain.domain;
import java.util.Set;
/**
* @author xingchuan.qxc
* @since 2018/1/20
*/
public class Block {
/**
* 区块的序号
*/
private Long index;
/**
* 区块产生的时间
*/
private Long timestamp;
/**
* 区块对应哪些交易
*/
private Set<Transaction> transactions;
/**
* 工作证明
*/
private Long proof;
/**
* 上一个区块的hash
*/
private String previousHash;
public Long getIndex() {
return index;
}
public void setIndex(Long index) {
this.index = index;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
public Set<Transaction> getTransactions() {
return transactions;
}
public void setTransactions(Set<Transaction> transactions) {
this.transactions = transactions;
}
public Long getProof() {
return proof;
}
public void setProof(Long proof) {
this.proof = proof;
}
public String getPreviousHash() {
return previousHash;
}
public void setPreviousHash(String previousHash) {
this.previousHash = previousHash;
}
@Override
public String toString() {
return "{\"Block\":{"
+ " \"index\":\"" + index + "\""
+ ", \"timestamp\":\"" + timestamp + "\""
+ ", \"transactions\":" + transactions
+ ", \"proof\":\"" + proof + "\""
+ ", \"previousHash\":\"" + previousHash + "\""
+ "}}";
}
}
Transaction定义
/**
* @author xingchuan.qxc
* @since 2018/1/20
*/
public class Transaction {
/**
* 发送人
*/
private String sender;
/**
* 接收人
*/
private String recipient;
/**
* 金额
*/
private long amount;
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getRecipient() {
return recipient;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
public long getAmount() {
return amount;
}
public void setAmount(long amount) {
this.amount = amount;
}
@Override
public String toString() {
return "{\"Transaction\":{"
+ " \"sender\":\"" + sender + "\""
+ ", \"recipient\":\"" + recipient + "\""
+ ", \"amount\":\"" + amount + "\""
+ "}}";
}
}
Blockchain定义
/**
* @author xingchuan.qxc
* @since 2018/1/20
*/
public class Blockchain {
/**
* Block 链
*/
private List<Block> blockchain = new LinkedList<>();
/**
* 待生成Block的交易
*/
private Set<Transaction> transactions = new HashSet<>();
/**
* 初始化的时候,创建genesis block
* @throws NoSuchAlgorithmException
*/
public Blockchain() throws NoSuchAlgorithmException {
//genesis block,真实场景下,应该是同步区块链的最长链最后一个区块
newBlock(720L);
}
/**
* 挖矿产生新的区块
* @throws NoSuchAlgorithmException
*/
public void mine() throws NoSuchAlgorithmException {
Block lastBlock = blockchain.get(blockchain.size() - 1);
Long lastProof = lastBlock.getProof();
Long proof = proofOfWork(lastProof);
newTransaction("0", "mineNode", 1L);
newBlock(proof);
}
/**
* 计算工作证明
* @param lastProof
* @return
* @throws NoSuchAlgorithmException
*/
public Long proofOfWork(Long lastProof) throws NoSuchAlgorithmException {
Long proof = 0L;
while (!validProof(lastProof, proof)) {
proof++;
}
return proof;
}
/**
* 算题,这里定义为,直到算出来的值以0000开头,才算正确答案
* @param lastProof
* @param proof
* @return
* @throws NoSuchAlgorithmException
*/
private boolean validProof(Long lastProof, Long proof) throws NoSuchAlgorithmException {
String guess = "" + lastProof + proof;
String guessHash = hash(guess);
return guessHash.startsWith("0000");
}
/**
* 新建一个区块
* @param proof
* @return
* @throws NoSuchAlgorithmException
*/
public Block newBlock(Long proof) throws NoSuchAlgorithmException {
Set<Transaction> transactions = new HashSet<>();
transactions.addAll(this.transactions);
int index = blockchain.size() - 1;
Block lastBlock = null;
if (index >= 0) {
lastBlock = blockchain.get(index);
}
if (lastBlock == null) {
lastBlock = new Block();
}
Block block = new Block();
block.setIndex(Long.valueOf(blockchain.size() + 1));
block.setTimestamp(System.currentTimeMillis());
block.setTransactions(transactions);
block.setProof(proof);
block.setPreviousHash(hash(lastBlock.toString()));
blockchain.add(block);
this.transactions.clear();
return block;
}
/**
* 提交一笔新的交易
* @param sender
* @param recipient
* @param amount
* @return
*/
public long newTransaction(String sender, String recipient, Long amount) {
Transaction transaction = new Transaction();
transaction.setSender(sender);
transaction.setRecipient(recipient);
transaction.setAmount(amount);
this.transactions.add(transaction);
int lastBlockIndex = blockchain.size() - 1;
if (lastBlockIndex >= 0) {
Block block = blockchain.get(lastBlockIndex);
return block.getIndex() + 1;
}
return 0;
}
/**
* SHA-512 算工作量证明
* @param value
* @return
* @throws NoSuchAlgorithmException
*/
private static String hash(String value) throws NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
messageDigest.update(value.getBytes());
return bytesToHexString(messageDigest.digest());
}
private static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
public List<Block> getBlockchain() {
return blockchain;
}
public Set<Transaction> getTransactions() {
return transactions;
}
}
测试代码
/**
* @author xingchuan.qxc
* @since 2018/1/20
*/
public class TestBlockChain {
public static void main(String[] args) throws Exception {
//初始化
Blockchain blockchain = new Blockchain();
//提交一笔交易
blockchain.newTransaction("xingchuan", "shine", 7201L);
//挖矿记录这一笔交易
blockchain.mine();
List<Block> blockList = blockchain.getBlockchain();
blockList.forEach(block->{
System.out.println(block);
});
Set<Transaction> transactions = blockchain.getTransactions();
for (Transaction transaction : transactions) {
System.out.println(transaction);
}
}
}