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版本区块链钱包核心代码的更多相关文章

  1. java 调用区块链 发布和调用智能合约

    java连接区块链 很简单 ,调用智能合约要麻烦一些. 先说连接 区块链查询数据. 1 maven 项目导入 web3j 的依赖. <dependency> <groupId> ...

  2. iFace安全专家揭秘:存放在区块链钱包中的比特币,其实已经早就不属于你……

    自MoreToken钱包跑路之后,2019年3月以来陆续多个钱包.交易所跑路,造成了大量用户账户被盗,仅MoreToken钱包用户损失总价值就达12.2亿人民币,用户损失惨重.为什么这么多钱包.交易所 ...

  3. 安装比特币区块链钱包API(Blockchain Wallet用户发送和接收比特币的简单API)

    区块链钱包API提供了一个简单的界面,商家可以用它以编程方式与钱包进行交互. 安装:要使用此API,您需要运行负责管理区块链钱包的小型本地服务. 您的应用程序通过HTTP API调用在本地与此服务进行 ...

  4. java开发区块链只需150行代码

    本文目的是通过java实战开发教程理解区块链是什么.将通过实战入门学习,用Java自学开发一个很基本的区块链,并在此基础上能扩展如web框架应用等.这个基本的java区块链也实现简单的工作量证明系统. ...

  5. 区块链钱包开发 - USDT - 一、Omni本地钱包安装

    背景 Tether(USDT)中文又叫泰达币,是一种加密货币,是Tether公司推出的基于稳定价值货币美元(USD)的代币Tether USD,也是目前数字货币中最稳定的币,USDT目前发行了两种代币 ...

  6. java实现自动化发布平台核心代码

    1.搭建jenkins环境 (1)jenkins官网下载jenkins.war包 (2)将该war包放入到tomcat的webapp的目录下(前提条件需要配置tomcat的环境,详情请自行百度) (3 ...

  7. 区块链技术核心概念与原理讲解-Tiny熊

    转载自简书ceido:https://www.jianshu.com/u/fcdf49ef65bb (1)区块链前世今生 密码朋克(Cypherpunk):是一个邮件组,里面有许多大牛. 区块链不是单 ...

  8. 区块链钱包开发 - USDT - 三、实战(nodejs版本)

    一.安装钱包 请参考另一篇随笔: 入口 二.获取测试usdt(TestOmni)步骤: 1.导入地址到钱包,往该地址充值测试比特币, 2.然后往 moneyqMan7uh8FqdCA2BV5yZ8qV ...

  9. Whitecoin区块链钱包高级功能使用命令

    格式:NO-命令-命令概要-主要对象-参数 <必须参数> [可选参数]-含义-描述-需要未锁定钱包   1 addmultisigaddress 新增多重签名地址 地址 <nrequ ...

随机推荐

  1. jqGrid添加删除功能(不和数据库交互)

    jqGrid添加删除功能(不和数据库交互) 一.背景需求 项目中需要在前端页面动态的添加行,删除行,上下移动行等,同时还不和数据库交互.一直在用jqGrid展示表格的我们,从没有深入的研究过它,当然看 ...

  2. Glide错误java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity

    解决办法 在使用Glide的那段代码加是否在主线程判断 if(Util.isOnMainThread()) { Glide.with(ClassifyItemDetailActivity.this). ...

  3. 51nod-1503 猪和回文 - 二维矩阵上的dp

    题目链接 一只猪走进了一个森林.很凑巧的是,这个森林的形状是长方形的,有n行,m列组成.我们把这个长方形的行从上到下标记为1到n,列从左到右标记为1到m.处于第r行第c列的格子用(r,c)表示. 刚开 ...

  4. div控制最小高度又自适高度

    div控制最小高度又自适高度我们在用div布局的时候经常会遇到这样的一种情况:我们需要设置一个div的高度,当里面的东西超过这个高度时,让这个容器自动被撑开,也就是自适应高度.当里面的信息很少时候,我 ...

  5. 洛谷P2770 航空路线问题 最小费用流

    Code: #include<cstdio> #include<iostream> #include<algorithm> #include<vector&g ...

  6. 学习jvm,关于MAT an internal error occurred during:"Parsing heap dump" from问题

    写了一个死循环不断的创建对象,模拟内存溢出 package com.zuo.test1; import java.util.ArrayList; import java.util.List; publ ...

  7. Java基础学习总结(6)——面向对象

    一.JAVA类的定义 JAVA里面有class关键字定义一个类,后面加上自定义的类名即可.如这里定义的person类,使用class person定义了一个person类,然后在person这个类的类 ...

  8. USACO 玛丽卡(最短路+枚举)

    USACO 玛丽卡 麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复. 因为她和他们不住在同一个城市,因此她开始准备她的长途旅行. 在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市 ...

  9. java 项目 导入成功后jsp页面报错处理方法

    本人新导入一个maven项目可是jsp页面一直报错,我先按照网上的经验操作如下步骤: 在pom.xml配置文件中添加上javax.servlet的相关依赖: <dependency>  & ...

  10. RubyMine2017破解

    RubyMine2017破解 学习了:https://www.7down.com/soft/172903.html 激活的时候选择 license server; 输入如下地址激活: http://i ...