用Java编写第一个区块链
原文地址:https://www.cnblogs.com/zacky31/p/9057193.html
目标:
- 创建一个最基本的“区块链”
- 实现一个简单的挖矿系统
前提:
对面向对象编程有一定的基础
注意:
值得注意的是,这不会是一个完整的功能,恰恰相反,这是一个概念证明的实例,可以帮助您进一步了解区块链。
准备:
我将会使用Java来实现,当然你也可以使用任何面向对象的语言。
环境:
- JDK 8
- IDEA
- Maven
开始吧
区块链就好比多个块连接起来。其中每一块都将拥有自己的签名,签名中包含其前面的块信息和一些数据(例如交易信息)。

每个块不仅仅包含它之前的块信息,同时也包含自身。如果前面一块内容改变了,其 hash 值也会改变,将会导致其后面所有的块发生变化。通过计算和比较所得的 hash 值,我们可以判断区块链是否合法。换句话说,改变区块链中的任意内容,将会改变整个区块链的签名。
根据上面的分析,我们先创建一个 Block 类。
import java.util.Date;
public class Block {
public String hash; //存放数字签名
public String preHash; //前面块的签名
private String data;
private long timeStamp;
public Block(String data, String preHash) {
this.data = data;
this.preHash = preHash;
this.timeStamp = new Date().getTime();
}
}
接下来,我们需要一个生成签名的方法。有很多加密算法可供选择,这里使用 SHA256 刚刚好。
import java.security.MessageDigest;
public class StringUtil {
public static String applySha256(String input) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(input.getBytes("UTF-8"));
StringBuilder hexString = new StringBuilder();
for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
现在,我们向 Block 类中添加计算数字签名的方法,并修改一下其构造方法。
public Block(String data, String preHash) {
this.data = data;
this.preHash = preHash;
this.timeStamp = new Date().getTime();
this.hash = calculateHash();
}
public String calculateHash() {
String calculatedhash = StringUtil.applySha256(preHash + Long.toString(timeStamp) + data);
return calculatedhash;
}
到这里,可以写个 Main 方法看一下效果。
public class Main {
public static void main(String[] args) {
Block first = new Block("Hi i am the first block", "0");
System.out.println("Hash for block 1 : " + first.hash);
Block second = new Block("Hi i am the second block", first.hash);
System.out.println("Hash for block 2 : " + second.hash);
Block third = new Block("Hi i am the third block", second.hash);
System.out.println("Hash for block 3 : " + third.hash);
}
}

可以看见每个 Block 都有自己唯一的 数字签名,当然,现在还没有构成一个区块链,将这些块存放到一个 ArrayList 中吧。修改 Main 类后再次运行。
import com.google.gson.GsonBuilder;
import java.util.ArrayList;
public class Main {
public static ArrayList<Block> blockchain = new ArrayList<Block>();
public static void main(String[] args) {
blockchain.add(new Block("Hi i am the first block", "0"));
blockchain.add(new Block("Hi i am the second block", blockchain.get(blockchain.size() - 1).hash));
blockchain.add(new Block("Hi i am the third block", blockchain.get(blockchain.size() - 1).hash));
String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
System.out.println(blockchainJson);
}
}

现在,需要一种方法去验证创建的区块链。编写一段 isChainValid() 方法。任何块的改变将会导致这个方法失效。
public static Boolean isChainValid() {
Block currentBlock;
Block previousBlock;
for (int i = 1; i < blockchain.size(); i++) {
currentBlock = blockchain.get(i);
previousBlock = blockchain.get(i - 1);
if (!currentBlock.hash.equals(currentBlock.calculateHash())) {
System.out.println("Current Hashes not equal!");
return false;
}
if (!previousBlock.hash.equals(currentBlock.preHash)) {
System.out.println("Previous Hashes not equal!");
return false
}
}
return true;
}
接下来,尝试一下挖矿!

在 Block 类中,新增一个变量 nonce,并且添加到 calculateHash() 这个方法中,同时需要 mineBlock() 这个方法。这个方法中的 difficulty 变量就是用来控制计算量的。当设置的值较低时,大部分计算机很快就能算出来。
import java.util.Date;
public class Block {
public String hash;
public String preHash;
private String data;
private long timeStamp;
private int nonce;
public Block(String data, String preHash) {
this.data = data;
this.preHash = preHash;
this.timeStamp = new Date().getTime();
this.hash = calculateHash();
}
public String calculateHash() {
String calculatedhash = StringUtil.applySha256(preHash + Long.toString(timeStamp) + Integer.toString(nonce) +
data);
return calculatedhash;
}
public void mineBlock(int difficulty) {
String target = new String(new char[difficulty]).replace('\0', '0');
while (!hash.substring(0, difficulty).equals(target)) {
nonce++;
hash = calculateHash();
}
System.out.println("Block Mined!!!" + hash);
}
}
我们可以在 Main 类中定义个静态变量。尝试在每次创建新块去调用 mineBlock() 方法。
import com.google.gson.GsonBuilder; import java.util.ArrayList;
import java.util.Date; public class Main { public static ArrayList<Block> blockchain = new ArrayList<Block>();
public static int difficulty = 5; public static void main(String[] args) {
long beginTime1 = new Date().getTime();
blockchain.add(new Block("Hi i am the first block", "0"));
System.out.println("Trying to mine block 1...");
blockchain.get(0).mineBlock(difficulty);
long endTime1 = new Date().getTime();
System.out.println("Mining block 1 cost " + (endTime1 - beginTime1)); long beginTime2 = new Date().getTime();
blockchain.add(new Block("Hi i am the second block", blockchain.get(blockchain.size() - 1).hash));
System.out.println("Trying to mine block 2...");
blockchain.get(1).mineBlock(difficulty);
long endTime2 = new Date().getTime();
System.out.println("Mining block 1 cost " + (endTime2 - beginTime2)); long beginTime3 = new Date().getTime();
blockchain.add(new Block("Hi i am the third block", blockchain.get(blockchain.size() - 1).hash));
System.out.println("Trying to mine block 3...");
blockchain.get(2).mineBlock(difficulty);
long endTime3 = new Date().getTime();
System.out.println("Mining block 1 cost " + (endTime3 - beginTime3)); System.out.println("\nBlockchain is Valid: " + isChainValid()); String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
System.out.println(blockchainJson);
} public static Boolean isChainValid() {
Block currentBlock;
Block previousBlock;
String hashTarget = new String(new char[difficulty]).replace('\0', '0'); for (int i = 1; i < blockchain.size(); i++) {
currentBlock = blockchain.get(i);
previousBlock = blockchain.get(i - 1); if (!currentBlock.hash.equals(currentBlock.calculateHash())) {
System.out.println("Current Hashes not equal!");
return false;
} if (!previousBlock.hash.equals(currentBlock.preHash)) {
System.out.println("Previous Hashes not equal!");
return false;
} if (!currentBlock.hash.substring(0, difficulty).equals(hashTarget)) {
System.out.println("This block hasn't been mined");
return false;
}
}
return true;
}
}
运行发现,挖矿过程还是很费时间的。把计算量改成7,差不多每挖一个需要一分钟。。。

如果在此过程中,有人篡改了数据,将会导致:
- 区块链将会无效
- 不能够创建一个更长的区块链
- 网络中的诚实链将会比较长的区块链有时间上的优势
不过如果篡改数据拥有更强的运算速度,可能成功篡改。
这样,基本上简单实现了一个区块链了。
用Java编写第一个区块链的更多相关文章
- 【原】用Java编写第一个区块链(一)
写这篇随笔主要是尝试帮助自己了解如何学习区块链技术开发. [本文禁止任何形式的全文粘贴式转载,本文来自 zacky31 的随笔] 目标: 创建一个最基本的"区块链" 实现一个简单的 ...
- 【原】用Java编写第一个区块链(二)
这篇文章将去介绍如何使用区块链进行交易. [本文禁止任何形式的全文粘贴式转载,本文来自 zacky31 的随笔] 目标: 在上一篇文章中,我们已经创建了一个可信任的区块链.但是目前所创建的链中包含的有 ...
- 用Java实现简单的区块链
用 Java 实现简单的区块链 1. 概述 本文中,我们将学习区块链技术的基本概念.也将根据概念使用 Java 来实现一个基本的应用程序. 进一步,我们将讨论一些先进的概念以及该技术的实际应用. 2. ...
- 我是如何从Java转型为Go区块链工程师
我是如何从Java转型为Go区块链工程师 本文来自于一个比原链核心开发的陈述 前言 IT部落在加入比原链之前一直是做Java开发的,当初看到Go还有点犹豫,还怕过不了面试,结果是否掌握一门语言的考量确 ...
- 使用 java 创建你的第一个区块链(第二部分)
本系列教程的目的是帮助您了解如何开发区块链技术. 在这第二个教程中,我们将: 创建一个简单的钱包: 使用我们的区块链发送已签名的交易: 感觉更酷. 以上这些将使我们拥有自己的加密货币! 从上一个教程开 ...
- 使用 java 创建你的第一个区块链(第一部分)
本系列教程的目的是帮助您了解如何开发区块链技术. 在本教程中,我们将: 创建你的第一个(非常)基本的“区块链”. 实施简单的工作证明(采矿)系统. 惊叹于可能性. (我假设您对面向对象编程有基本的了解 ...
- 基于java实现的简单区块链
技术:maven3.0.5 + jdk1.8 概述 区块链是分布式数据存储.点对点传输.共识机制.加密算法等计算机技术的新型应用模式.所谓共识机制是区块链系统中实现不同节点之间建立信任.获取权益的 ...
- android和java以太坊开发区块链应用使用web3j类库
如何使用web3j为Java应用或Android App增加以太坊区块链支持,教程内容即涉及以太坊中的核心概念,例如账户管理包括账户的创建.钱包创建.交易转账,交易与状态.智能合约开发与交互.过滤器和 ...
- [C#]使用 C# 编写自己的区块链挖矿算法
[C#] 使用 C# 编写自己区块链的挖矿算法 文章原文来自:Code your own blockchain mining algorithm in Go! ,原始文章通过 Go 语言来实现的,这里 ...
随机推荐
- CentOS7.2重置root密码的处理方法
第一个里程碑 --在启动GRUB菜单中选择编辑选项,按键 "e" 进入编辑; 第二个里程碑 -- 大约在第16行找到 "ro" 将 "ro" ...
- 使用docker swarm集群心得
本片关于使用docker swarm 集群心得,也是一些经验吧!过程描述可能简单! 根据一些公司使用经历接收一下问题并针对问题作出应对策略 1.docker swarm集群 主节点数必须是单数,也就是 ...
- VS 附加到进程 加载“附加进程”弹窗很慢
最近遇到一个问题,点击Ctrl + Alt + P 附加到进程的时候,弹出下图弹窗“附加到进程”很慢. 找了很多原因,后来发现,是因为少安装了一个插件,安装后,弹窗的耗时明显少了. 下载 Win ...
- 重建二叉树[by Python]
题目: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2 ...
- 货车运输-洛谷-1967-LCA+最大生成树(kruskal(并查集))
传送门 一道:LCA+最大生成树 个人认为把这两个的板子写好(并熟练掌握了之后)就没什么难的 (但我还是de了好久bug)qwq 最大生成树:其实就是最小生成树的变形 我用的是kruskal (个人觉 ...
- Linux内存管理 (6)vmalloc
专题:Linux内存管理专题 关键词:vmalloc.页对齐.虚拟地址连续.物理不连续 至此,已经介绍了集中内核中内存分配函数,在开始简单做个对比总结Linux中常用内存分配函数的异同点,然后重点介绍 ...
- OCR技术浅析-tesserOCR(3)
tesserOCR使用 tesserOCR是文字识别软件(惠普公司开源) Optical Character Recognition (OCR)即光学字符辨识是把打印文本转换成一个数字表示的过程.它有 ...
- Linux下redis的安装及配置
1.去官网下载redis(redis.io) 2.将其解压到根目录下 3.进入解压的目录,然后编译源程序, 如果不是root账户登录的,命令前面需要加sudo make make install PR ...
- MySQL源码包编译安装
+++++++++++++++++++++++++++++++++++++++++++标题:MySQL数据库实力部署时间:2019年3月9日内容:MySQL源码包进行编译,然后部署MySQL单实例重点 ...
- centos7之rsync+serrsync
Rsync+Inotify-tools与Rsync+sersync这两种架构有什么区别 1.Rsync+Inotify-tools(1):Inotify-tools只能记录下被监听的目录发生了变化(包 ...