安卓编写区块链的尝试(失败)
在开始之前,我看了手把手教你实现简易比特币(Java版),看了之后感觉挺容易的样子,我就根据他的代码进行修改尝试。
创建Block.java
Block类中有区块hash,父区块hash,区块交易,时间戳,区块高度,工作量证明的随机数nonce这几个属性,添加org.projectlombok依赖,使用注解的方式可以实现属性的set/get方法,该类有创建区块,创建创世区块(区块链中的第一个区块),和计算区块交易的hash。
package com.example.blockchain;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 区块
* @author hanru
*
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Block {
/**
* 区块hash值
*/
private String hash;
/**
* 前一个区块的hash值
*/
private String prevBlockHash;
/**
* 区块交易
*/
private List<Transaction> transactions;
/**
* 时间戳,单位秒
*/
private long timeStamp;
/**
* 区块的高度
*/
private long height;
/**
* 工作量证明计数器
*/
private long nonce;
/**
* 创建新的区块
*
* @param previousHash
* @param transactions
* @return
*/
public static Block newBlock(String previousHash, List<Transaction> transactions, long height) {
Block block = new Block("", previousHash, transactions, Instant.now().getEpochSecond(),height,0);
ProofOfWork pow = ProofOfWork.newProofOfWork(block);
PowResult powResult = pow.run();
block.setHash(powResult.getHash());
block.setNonce(powResult.getNonce());
// block.setHash();
return block;
}
private static final String ZERO_HASH = Hex.encodeHexString(new byte[32]);
/**
* 创建创世区块
* @param coinbase
* @return
*/
public static Block newGenesisBlock(Transaction coinbase) {
List<Transaction> transactions = new ArrayList<>();
transactions.add(coinbase);
return Block.newBlock(ByteUtils.ZERO_HASH, transactions,0);
}
/**
* 对区块中的交易信息进行Hash计算
*
* @return
*/
public byte[] hashTransaction() {
byte[][] txIdArrays = new byte[this.getTransactions().size()][];
for (int i = 0; i < this.getTransactions().size(); i++) {
txIdArrays[i] = this.getTransactions().get(i).getTxId();
}
return DigestUtils.sha256(ByteUtils.merge(txIdArrays));
}
}
创建ByteUtils.java
该类的作用是将数据转换承byte[]字节数据
package com.example.blockchain;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.ArrayUtils;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.stream.Stream;
/**
* 字节数组工具类
*
*/
public class ByteUtils {
public static final String ZERO_HASH = Hex.encodeHexString(new byte[32]);
/**
* 将多个字节数组合并成一个字节数组
* @param bytes
* @return
*/
public static byte[] merge(byte[]... bytes) {
Stream<Byte> stream = Stream.of();
for (byte[] b : bytes) {
stream = Stream.concat(stream, Arrays.stream(ArrayUtils.toObject(b)));
}
return ArrayUtils.toPrimitive(stream.toArray(Byte[]::new));
}
/**
* long 转化为 byte[]
* @param val
* @return
*/
public static byte[] toBytes(long val) {
return ByteBuffer.allocate(Long.BYTES).putLong(val).array();
}
}
创建Blockchain.java
其中的方法有创建区块链,添加区块Block,区块链遍历,打包交易信息创建区块添加到区块链等
package com.example.blockchain;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 区块链
*
*/
@Data
@AllArgsConstructor
public class Blockchain {
/**
* 最后一个区块的hash
*/
private String lastBlockHash;
/**
* 创建区块链,createBlockchain
* @param address
* @return
*/
public static Blockchain createBlockchain(String address) {
String lastBlockHash = "";
if (StringUtils.isBlank(lastBlockHash)){
//对应的bucket不存在,说明是第一次获取区块链实例
// 创建 coinBase 交易
Transaction coinbaseTX = Transaction.newCoinbaseTX(address, "");
Block genesisBlock = Block.newGenesisBlock(coinbaseTX);
lastBlockHash = genesisBlock.getHash();
RocksDBUtils.getInstance().putBlock(genesisBlock);
RocksDBUtils.getInstance().putLastBlockHash(lastBlockHash);
}
return new Blockchain(lastBlockHash);
}
/**
* 根据block,添加区块
* @param block
*/
public void addBlock(Block block) {
RocksDBUtils.getInstance().putLastBlockHash(block.getHash());
RocksDBUtils.getInstance().putBlock(block);
this.lastBlockHash = block.getHash();
}
/**
* 根据data添加区块
* @param data
*/
// public void addBlock(String data) throws Exception{
//
// String lastBlockHash = RocksDBUtils.getInstance().getLastBlockHash();
// if (StringUtils.isBlank(lastBlockHash)){
// throw new Exception("还没有数据库,无法直接添加区块。。");
// }
// this.addBlock(Block.newBlock(lastBlockHash,data));
// }
/**
* 区块链迭代器:内部类
*/
public class BlockchainIterator{
/**
* 当前区块的hash
*/
private String currentBlockHash;
/**
* 构造函数
* @param currentBlockHash
*/
public BlockchainIterator(String currentBlockHash) {
this.currentBlockHash = currentBlockHash;
}
/**
* 判断是否有下一个区块
* @return
*/
public boolean hashNext() {
if (ByteUtils.ZERO_HASH.equals(currentBlockHash)) {
return false;
}
Block lastBlock = RocksDBUtils.getInstance().