由于在笔记二中提到区块链数据有2大部分组成
1:交易数据
2:区块信息(hash值 工作量等)
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.JSONObject;
public class BlockChain {
// 存储区块链
private List<Map<String, Object>> chain;
// 该实例变量用于当前的交易信息列表
private List<Map<String, Object>> currentTransactions;
private static BlockChain blockChain = null;
private BlockChain() {
// 初始化区块链以及当前的交易信息列表
chain = new ArrayList<Map<String, Object>>();
currentTransactions = new ArrayList<Map<String, Object>>();
// 创建创世区块
newBlock(100, "0");
}
//因为新的区块都是依赖上一个区块hash值产生,所以创世区块稍微特殊,在初始化的时候生成,用于理解比特币的创世区块
// 创建单例对象,保持区块一致性
public static BlockChain getInstance() {
if (blockChain == null) {
synchronized (BlockChain.class) {
if (blockChain == null) {
blockChain = new BlockChain();
}
}
}
return blockChain;
}
public List<Map<String, Object>> getChain() {
return chain;
}
public void setChain(List<Map<String, Object>> chain) {
this.chain = chain;
}
public List<Map<String, Object>> getCurrentTransactions() {
return currentTransactions;
}
public void setCurrentTransactions(List<Map<String, Object>> currentTransactions) {
this.currentTransactions = currentTransactions;
}
/**
* @return 得到区块链中的最后一个区块
* 用于存放最近的交易记录,也是为下次生成新的区块做准备
*/
public Map<String, Object> lastBlock() {
return getChain().get(getChain().size() - 1);
}
/**
* 在区块链上新建一个区块
*
* @param proof
* @param previous_hash
* 上一个区块的hash值
* @return 返回新建的区块
*/
public Map<String, Object> newBlock(long proof, String previous_hash) {
Map<String, Object> block = new HashMap<String, Object>();
block.put("index", getChain().size() + 1);
block.put("timestamp", System.currentTimeMillis());
block.put("transactions", getCurrentTransactions());
block.put("proof", proof);
// 如果没有传递上一个区块的hash就计算出区块链中最后一个区块的hash
block.put("previous_hash", previous_hash != null ? previous_hash : hash(getChain().get(getChain().size() - 1)));
// 重置当前的交易信息列表
setCurrentTransactions(new ArrayList<Map<String, Object>>());
getChain().add(block);
return block;
}
/**
* 生成新交易信息,信息将加入到下一个待挖的区块中
*
* @param sender
* 发送方的地址
* @param recipient
* 接收方的地址
* @param amount
* 交易数量
* @return 返回该交易事务的块的索引
*/
public int newTransactions(String sender, String recipient, long amount) {
Map<String, Object> transaction = new HashMap<String, Object>();
transaction.put("sender", sender);
transaction.put("recipient", recipient);
transaction.put("amount", amount);
getCurrentTransactions().add(transaction);
return (Integer) lastBlock().get("index") + 1;
}
/**
* 生成区块的 SHA-256格式的 hash值
*
* @param block
* 区块
* @return 返回该区块的hash
*/
public static Object hash(Map<String, Object> block) {
return new Encrypt().getSHA256(new JSONObject(block).toString());
}
/**
* 简单的工作量证明:
* - 查找一个 p' 使得 hash(pp') 以4个0开头
* - p 是上一个块的证明, p' 是当前的证明
*
* @param last_proof
* 上一个块的证明
* @return
*/
public long proofOfWork(long last_proof) {
long proof = 0;
while (!validProof(last_proof, proof)) {
proof += 1;
}
return proof;
}
/**
* 验证证明: 是否hash(last_proof, proof)以4个0开头?
*
* @param last_proof
* 上一个块的证明
* @param proof
* 当前的证明
* @return 以4个0开头返回true,否则返回false
*目前比特币是18个0开头的hash值,计算难度相当大
*/
public boolean validProof(long last_proof, long proof) {
String guess = last_proof + "" + proof;
String guess_hash = new Encrypt().getSHA256(guess);
return guess_hash.startsWith("0000");
}
}