JAVA版本区块链钱包核心代码
Block.java
package com.ppblock.blockchain.core;
import java.io.Serializable;
/**
* 区块
* @author yangjian
* @since 18-4-6
*/
public class Block implements Serializable {
/**
* 区块 Header
*/
private BlockHeader header;
/**
* 区块 Body
*/
private BlockBody body;
public Block(BlockHeader header, BlockBody body) {
this.header = header;
this.body = body;
}
public Block() {
}
public BlockHeader getHeader() {
return header;
}
public void setHeader(BlockHeader header) {
this.header = header;
}
public BlockBody getBody() {
return body;
}
public void setBody(BlockBody body) {
this.body = body;
}
@Override
public String toString() {
return "Block{" +
"header=" + header +
", body=" + body.toString() +
'}';
}
}
BlockBody.java
package com.ppblock.blockchain.core;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 区块数据
* @author yangjian
* @since 18-4-8
*/
public class BlockBody implements Serializable {
/**
* 区块所包含的交易记录
*/
private List<Transaction> transactions;
public BlockBody(List<Transaction> transactions) {
this.transactions = transactions;
}
public BlockBody() {
this.transactions = new ArrayList<>();
}
public List<Transaction> getTransactions() {
return transactions;
}
public void setTransactions(List<Transaction> transactions) {
this.transactions = transactions;
}
/**
* 追加一笔交易
* @param transaction
*/
public void addTransaction(Transaction transaction) {
transactions.add(transaction);
}
@Override
public String toString() {
return "BlockBody{" +
"transactions=" + transactions +
'}';
}
}
BlockChain.java
package com.ppblock.blockchain.core;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.ppblock.blockchain.crypto.Credentials;
import com.ppblock.blockchain.crypto.Keys;
import com.ppblock.blockchain.crypto.Sign;
import com.ppblock.blockchain.db.DBAccess;
import com.ppblock.blockchain.enums.TransactionStatusEnum;
import com.ppblock.blockchain.event.MineBlockEvent;
import com.ppblock.blockchain.event.SendTransactionEvent;
import com.ppblock.blockchain.mine.Miner;
import com.ppblock.blockchain.net.ApplicationContextProvider;
import com.ppblock.blockchain.net.base.Node;
import com.ppblock.blockchain.net.client.AppClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* 区块链主类
* @author yangjian
* @since 18-4-6
*/
@Component
public class BlockChain {
private static Logger logger = LoggerFactory.getLogger(BlockChain.class);
@Autowired
private DBAccess dbAccess;
@Autowired
private AppClient appClient;
@Autowired
private Miner miner;
@Autowired
private TransactionPool transactionPool;
@Autowired
private TransactionExecutor executor;
/**
* 挖取一个区块
* @return
*/
public Block mining() throws Exception {
Optional<Block> lastBlock = getLastBlock();
Block block = miner.newBlock(lastBlock);
transactionPool.getTransactions().forEach(e -> block.getBody().addTransaction(e));
executor.run(block);
//清空交易池
transactionPool.clearTransactions();
//存储区块
dbAccess.putLastBlockIndex(block.getHeader().getIndex());
dbAccess.putBlock(block);
logger.info("Find a New Block, {}", block);
//触发挖矿事件,并等待其他节点确认区块
ApplicationContextProvider.publishEvent(new MineBlockEvent(block));
return block;
}
/**
* 发送交易
* @param credentials 交易发起者的凭证
* @param to 交易接收者
* @param amount
* @param data 交易附言
* @return
* @throws Exception
*/
public Transaction sendTransaction(Credentials credentials, String to, BigDecimal amount, String data) throws
Exception {
//校验付款和收款地址
Preconditions.checkArgument(to.startsWith("0x"), "收款地址格式不正确");
Preconditions.checkArgument(!credentials.getAddress().equals(to), "收款地址不能和发送地址相同");
//构建交易对象
Transaction transaction = new Transaction(credentials.getAddress(), to, amount);
transaction.setPublicKey(Keys.publicKeyEncode(credentials.getEcKeyPair().getPublicKey().getEncoded()));
transaction.setStatus(TransactionStatusEnum.APPENDING);
transaction.setData(data);
transaction.setTxHash(transaction.hash());
//签名
String sign = Sign.sign(credentials.getEcKeyPair().getPrivateKey(), transaction.toString());
transaction.setSign(sign);
//先验证私钥是否正确
if (!Sign.verify(credentials.getEcKeyPair().getPublicKey(), sign, transaction.toString())) {
throw new RuntimeException("私钥签名验证失败,非法的私钥");
}
//打包数据到交易池
transactionPool.addTransaction(transaction);
//触发交易事件,向全网广播交易,并等待确认
ApplicationContextProvider.publishEvent(new SendTransactionEvent(transaction));
return transaction;
}
/**
* 获取最后一个区块
* @return
*/
public Optional<Block> getLastBlock() {
return dbAccess.getLastBlock();
}
/**
* 添加一个节点
* @param ip
* @param port
* @return
*/
public void addNode(String ip, int port) throws Exception {
appClient.addNode(ip, port);
Node node = new Node(ip, port);
dbAccess.addNode(node);
}
}
BlockHeader.java
package com.ppblock.blockchain.core;
import com.ppblock.blockchain.crypto.Hash;
import java.io.Serializable;
import java.math.BigInteger;
/**
* 区块头
* @author yangjian
* @since 18-4-6
*/
public class BlockHeader implements Serializable {
/**
* 区块高度
*/
private Integer index;
/**
* 难度指标
*/
private BigInteger difficulty;
/**
* PoW 问题的答案
*/
private Long nonce;
/**
* 时间戳
*/
private Long timestamp;
/**
* 区块 Hash
*/
private String hash;
/**
* 上一个区块的 hash 地址
*/
private String previousHash;
public BlockHeader(Integer index, String previousHash) {
this.index = index;
this.timestamp = System.currentTimeMillis();
this.previousHash = previousHash;
}
public BlockHeader() {
this.timestamp = System.currentTimeMillis();
}
public Integer getIndex() {
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
public BigInteger getDifficulty() {
return difficulty;
}
public void setDifficulty(BigInteger difficulty) {
this.difficulty = difficulty;
}
public Long getNonce() {
return nonce;
}
public void setNonce(Long nonce) {
this.nonce = nonce;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
public String getPreviousHash() {
return previousHash;
}
public void setPreviousHash(String previousHash) {
this.previousHash = previousHash;
}
public String getHash() {
return hash;
}
public void setHash(String hash) {
this.hash = hash;
}
@Override
public String toString() {
return "BlockHeader{" +
"index=" + index +
", difficulty=" + difficulty +
", nonce=" + nonce +
", timestamp=" + timestamp +
", hash='" + hash + '\'' +
", previousHash='" + previousHash + '\'' +
'}';
}
/**
* 获取区块头的 hash 值
* @return
*/
public String hash() {
return Hash.sha3("BlockHeader{" +
"index=" + index +
", difficulty=" + difficulty +
", nonce=" + nonce +
", timestamp=" + timestamp +
", previousHash='" + previousHash + '\'' +
'}');
}
}
Transaction.java
package com.ppblock.blockchain.core;
import com.ppblock.blockchain.crypto.Hash;
import com.ppblock.blockchain.enums.TransactionStatusEnum;
import java.math.BigDecimal;
/**
* 交易对象
* @author yangjian
* @since 18-4-6
*/
public class Transaction {
/**
* 付款人地址
*/
private String from;
/**
* 付款人签名
*/
private String sign;
/**
* 收款人地址
*/
private String to;
/**
* 收款人公钥
*/
private String publicKey;
/**
* 交易金额
*/
private BigDecimal amount;
/**
* 交易时间戳
*/
private Long timestamp;
/**
* 交易 Hash 值
*/
private String txHash;
/**
* 交易状态
*/
private TransactionStatusEnum status = TransactionStatusEnum.SUCCESS;
/**
* 交易错误信息
*/
private String errorMessage;
/**
* 附加数据
*/
private String data;
public Transaction(String from, String to, BigDecimal amount) {
this.from = from;
this.to = to;
this.amount = amount;
this.timestamp = System.currentTimeMillis();
}
public Transaction() {
this.timestamp = System.currentTimeMillis();
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getPublicKey() {
return publicKey;
}
public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
public String getTxHash() {
return txHash;
}
public void setTxHash(String txHash) {
this.txHash = txHash;
}
public TransactionStatusEnum getStatus() {
return status;
}
public void setStatus(TransactionStatusEnum status) {
this.status = status;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
/**
* 计算交易信息的Hash值
* @return
*/
public String hash() {
return Hash.sha3(this.toString());
}
@Override
public String toString() {
return "Transaction{" +
"from='" + from + '\'' +
", to='" + to + '\'' +
", publicKey=" + publicKey +
", amount=" + amount +
", timestamp=" + timestamp +
", data='" + data + '\'' +
'}';
}
}
TransactionExecutor.java
package com.ppblock.blockchain.core;
import com.google.common.base.Optional;
import com.ppblock.blockchain.account.Account;
import com.ppblock.blockchain.crypto.Keys;
import com.ppblock.blockchain.crypto.Sign;
import com.ppblock.blockchain.db.DBAccess;
import com.ppblock.blockchain.enums.TransactionStatusEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* 交易执行器
* @author yangjian
* @since 18-4-23
*/
@Component
public class TransactionExecutor {
@Autowired
private DBAccess dbAccess;
@Autowired
private TransactionPool transactionPool;
/**
* 执行区块中的交易
* @param block
*/
public void run(Block block) throws Exception {
for (Transaction transaction : block.getBody().getTransactions()) {
synchronized (this) {
Optional<Account> recipient = dbAccess.getAccount(transaction.getTo());
//如果收款地址账户不存在,则创建一个新账户
if (!recipient.isPresent()) {
recipient = Optional.of(new Account(transaction.getTo(), BigDecimal.ZERO));
}
//挖矿奖励
if (null == transaction.getFrom()) {
recipient.get().setBalance(recipient.get().getBalance().add(transaction.getAmount()));
dbAccess.putAccount(recipient.get());
continue;
}
//账户转账
Optional<Account> sender = dbAccess.getAccount(transaction.getFrom());
//验证签名
boolean verify = Sign.verify(
Keys.publicKeyDecode(transaction.getPublicKey()),
transaction.getSign(),
transaction.toString());
if (!verify) {
transaction.setStatus(TransactionStatusEnum.FAIL);
transaction.setErrorMessage("交易签名错误");
continue;
}
//验证账户余额
if (sender.get().getBalance().compareTo(transaction.getAmount()) == -1) {
transaction.setStatus(TransactionStatusEnum.FAIL);
transaction.setErrorMessage("账户余额不足");
continue;
}
//执行转账操作,更新账户余额
sender.get().setBalance(sender.get().getBalance().subtract(transaction.getAmount()));
recipient.get().setBalance(recipient.get().getBalance().add(transaction.getAmount()));
dbAccess.putAccount(sender.get());
dbAccess.putAccount(recipient.get());
}//end synchronize
}// end for
//清空交易池
transactionPool.clearTransactions();
}
}
TransactionPool.java
package com.ppblock.blockchain.core;
import com.google.common.base.Objects;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* 交易池
* @author yangjian
* @since 18-4-23
*/
@Component
public class TransactionPool {
private List<Transaction> transactions = new ArrayList<>();
/**
* 添加交易
* @param transaction
*/
public void addTransaction(Transaction transaction) {
boolean exists = false;
//检验交易是否存在
for (Transaction tx : this.transactions) {
if (Objects.equal(tx.getTxHash(), transaction.getTxHash())) {
exists = true;
}
}
if (!exists) {
this.transactions.add(transaction);
}
}
public List<Transaction> getTransactions() {
return transactions;
}
/**
* 清空交易池
*/
public void clearTransactions() {
this.transactions.clear();
}
}
浙公网安备 33010602011771号