使用Java编写自己的区块链
关于区块链技术,网络上有很多入门、科普的文章,如果大家对于区块链感兴趣,应该已经通过网络了解区块链的基本概念了,这里就不再赘述基本概念了。
相信阅读本文章的朋友们应该都和我一样对于区块链技术感到新奇,都想知道区块链在代码上怎么实现的,所以本文是实战为主,理论为辅的,毕竟大家应该都看过不少的理论文章了,但是对于区块链具体实现还不是很清楚,本文就是用Java语言来实现一个简易的区块链。
准备工作
使用Java语言编写区块链程序,需要掌握基本的JavaSE以及JavaWeb开发,能够使用Java开发简单的项目,并且对于HTTP协议有一定的了解。
相信大家都听说过区块链的记录构成是不可变、有序的链结构,记录可以是交易、文件或任何你想要的数据,重要的是它们是通过哈希值(Hash)连接起来的。
如果你还不知道什么是哈希,可以查看 这篇文章 。
开发环境
- JDK 1.8
- Tomcat 9.0
- Maven 3.6
- IntelliJ IDEA 2018及以上版本
- Springboot 2.3.7.RELEASE
- alibaba fastjson 1.2.47
- Postman
pom.xml文件配置内容:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
开始开发
Transaction类
首先创建一个Transaction类,主要有三个参数分别是:sender(发送者)、recipient(接收者)、amount(金额)。
以下是Transaction类的代码:
package com.feonix.blockchain.pojo;
import java.io.Serializable;
/**
* 交易类
*/
public class Transaction implements Serializable {
/**
* 发送者
*/
private String sender;
/**
* 接收者
*/
private String recipient;
/**
* 交易金额
*/
private long amount;
public Transaction() {
}
public Transaction(String sender, String recipient, long amount) {
this.sender = sender;
this.recipient = recipient;
this.amount = amount;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getRecipient() {
return recipient;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
public long getAmount() {
return amount;
}
public void setAmount(long amount) {
this.amount = amount;
}
@Override
public String toString() {
return "Transaction{" +
"sender='" + sender + '\'' +
", recipient='" + recipient + '\'' +
", amount=" + amount +
'}';
}
}
Transaction类是用来表示交易的实体类,交易中所涉及的要素都在类中体现出来。
Block类
再创建一个Block区块类,每个区块包含属性:index(索引)、timestamp(时间戳)、transactions(交易列表)、proof(工作量证明)、previous_hash(前一个区块的哈希值)。
以下是一个区块的结构:
block = {
"index": 2,
"previous_hash": "d86a71b5af281c5b32cf50323114975ae0394ca2754b0a590390e65e5bd6cc68",
"proof": 35293,
"timestamp": 1608699216469,
"transactions": [
{
"amount": 5,
"recipient": "327598e7426e4c6593e167444a13efvc",
"sender": "672798e7426e4c6593e167444a13fcad"
}
]
}
以下是Block类的具体实现:
package com.feonix.blockchain.pojo;
import java.io.Serializable;
import java.util.List;
/**
* 区块类
*/
public class Block implements Serializable {
/**
* 索引
*/
private int index;
/**
* 时间戳
*/
private long timestamp;
/**
* 交易列表
*/
private List<Transaction> transactions;
/**
* 工作量证明
*/
private long proof;
/**
* 前一个区块的哈希值
*/
private String previous_hash;
public Block() {
}
public Block(int index, long timestamp, List<Transaction> transactions, long proof, String previous_hash) {
this.index = index;
this.timestamp = timestamp;
this.transactions = transactions;
this.proof = proof;
this.previous_hash = previous_hash;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public List<Transaction> getTransactions() {
return transactions;
}
public void setTransactions(List<Transaction> transactions) {
this.transactions = transactions;
}
public long getProof() {
return proof;
}
public void setProof(long proof) {
this.proof = proof;
}
public String getPrevious_hash() {
return previous_hash;
}
public void setPrevious_hash(String previous_hash) {
this.previous_hash = previous_hash;
}
@Override
public String toString() {
return "Block{" +
"index=" + index +
", timestamp=" + timestamp +
", transactions=" + transactions +
", proof=" + proof +
", previous_hash='" + previous_hash + '\'' +
'}';
}
}
BlockChain类
接下来创建BlockChain类,在构造器中创建了两个主要的集合,一个用于储存区块链,一个用于储存交易列表,这是本文中所用到的核心类,关于区块链的操作都封装在这个类中。
下面是BlockChain类的基础代码框架:
package com.feonix.blockchain.dao;
import com.feonix.blockchain.pojo.Block;
import com.feonix.blockchain.pojo.Transaction;
public class BlockChain {
/**
* 存储区块链
*/
private List<Block> chain;
/**
* 当前交易信息列表
*/
private List<Transaction> currentTransactions;
private BlockChain() {
// 初始化区块链
this.chain = new ArrayList<Block>();
// 初始化当前的交易信息列表
this.currentTransactions = new ArrayList<Transaction>();
}
public List<Block> getChain() {
return chain;
}
public void setChain(List<Block> chain) {
this.chain = chain;
}
public List<Transaction> getCurrentTransactions() {
return currentTransactions;
}
public void setCurrentTransactions(List<Transaction> currentTransactions) {
this.currentTransactions = currentTransactions;
}
public Block getLastBlock() {
return null;
}
public Block newBlock(long proof, String previous_hash) {
return null;
}
public static String hash(Block block) {
return null;
}
}
BlockChain类用来管理区块链,它能存储交易,加入新块等,到这里,区块链的概念就清楚了,每个新的区块都包含上一个区块的Hash,这是关键的一点,它保障了区块链不可变性。如果攻击者破坏了前面的某个区块,那么后面所有区块的Hash都会变得不正确。不理解的话,慢慢消化,可以参考 区块链记账原理。
接下来让我们进一步完善这个区块链程序,由于需要计算区块的hash,我们需要先编写一个计算hash值的工具类:
package com.feonix.blockchain.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* 加密
*/
public class Encrypt {
/**
* 传入字符串,返回 SHA-256 加密字符串
*
* @param strText
* @return
*/
public static String getSHA256(final String strText) {
return SHA(strText,