springboot责任链模式_Java实现简单的区块链(一)

本文介绍了如何使用Java和SpringBoot实现一个简单的区块链,包括环境准备、依赖管理、数据模型(Block和BlockList)、区块链构建教程、业务接口创建以及初步测试。通过这个教程,读者将理解区块链的完整性、散列函数的作用以及如何在SpringBoot中实现区块链的基本功能。
摘要由CSDN通过智能技术生成

2839d0b010be722a7aa473301430031d.png

广大读者都听说过比特币,或许还有智能合约,相信大家都非常想了解这一切是如何工作的。这篇文章就是帮助你使用 Java 语言来实现一个简单的区块链。

通过本文,我们将可以:

  • 创建自己的区块链

  • 理解 hash 函数是如何保持区块链的完整性的

  • 如何创造并添加新的块

  • 多个节点如何竞争生成块

  • 通过浏览器来查看整个链

  • 所有其他关于区块链的基础知识

环境准备

因为大多数区块链的产品都是用gradle作为构建工具,而且springboot也渐渐将重心转移到gradle,所以在此使用gradle作为构建部署工具

依赖jar包

jar包名版本用途
spring-boot-starter-web2.3.0.RELEASE提供web端展示界面
knife4j-spring-boot-starter2.0.4提供方便快捷的调试页面
commons-codec1.14编解码工具
lombok1.18.12简化类结构

UML类图

8cdbb982ee14cd78efe26dad4dbc71b4.png

数据模型

Block

我们来定义一个Block类,它代表组成区块链的每一个块的数据模型:

@Getter

@NoArgsConstructor

@ToString

@Slf4j

public class Block implements Serializable{

//当前块下标

private int index;

//块生成时间戳

private long timestamp;

//数据

private String data;

//是这个块

private String hash;

//上一个块通过 SHA256 算法生成的散列值

private String prevHash;

//块生成的构造函数

public Block(BlockList blockList, String data){

this.index = blockList.getLastBlock().getIndex() + 1;

this.timestamp = System.currentTimeMillis();

this.data = data;

this.prevHash = blockList.getLastBlock().hash;

this.hash = calculateHash(this);

}

//创建创世区块

public static Block generateGenesisBlock(){

Block block = new Block();

block.index = 0;

block.timestamp = System.currentTimeMillis();

block.data = "genesis block is generated";

block.prevHash = "";

block.hash = calculateHash(block);

return block;

}

//生成区块hash值

public static String calculateHash(Block block){

String record = block.index

+ block.timestamp

+ block.getData().toString()

+ block.prevHash;

log.info("calculate hash record is {}",record);

MessageDigest messageDigest = DigestUtils.getSha256Digest();

byte[] bytes = messageDigest.digest(record.getBytes(Charset.forName("utf-8")));

return Hex.encodeHexString(bytes);

}

//块数据校验

public boolean validBlock(Block oldBlock) {

//判断旧块的下标是否与新区块的下表对应

if (oldBlock.getIndex() + 1 != this.getIndex()) {

return false;

}

//判断新块是否和旧块的hash值是否匹配

if (oldBlock.getHash() != this.getPrevHash()) {

return false;

}

//校验当前块hash与数据是否匹配

if(!calculateHash(this).equals(this.hash)){

return false;

}

return true;

}

}

我们使用散列算法(SHA256)来确定和维护链中块和块正确的顺序,确保每一个块的 PrevHash 值等于前一个块中的 Hash 值,这样就以正确的块顺序构建出链:[ index:0| hash:"xxxw"| preHash:""] - [ index:1| hash:"xxxx"| preHash:"xxxw"] - [ index2| hash:"xxxy"| preHash:"xxxx"] 使用散列的理由:

  • 在节省空间的前提下去唯一标识数据。散列是用整个块的数据计算得出,在我们的例子中,将整个块的数据通过 SHA256 计算成一个定长不可伪造的字符串。

  • 维持链的完整性。通过存储前一个块的散列值,我们就能够确保每个块在链中的正确顺序。任何对数据的篡改都将改变散列值,同时也就破坏了链。以我们从事的医疗健康领域为例,比如有一个恶意的第三方为了调整“人寿险”的价格,而修改了一个或若干个块中的代表不健康的 VAC 值,那么整个链都变得不可信了。

BlockList

接下来我们建立一个链表结构保存区块的数据,将具体的链封装进我们自定义的BlockList数据结构中,仅开放我们需要的接口,保证链的安全性。

public class BlockList implements Serializable {

@Getter

private List<Block> chain;

public BlockList() {

chain = new LinkedList<>();

generateGenesisBlock();

}

public void add(Block block){

chain.add(block);

}

@JsonIgnore

public Block getLastBlock(){

return chain.get(chain.size()-1);

}

public int size(){

return chain.size();

}

private void generateGenesisBlock(){

//todo:补充完成创世块生成操作

if(chain.size() > 0){

throw new BlockException("已存在数据,无法创建创世区块");

}

chain.add(Block.generateGenesisBlock());

}

}

构建教程

现在我们有了单节点区块链的核心,区块和链,那么我们接下来就要将它运行在我们的springboot框架里。

建立链管理器

@Slf4j

public class BlockManager {

private BlockManager(){}

private static BlockList blockChain = new BlockList();

public static void addBlock(Block block){

blockChain.add(block);

}

public static BlockList getAll(){

return blockChain;

}

//替换较长区块

private static void replaceChain(BlockList newBlocks) {

if (newBlocks.size() > blockChain.size()) {

blockChain = newBlocks;

}

}

}

链管理器的作用是负责区块链的初始化,区块链和业务层的交互,在下一步建立节点通信中,也将担负起节点同步的责任。

创建业务接口

@RestController

@RequestMapping("block")

@Api

@Slf4j

public class BlockChainController {

@ApiOperation("获取链信息")

@GetMapping("getBlockChain")

public ResponseEntity<BlockList> getBlockChain(){

BlockList blockList = BlockManager.getAll();

return ResponseEntity.ok(blockList);

}

@PostMapping("addBlock")

@ApiOperation("添加新区块")

public ResponseEntity<BlockList> addBlock(String data){

Block newBlock = new Block(BlockManager.getAll(), data);

log.info("generate new block, {}",newBlock.toString());

if(!newBlock.validBlock(BlockManager.getAll().getLastBlock())){

log.error("generate new block failed, new block is not match old block");

return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();

}

BlockManager.addBlock(newBlock);

return ResponseEntity.ok(BlockManager.getAll());

}

}

测试一下

6fd1933b9070a31f5229482a2c8602fe.png

总结

好了,单节点的区块链就这么构建完成了,虽然很简单很简陋,但它具备块生成、散列计算、块校验等基本能力。接下来我们要学习比如tcp网络通信,去中心化的p2p连接,evm虚拟机的原理,共识算法,一步一步理解区块链的原理。

8ab93464c5631d46bbe985d7fd048313.png

  WE BUILD VALUABLE PRODUCTS

www.andlinks.com 联系方式: contact@andlinks.com

774012a693bd4e3c20bceb46ba48a533.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值