博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【原】用Java编写第一个区块链(一)
阅读量:7044 次
发布时间:2019-06-28

本文共 7592 字,大约阅读时间需要 25 分钟。

  写这篇随笔主要是尝试帮助自己了解如何学习区块链技术开发。

 【本文禁止任何形式的全文粘贴式转载,本文来自 zacky31 的随笔】

目标:

  • 创建一个最基本的“区块链”
  • 实现一个简单的挖矿系统

前提:

  对面向对象编程有一定的基础

注意:

  值得注意的是,这不会是一个完整的功能,恰恰相反,这是一个概念证明的实例,可以帮助您进一步了解区块链。

准备:

  我将会使用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
blockchain = new ArrayList
(); 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);    }}
View Code

  我们可以在 Main 类中定义个静态变量。尝试在每次创建新块去调用 mineBlock() 方法。

import com.google.gson.GsonBuilder;import java.util.ArrayList;import java.util.Date;public class Main {    public static ArrayList
blockchain = new ArrayList
(); 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,差不多每挖一个需要一分钟。。。

  如果在此过程中,有人篡改了数据,将会导致:

  • 区块链将会无效
  • 不能够创建一个更长的区块链
  • 网络中的诚实链将会比较长的区块链有时间上的优势

  不过如果篡改数据拥有更强的运算速度,可能成功篡改。

  这样,基本上简单实现了一个区块链了。

       

 

转载于:https://www.cnblogs.com/zacky31/p/9057193.html

你可能感兴趣的文章
《Java程序设计》 第一周学习任务(2)
查看>>
串复习
查看>>
C#语言课程10月31日
查看>>
11.01T3 实数二分
查看>>
react+antd分页 实现分页及页面刷新时回到刷新前的page
查看>>
express后台数据编写
查看>>
leetcode — partition-list
查看>>
在Eclipse设置打开项目或文件目录
查看>>
JAVA第一次作业
查看>>
android找不到aar包
查看>>
scala学习手记14 - 单例对象
查看>>
C++ sort求助!!!
查看>>
ng-view和ng-include之间的区别
查看>>
OD使用教程11(困境) - 调试篇11|解密系列
查看>>
apache的php模块讲解以及搭建phpmyadmin管理数据库mysql
查看>>
项目进展和总结
查看>>
dubbo协议参考手册(转)
查看>>
DevOps - Git - 必知必会
查看>>
数据结构-排序
查看>>
kernel不同版本中文件的变更(简洁版)【不断补充】
查看>>