不知不覺陷虎,又到了周末,已經很久沒有寫東西了杠袱,最近看了很多關于區(qū)塊鏈的東西尚猿,但是簡易的入門的很少,于是楣富,我想著寫一篇能讓小白快速理解最基礎的代碼凿掂。
區(qū)塊鏈概述
網上有很多關于這方面的文章和歷史,這里有幾個問題簡單描述一下:
比特幣是一個分布式記賬系統(tǒng)纹蝴,既然是記賬庄萎,那么數(shù)據(jù)記在哪兒呢?答案是塘安,記在千千萬萬個網絡的節(jié)點上糠涛。
分布式記賬,要明白幾個問題:
一致性的問題兼犯?
多種原因可能造成不一致忍捡,比如
- 每臺機器的算力是不一樣的,計算有快有慢
- 當我和你都收到一筆交易A的時候切黔,我要記這一筆賬砸脊,你也要記,一切順利的情況下纬霞,我們都記成功了凌埂,賬本也都是一致的結果,那么如果由于網絡問題诗芜,你沒收到這一筆交易侨舆,怎么辦?
區(qū)塊鏈系統(tǒng)是這樣處理的绢陌,全網所有的機器都會有一個確認過程挨下,這個確認的過程就是校驗交易合法的過程,你遺失了這一筆交易A脐湾,最后你算出來的區(qū)塊和別人不一樣臭笆,你就白白付出了努力,結果不被認可!
共同造假的問題愁铺?
比特幣可不可能有造假的問題鹰霍?當然有,當全網參與記賬的節(jié)點有51%參與造假茵乱,記賬就是不對的茂洒,當前比特幣就有這樣的算力中心化的問題。
賬記在哪兒瓶竭?過程怎樣督勺?
用戶提交一筆交易到網絡,網絡各個礦工節(jié)點(參與記賬的)收到了這一筆交易斤贰,不會立即記賬智哀,而是把這筆交易標記到下一個區(qū)塊,當準備好出新的區(qū)塊的時候荧恍,礦工需要先算一道題算出一個值瓷叫,這個值是表示你經過千辛萬苦參與了這一次記賬,然后把區(qū)塊信息(包含交易信息送巡,上一個區(qū)塊的hash摹菠,proof算出的答案),提交到網絡骗爆,所有節(jié)點的礦工發(fā)現(xiàn)來了一個新的區(qū)塊次氨,立即停下算題的腳步,看一下這個區(qū)塊是不是工作在最長鏈淮腾,如果是糟需,校驗一下屉佳,如果成功谷朝,則確認。
proof瞎寫會怎樣武花?
接著上面的問題說圆凰,如果我沒有算這個題,直接瞎寫一個答案体箕,提交出去专钉,別的礦工看了,校驗了一把累铅,發(fā)現(xiàn)你是扯淡的跃须,你算出來的這個區(qū)塊就丟掉,永遠不會被確認娃兽。
代碼實現(xiàn):
扯淡了那么久菇民,還是開始寫一段代碼,更直觀。
Block定義
package com.xingchuan.study.blockchain.domain;
import java.util.Set;
/**
* @author xingchuan.qxc
* @since 2018/1/20
*/
public class Block {
/**
* 區(qū)塊的序號
*/
private Long index;
/**
* 區(qū)塊產生的時間
*/
private Long timestamp;
/**
* 區(qū)塊對應哪些交易
*/
private Set<Transaction> transactions;
/**
* 工作證明
*/
private Long proof;
/**
* 上一個區(qū)塊的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 {
/**
* 發(fā)送人
*/
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<>();
/**
* 初始化的時候第练,創(chuàng)建genesis block
* @throws NoSuchAlgorithmException
*/
public Blockchain() throws NoSuchAlgorithmException {
//genesis block阔馋,真實場景下,應該是同步區(qū)塊鏈的最長鏈最后一個區(qū)塊
newBlock(720L);
}
/**
* 挖礦產生新的區(qū)塊
* @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");
}
/**
* 新建一個區(qū)塊
* @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);
}
}
}