使用 java 创建你的第一个区块链(第一部分)

摘要:
本系列教程的目的是帮助您了解如何开发区块链技术。在本教程中,我们将:创建你的第一个(非常)基本的“区块链”。我将把我的项目称为“noobchain”,并使用相同的名称创建一个新类。2,制作区块链区块链只是一个由区块组成的链表/列表。区块链中的每个区块都包括自己的数字签名、前一个区块的数字签名和一些数据。计算和比较哈希可以检查区块链是否无效。更改区块链中的任何数据,将更改签名并破坏区块链。

本系列教程的目的是帮助您了解如何开发区块链技术。

在本教程中,我们将:

  • 创建你的第一个(非常)基本的“区块链”。
  • 实施简单的工作证明(采矿)系统。
  • 惊叹于可能性。

(我假设您对面向对象编程有基本的了解

需要注意的是,本教程并没有生产区块链的完整功能。相反,这是一个概念实现的证明,以帮助您理解区块链,为以后的教程打基础。

1,安装

教程中使用 Java,当然你可以使用其他的面向对象编程语言。 开发工具是 Eclipse,同样你可以使用其他的文本编辑器(虽然你可能会错过很多好用的功能 。

你需要:

  • 安装 Java 和 JDK;
  • Eclipse(或者其他 IDE/文本编辑器)。

你还可以使用谷歌发布的 GSON 类库,实现 Java 对象和 JSON 字符串之间的转换。这是个非常有用的类库,会在下文的点对点代码中继续使用,同样的,有其他方法能替换该类库。

在Eclipse中创建一个(file> new>)Java项目。我将把我的项目称为“noobchain”,并使用相同的名称创建一个新类。

使用 java 创建你的第一个区块链(第一部分)第1张

2,制作区块链

区块链只是一个由区块组成的链表/列表。区块链中的每个区块都包括自己的数字签名、前一个区块的数字签名和一些数据(这些数据可能是交易)。

使用 java 创建你的第一个区块链(第一部分)第2张

哈希=数字签名

每个区块不仅包含它前一个区块的哈希,也包含它自己的哈希(根据前一个区块的哈希和自己区块的数据计算得到)。如果前一区块的数据变化,则其哈希也变化(因为它的计算也与区块的数据有关),然后影响后面所有区块的哈希。计算和比较哈希可以检查区块链是否无效。

这意味着什么?更改区块链中的任何数据,将更改签名并破坏区块链。

所有我们先创建构造区块链的Block类:

1 importjava.util.Date;
2 
3 public classBlock {
4 
5     publicString hash;
6     publicString previousHash;
7     private String data; //our data will be a simple message.
8     private long timeStamp; //as number of milliseconds since 1/1/1970.
9 
10     //Block Constructor.
11     publicBlock(String data,String previousHash ) {
12         this.data =data;
13         this.previousHash =previousHash;
14         this.timeStamp = newDate().getTime();
15 }
16 }

可以看到,我们的区块Block包含一个String类型的hash作为数字签名。变量previousHash作为前一个区块的hash,String类型的data作为区块数据。

接下来我们需要一种方法生成数字签名:

有很多密码算法供你选择,然而SHA256最为合适,我们可以导入java.security.MessageDigest来使用该算法。

下面我们需要使用SHA256算法,所以我们创建一个StringUtil类并在其中定义了一个方法:

1 importjava.security.MessageDigest;
2 
3 public classStringUtil {
4     //Applies Sha256 to a string and returns the result. 
5     public staticString applySha256(String input){        
6         try{
7             MessageDigest digest = MessageDigest.getInstance("SHA-256");            
8             //Applies sha256 to our input, 
9             byte[] hash = digest.digest(input.getBytes("UTF-8"));            
10             StringBuffer hexString = new StringBuffer(); //This will contain hash as hexidecimal
11             for (int i = 0; i < hash.length; i++) {
12                 String hex = Integer.toHexString(0xff &hash[i]);
13                 if(hex.length() == 1) hexString.append('0');
14 hexString.append(hex);
15 }
16             returnhexString.toString();
17 }
18         catch(Exception e) {
19             throw newRuntimeException(e);
20 }
21 }    
22 }

不用担心看不懂,你只需要知道,它需要输入一个字符串,调用SHA256算法,然后就返回一个字符串签名。

现在让我们在Block类中创建一个新方法,调用SHA256算法来计算哈希。我们必须根据不希望被篡改的所有区块来计算hash,所以我们的区块包括previousHash,datatimeStamp(时间戳)。

1 publicString calculateHash() {
2     String calculatedhash =StringUtil.applySha256( 
3             previousHash +
4             Long.toString(timeStamp) +
5 data 
6 );
7     returncalculatedhash;
8 }

把该方法添加到Block的构造函数中:

1 publicBlock(String data,String previousHash ) {
2         this.data =data;
3         this.previousHash =previousHash;
4         this.timeStamp = newDate().getTime();
5         this.hash = calculateHash(); //Making sure we do this after we set the other values.
6     }

是时候做些测试了

在NoobChain类中创建些区块并打印它的哈希到屏幕上,确认它正常工作。

第一个区块叫做初始区块,因为它没有前驱区块,所以我们把它前一区块的哈希设为“0”.

1 public classNoobChain {
2 
3     public static voidmain(String[] args) {
4         
5         Block genesisBlock = new Block("Hi im the first block", "0");
6         System.out.println("Hash for block 1 : " +genesisBlock.hash);
7         
8         Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
9         System.out.println("Hash for block 2 : " +secondBlock.hash);
10         
11         Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
12         System.out.println("Hash for block 3 : " +thirdBlock.hash);
13         
14 }
15 }

输出如下:

使用 java 创建你的第一个区块链(第一部分)第3张

(你的是不一样的,因为你的时间戳是不同的)

现在每一个区块有自己的基于它自己的信息和前一区块数字签名的数字签名。

现在它还不是区块链,所以我们存储我们的区块到ArrayList,然后导入gson包将其转化为Json来查看。

1 importjava.util.ArrayList;
2 importcom.google.gson.GsonBuilder;
3 
4 public classNoobChain {
5     
6     public static ArrayList<Block> blockchain = new ArrayList<Block>(); 
7 
8     public static voidmain(String[] args) {    
9         //add our blocks to the blockchain ArrayList:
10         blockchain.add(new Block("Hi im the first block", "0"));        
11         blockchain.add(new Block("Yo im the second block",blockchain.get(blockchain.size()-1).hash)); 
12         blockchain.add(new Block("Hey im the third block",blockchain.get(blockchain.size()-1).hash));
13         
14         String blockchainJson = newGsonBuilder().setPrettyPrinting().create().toJson(blockchain);        
15 System.out.println(blockchainJson);
16 }
17 
18 }

现在我们的输出应该看起来接近我们所期望的区块链了。

现在我们需要一种方法来验证区块链的完整性。

在NoobChain类中创建一个isChainValid()方法,遍历所有的区块并比较它们的哈希。这个方法需要验证当前区块的哈希值是否等于计算得到的哈希值,前一区块的哈希值是否等于当前区块的哈希值。

1 public staticBoolean isChainValid() {
2 Block currentBlock; 
3 Block previousBlock;
4     
5     //loop through blockchain to check hashes:
6     for(int i=1; i < blockchain.size(); i++) {
7         currentBlock =blockchain.get(i);
8         previousBlock = blockchain.get(i-1);
9         //compare registered hash and calculated hash:
10         if(!currentBlock.hash.equals(currentBlock.calculateHash()) ){
11             System.out.println("Current Hashes not equal");            
12             return false;
13 }
14         //compare previous hash and registered previous hash
15         if(!previousBlock.hash.equals(currentBlock.previousHash) ) {
16             System.out.println("Previous Hashes not equal");
17             return false;
18 }
19 }
20     return true;
21 }

区块链中的区块有任何改变将导致该方法返回false。

在比特币网络节点上共享其区块,并且网络接受最长的有效链。什么阻止某人篡改旧块中的数据然后创建一个全新的更长的区块链并将其呈现给网络?工作量证明。哈希工作量证明系统意味着创建新的区块需要相当长的时间和计算能力。因此攻击者需要有比其他所有同行加起来还有多的算力。

3,开始挖矿

我们要让矿机完成工作量证明机制,通过在区块中尝试不同的变量值直到它的哈希值以某个固定数量的0开头。

在calculateHash()方法中添加一个整数类型变量nonce,添加一个mineBlock()方法。

1 importjava.util.Date;
2 
3 public classBlock {
4     
5     publicString hash;
6     publicString previousHash; 
7     private String data; //our data will be a simple message.
8     private long timeStamp; //as number of milliseconds since 1/1/1970.
9     private intnonce;
10     
11     //Block Constructor.  
12     publicBlock(String data,String previousHash ) {
13         this.data =data;
14         this.previousHash =previousHash;
15         this.timeStamp = newDate().getTime();
16         
17         this.hash = calculateHash(); //Making sure we do this after we set the other values.
18 }
19     
20     //Calculate new hash based on blocks contents
21     publicString calculateHash() {
22         String calculatedhash =StringUtil.applySha256( 
23                 previousHash +
24                 Long.toString(timeStamp) +
25                 Integer.toString(nonce) + 
26 data 
27 );
28         returncalculatedhash;
29 }
30     
31     public void mineBlock(intdifficulty) {
32         String target = new String(new char[difficulty]).replace('

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Linux命令之sftp 安全文件传输命令行工具Tier和Layer下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

YARN应用程序的开发步骤

开发基于YARN的应用程序需要开发客户端程序和AppMaster程序: 我们基于程序自带的例子来实现提交application 到YARN的ResourceManger。 Distributed Shell application:Client 步骤: 连接  ResourceManager; 通过ApplicationClientProtocol协议 与...

Java导出成可运行Jar包 dll或者so加载失败的解决方案

正常情况下, xxx.class.getResourceAsStream(lib) 这样就可以获取到了。但是我的是在JFrame的初始化中的, 所以需要Thread.currentThread().getContextClassLoader().getResourceAsStream(lib); 这样来获取。   这个坑  找了蛮久才找到解决方案记录下。...

JDK的第三个LTS版本JDK17来了

目录 简介 JDK17中的新特性 语言上的新特性 核心库的优化 支持新的平台 预览特性 其他改动 总结 简介 2021年9月JDK17发布了,JDK17是最新的一个LTS版本。所谓LTS版本就是可以得到至少八年产品支持的版本。从2014年的JDK8,到2018年的JDK11,再到2021年的JDK17。 同时Oracle也调整了LTS版本...

SpringBoot请求处理-常用参数注解使用

PathVariable RequestBody @RestController public class ParameterTestController { /** * 数据绑定:页面提交的请求数据(GET、POST)都可以和对象属性进行绑定 * @param person * @return */...

分布式调度任务管理——Dkron(2)运行配置

一、Dkron——服务器配置信息 dkron 的命令行操作都以dkron 开头,后面可以跟着不同的配置信息,例如在命令行敲出以下命令 :dkron agent --server --bootstrap-expect= 1 表示dkron以代理服务器形式启动,并且提供数据中心中预期的服务器数量为1。 其他相关配置dkron agent信息如下: –adver...

kafka客户端和服务端开发(三)

前面我们已经搭建了kafka的单机和集群环境,分别写了简单的实例代码,对于代码里面使用到的参数并没有做解释。下面我们来详细说一下各个参数的作用。 1. 创建kafka生产者 kafka生产者有3个必选的属性: bootstrap.servers 该属性指定broker的地址清单,地址的格式为host:port。清单里不需要包含所有的broker 地址,生产...