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();
} }
JAVA版本区块链钱包核心代码的更多相关文章
- java 调用区块链 发布和调用智能合约
java连接区块链 很简单 ,调用智能合约要麻烦一些. 先说连接 区块链查询数据. 1 maven 项目导入 web3j 的依赖. <dependency> <groupId> ...
- iFace安全专家揭秘:存放在区块链钱包中的比特币,其实已经早就不属于你……
自MoreToken钱包跑路之后,2019年3月以来陆续多个钱包.交易所跑路,造成了大量用户账户被盗,仅MoreToken钱包用户损失总价值就达12.2亿人民币,用户损失惨重.为什么这么多钱包.交易所 ...
- 安装比特币区块链钱包API(Blockchain Wallet用户发送和接收比特币的简单API)
区块链钱包API提供了一个简单的界面,商家可以用它以编程方式与钱包进行交互. 安装:要使用此API,您需要运行负责管理区块链钱包的小型本地服务. 您的应用程序通过HTTP API调用在本地与此服务进行 ...
- java开发区块链只需150行代码
本文目的是通过java实战开发教程理解区块链是什么.将通过实战入门学习,用Java自学开发一个很基本的区块链,并在此基础上能扩展如web框架应用等.这个基本的java区块链也实现简单的工作量证明系统. ...
- 区块链钱包开发 - USDT - 一、Omni本地钱包安装
背景 Tether(USDT)中文又叫泰达币,是一种加密货币,是Tether公司推出的基于稳定价值货币美元(USD)的代币Tether USD,也是目前数字货币中最稳定的币,USDT目前发行了两种代币 ...
- java实现自动化发布平台核心代码
1.搭建jenkins环境 (1)jenkins官网下载jenkins.war包 (2)将该war包放入到tomcat的webapp的目录下(前提条件需要配置tomcat的环境,详情请自行百度) (3 ...
- 区块链技术核心概念与原理讲解-Tiny熊
转载自简书ceido:https://www.jianshu.com/u/fcdf49ef65bb (1)区块链前世今生 密码朋克(Cypherpunk):是一个邮件组,里面有许多大牛. 区块链不是单 ...
- 区块链钱包开发 - USDT - 三、实战(nodejs版本)
一.安装钱包 请参考另一篇随笔: 入口 二.获取测试usdt(TestOmni)步骤: 1.导入地址到钱包,往该地址充值测试比特币, 2.然后往 moneyqMan7uh8FqdCA2BV5yZ8qV ...
- Whitecoin区块链钱包高级功能使用命令
格式:NO-命令-命令概要-主要对象-参数 <必须参数> [可选参数]-含义-描述-需要未锁定钱包 1 addmultisigaddress 新增多重签名地址 地址 <nrequ ...
随机推荐
- fatal error C1003: error count exceeds number; stopping compilation解决方法
[error]C1003: error count exceeds 100; stopping compilation ...winnt.h 在项目工程中添加#include<windows.h ...
- MFC补码原码反码转换工具
/*_TCHAR str[100] = { 0 }; wsprintf(str, _T("%d"),num);*/ ; CString str; m_edit1.GetWindow ...
- 用Beamer做Slides
学术用幻灯片,首选还是latex.但是问题来了,Beamer这个latex幻灯模板还需要很多自定义设置.于是找了网上一些自己觉得好的例子. http://www.latexstudio.net/ind ...
- Servlet学习(九)——request
request运行流程在Servlet学习(四)——response已介绍,不再赘述 1.通过抓包工具获取Http请求 因为request代表请求,所以我们可以通过该对象分别获得Http请求的请求行, ...
- 集合类 ArrayList实现公司职员薪水管理
package com.test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStr ...
- Mac 如何修改Mac系统的默认截图路径
step 1 :打在桌面或者其他任意位置创建一个文件夹:截图图库.我创建的路径是:/Users/yilin/Documents/截图图库(仅供参考) step 2:打开终端,输入以下命令:defaul ...
- iF.svnadmin 安装遇到的坑
iF.svnadmin 官网:http://svnadmin.insanefactory.com/ 安装配置iF.svnadmin : http://blog.linhere.com/archives ...
- vue 锚点定位
vue 锚点定位 <template> <div class="details"> <div class="wrapper w"& ...
- SpringBoot 获取客户端 ip
/** * 获取客户端ip地址 * @param request * @return */ public static String getCliectIp(HttpServletRequest re ...
- 2017年6月28日 python爬虫学习
1.写入csv文件2.lxml的用法3.自定义字典类的方法4.bytes解码得到str,str编码得到bytes5.json 1 import csv import lxml.html class S ...