自己动手写区块链(Java版)

简介:

2018年开始区块链真是火啊。一夜暴富的例子一直在传说。今天我们就自己动手写一个基本的区块链。

先简单的说一下区块链是个什么(相信你早就知道了)。

区块链就是一个链表。把一堆区块串起来就是区块链。每个block有自己的数字签名(就是一串不规则看起来叼叼的字符串),同时包含有上一个block的数字签名,然后包含一些其他的data。

大体就长这样:

是不是很熟悉,链表。

好,继续。

数字签名是什么?就是hash。

而且每个block含有前一个block的hash值,而且每个block自己的hash也是由前一个的hash计算得来的。如果前一个block(数据块)的数据发生改变,那么前一个的hash值也改变了,由此就会影响到之后的数据块的所有hash值。

所以,通过计算和对比hash值这种方式我们就可以知道区块链是不是合法的,是不是已经被篡改。

什么意思呢?意味着只要你修改了区块链中的任何一个块中的数据,都将会改变hash,从而破坏了整个链。

好,不多说。上代码:

block块定义

先新建个block块:

public class Block {
   
   public String hash;
   public String previousHash; 
   private String data; //our data will be a simple message.
   private long timeStamp; //as number of milliseconds since 1/1/1970.
   
   //Block Constructor.  
   public Block(String data,String previousHash ) {
      this.data = data;
      this.previousHash = previousHash;
      this.timeStamp = new Date().getTime();
   }
}

你也看到了我们的Block里有四个字段,hash就是这个块自己的hash值,previousHash就是上一个块的hash值,data就是这个块所持有的数据,timeStamp就是一个时间记录。

数字签名生成

接下来我们就需要生成数字签名。

有很多种的加密算法来生成数字签名。这里我们就选择SHA256。这里先新建一个工具类用来搞定这个件事情:

import java.security.MessageDigest;//通过导入MessageDigest来使用SHA256

public class StringUtil {
   
   //Applies Sha256 to a string and returns the result. 
   public static String applySha256(String input){
      
      try {
         MessageDigest digest = MessageDigest.getInstance("SHA-256");
           
         //Applies sha256 to our input, 
         byte[] hash = digest.digest(input.getBytes("UTF-8"));
           
         StringBuffer hexString = new StringBuffer(); // This will contain hash as hexidecimal
         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);
      }
   }
   
   //Short hand helper to turn Object into a json string
   public static String getJson(Object o) {
      return new GsonBuilder().setPrettyPrinting().create().toJson(o);
   }
   
   //Returns difficulty string target, to compare to hash. eg difficulty of 5 will return "00000"  
   public static String getDificultyString(int difficulty) {
      return new String(new char[difficulty]).replace('\0', '0');
   }
   
   
}

好,现在我们在Block里添加生成hash的方法:

//Calculate new hash based on blocks contents
public String calculateHash() {
   String calculatedhash = StringUtil.applySha256( 
         previousHash +
         Long.toString(timeStamp) +
         Integer.toString(nonce) + 
         data 
         );
   return calculatedhash;
}

然后我们在构造函数里添加hash值的计算:

//Block Constructor.  
public Block(String data,String previousHash ) {
   this.data = data;
   this.previousHash = previousHash;
   this.timeStamp = new Date().getTime();
   
   this.hash = calculateHash(); //Making sure we do this after we set the other values.
}

一试身手

现在是时候一试身手了。我们新建一个main类来玩耍一次:

public static void main(String[] args) {
   Block genesisBlock = new Block("Hi im the first block", "0");
   System.out.println("block 1的hash值 : " + genesisBlock.hash);

   Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
   System.out.println("block 2的hash值: " + secondBlock.hash);

   Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
   System.out.println("block 3的hash值: " + thirdBlock.hash);

}

输出结果如下:

hash值是不一样的,因为每个block的时间戳不同。

现在每个块都有了自己的数字签名,并且这些数字签名都是基于每个块自身的信息以及前一个块的数字签名联合起来生成的数字签名。

但,现在还不能叫区块链。只是一个个区块。接下来就让我们把这些块装入一个ArrayList中:

public static ArrayList<Block> blockchain = new ArrayList<Block>();

public static void main(String[] args) {
    //add our blocks to the blockchain ArrayList:
    blockchain.add(new Block("Hi im the first block", "0"));
    blockchain.add(new Block("Yo im the second block",blockchain.get(blockchain.size()-1).hash));
    blockchain.add(new Block("Hey im the third block",blockchain.get(blockchain.size()-1).hash));

    String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
    System.out.println(blockchainJson);
}

现在看起来就比较紧凑了,也像个区块链的样子了:

检查区块链的完整性

现在就让我们在ImportChain中创建一个isChainValid()方法,它会遍历链中每个块,然后对比hash值。这个方法做的事情就是检查hash变量的值是否等于计算出来的hash值以及上一个块的hash是否等于previousHash变量的值。

public static Boolean isChainValid() {
   Block currentBlock; 
   Block previousBlock;
   String hashTarget = new String(new char[difficulty]).replace('\0', '0');
   
   //循环遍历每个块检查hash
   for(int i=1; i < blockchain.size(); i++) {
      currentBlock = blockchain.get(i);
      previousBlock = blockchain.get(i-1);
      //比较注册的hash和计算的hash:
      if(!currentBlock.hash.equals(currentBlock.calculateHash()) ){
         System.out.println("Current Hashes not equal");          
         return false;
      }
      //比较上一个块的hash和注册的上一个hash(也就是previousHash)
      if(!previousBlock.hash.equals(currentBlock.previousHash) ) {
         System.out.println("Previous Hashes not equal");
         return false;
      }
      //检查hash是否被处理
      if(!currentBlock.hash.substring( 0, difficulty).equals(hashTarget)) {
         System.out.println("This block hasn't been mined");
         return false;
      }
      
   }
   return true;
}

对区块链中的块的任何更改都将导致此方法返回false。

On the bitcoin network nodes share their blockchains and the longest valid chain is accepted by the network. What’s to stop someone tampering with data in an old block then creating a whole new longer blockchain and presenting that to the network ? Proof of work. The hashcash proof of work system means it takes considerable time and computational power to create new blocks. Hence the attacker would need more computational power than the rest of the peers combined.

上面说的就是POW 。之后会介绍。

好,上面基本上把区块链搞完了。

现在我们开始新的征程吧!

挖矿

我们将要求矿工们来做POW,具体就是通过尝试不同的变量直到块的hash以几个0开头。

然后我们添加一个nonce(Number once)到calculateHash() 方法以及mineBlock()方法:

public class ImportChain {
   
   public static ArrayList<Block> blockchain = new ArrayList<Block>();
   public static int difficulty = 5;

   public static void main(String[] args) {
      //add our blocks to the blockchain ArrayList:

      System.out.println("正在尝试挖掘block 1... ");
      addBlock(new Block("Hi im the first block", "0"));

      System.out.println("正在尝试挖掘block 2... ");
      addBlock(new Block("Yo im the second block",blockchain.get(blockchain.size()-1).hash));

      System.out.println("正在尝试挖掘block 3... ");
      addBlock(new Block("Hey im the third block",blockchain.get(blockchain.size()-1).hash));

      System.out.println("\nBlockchain is Valid: " + isChainValid());

      String blockchainJson = StringUtil.getJson(blockchain);
      System.out.println("\nThe block chain: ");
      System.out.println(blockchainJson);
   }

   public static Boolean isChainValid() {
      Block currentBlock; 
      Block previousBlock;
      String hashTarget = new String(new char[difficulty]).replace('\0', '0');
      
      //loop through blockchain to check hashes:
      for(int i=1; i < blockchain.size(); i++) {
         currentBlock = blockchain.get(i);
         previousBlock = blockchain.get(i-1);
         //compare registered hash and calculated hash:
         if(!currentBlock.hash.equals(currentBlock.calculateHash()) ){
            System.out.println("Current Hashes not equal");          
            return false;
         }
         //compare previous hash and registered previous hash
         if(!previousBlock.hash.equals(currentBlock.previousHash) ) {
            System.out.println("Previous Hashes not equal");
            return false;
         }
         //check if hash is solved
         if(!currentBlock.hash.substring( 0, difficulty).equals(hashTarget)) {
            System.out.println("This block hasn't been mined");
            return false;
         }
         
      }
      return true;
   }
   
   public static void addBlock(Block newBlock) {
      newBlock.mineBlock(difficulty);
      blockchain.add(newBlock);
   }
}

import java.util.Date;

public class Block {
   
   public String hash;
   public String previousHash; 
   private String data; //our data will be a simple message.
   private long timeStamp; //as number of milliseconds since 1/1/1970.
   private int nonce;
   
   //Block Constructor.  
   public Block(String data,String previousHash ) {
      this.data = data;
      this.previousHash = previousHash;
      this.timeStamp = new Date().getTime();
      
      this.hash = calculateHash(); //Making sure we do this after we set the other values.
   }
   
   //Calculate new hash based on blocks contents
   public String calculateHash() {
      String calculatedhash = StringUtil.applySha256( 
            previousHash +
            Long.toString(timeStamp) +
            Integer.toString(nonce) + 
            data 
            );
      return calculatedhash;
   }
   
   //Increases nonce value until hash target is reached.
   public void mineBlock(int difficulty) {
      String target = StringUtil.getDificultyString(difficulty); //Create a string with difficulty * "0" 
      while(!hash.substring( 0, difficulty).equals(target)) {
         nonce ++;
         hash = calculateHash();
      }
      System.out.println("Block已挖到!!! : " + hash);
   }
   
}

执行main,输出如下:

挖掘每一个块都需要一些时间,大概3秒钟。你可以调整难度,看看是如何影响挖矿时间的。

如果有人要窜改区块链中的数据,那么他们的区块链将是无效的,invalid。

他们将无法创建更长的区块链。

在你的网络中诚实的区块链有更大的时间优势来创建一个最长的链。

被篡改的区块链将无法追上更长、更有效的链。

除非它们比网络中的所有其他节点具有更快的计算速度。比如未来的量子计算机之类的东西。

好,我们已经完成了一个基本的区块链!

总结一下我们的这个区块链:

  • 每个区块上携带数据。
  • 有数字签名。
  • 必须通过POW来挖掘来验证新的区块。
  • 可以验证数据是否合法和是否被修改。



原文发布时间为:2018-02-22
本文作者:ImportSource
本文来源:腾讯云 云+社区,如需转载请联系原作者。

目录
相关文章
|
Java 测试技术 数据库
如何做SpringBoot单元测试?
如何做SpringBoot单元测试?
|
Java 区块链
Java工程师入门区块链的7个开源项目
如果你是一个对区块链感兴趣的Java工程师,那么除了阅读书籍或博客之外,更好的学习方法是亲自动手,深入了解以下7个最流行的Java区块链项目。 1、Corda Corda可能是Java开发人员进入区块链世界的最自然的出发点。
7145 0
|
存储 Prometheus 监控
使用helm快速部署prometheus+Grafana
通过Helm快速部署Prometheus监控栈:添加仓库、更新缓存并安装kube-prometheus-stack。建议创建独立命名空间(如monitoring)进行隔离,使用`port-forward`临时访问Prometheus和Grafana界面。通过自定义values.yaml文件可配置持久化、密码等参数,实现灵活管理。
1397 0
|
小程序 数据库 开发者
小程序云开发联表数据查询以及云函数中的应用
1、联表查询 (1)lookup联接两个表格 (2)使用match进行条件查询 (3)直接返回学生成绩平均值 (4)只显示teacher和score这两个值 2、在云函数中的应用 (1)在云数据库中添加数据 (2)创建云函数并初始化数据库 (3)编辑云函数入口函数 (4)上传部署云函数
1496 0
小程序云开发联表数据查询以及云函数中的应用
|
6月前
|
弹性计算 监控 安全
2026年阿里云秒杀活动全攻略:时间、入口、技巧与低成本上云方案
2026年阿里云推“普惠上云”战略,每日10:00/15:00限时秒杀轻量/ECS云服务器,低至38元/年!本文详解抢购技巧、入口及备选方案(如68元轻量、99元ECS、免费试用等),助开发者与中小企业低成本高效上云。
943 6
|
数据采集 安全 数据挖掘
Pandas数据合并:10种高效连接技巧与常见问题
在数据分析中,数据合并是常见且关键的步骤。本文针对合并来自多个来源的数据集时可能遇到的问题,如列丢失、重复记录等,提供系统解决方案。基于对超1000个复杂数据集的分析经验,总结了10种关键技术,涵盖Pandas库中`merge`和`join`函数的使用方法。内容包括基本合并、左连接、右连接、外连接、基于索引连接、多键合并、数据拼接、交叉连接、后缀管理和合并验证等场景。通过实际案例与技术原理解析,帮助用户高效准确地完成数据整合任务,提升数据分析效率。
1337 13
Pandas数据合并:10种高效连接技巧与常见问题
|
机器学习/深度学习 人工智能 供应链
AI赋能采购管理工具全解析:智能寻源、预测分析与风险控制的实践路径
本文探讨了采购管理工具从传统系统向智能化演进的发展路径,分析了现代采购系统的技术架构与核心功能,并构建了包含28项指标的选型评估体系。随着AI、区块链、数字孪生等技术的应用,采购管理正迈向智能预测与自动响应的新阶段。
2090 0
|
监控 安全 Java
Spring Cloud 微服务治理技术详解与实践指南
本文档全面介绍 Spring Cloud 微服务治理框架的核心组件、架构设计和实践应用。作为 Spring 生态系统中构建分布式系统的标准工具箱,Spring Cloud 提供了一套完整的微服务解决方案,涵盖服务发现、配置管理、负载均衡、熔断器等关键功能。本文将深入探讨其核心组件的工作原理、集成方式以及在实际项目中的最佳实践,帮助开发者构建高可用、可扩展的分布式系统。
740 1
|
人工智能 算法 定位技术
元宇宙房地产:虚拟土地的价值评估
【10月更文挑战第28天】随着科技发展,元宇宙成为融合虚拟现实、增强现实和区块链技术的数字世界。本文探讨元宇宙房地产中的虚拟土地价值评估,分析其影响因素、评估方法及未来发展趋势,包括地理位置、平台流量、土地用途、用户基础、技术创新等方面。未来,元宇宙房地产将呈现跨平台交易、定制化城市建设及金融产品创新等趋势。
1093 3
|
SQL JSON 分布式计算

热门文章

最新文章