原文地址: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编写第一个区块链的更多相关文章

  1. 【原】用Java编写第一个区块链(一)

    写这篇随笔主要是尝试帮助自己了解如何学习区块链技术开发. [本文禁止任何形式的全文粘贴式转载,本文来自 zacky31 的随笔] 目标: 创建一个最基本的"区块链" 实现一个简单的 ...

  2. 【原】用Java编写第一个区块链(二)

    这篇文章将去介绍如何使用区块链进行交易. [本文禁止任何形式的全文粘贴式转载,本文来自 zacky31 的随笔] 目标: 在上一篇文章中,我们已经创建了一个可信任的区块链.但是目前所创建的链中包含的有 ...

  3. 用Java实现简单的区块链

    用 Java 实现简单的区块链 1. 概述 本文中,我们将学习区块链技术的基本概念.也将根据概念使用 Java 来实现一个基本的应用程序. 进一步,我们将讨论一些先进的概念以及该技术的实际应用. 2. ...

  4. 我是如何从Java转型为Go区块链工程师

    我是如何从Java转型为Go区块链工程师 本文来自于一个比原链核心开发的陈述 前言 IT部落在加入比原链之前一直是做Java开发的,当初看到Go还有点犹豫,还怕过不了面试,结果是否掌握一门语言的考量确 ...

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

    本系列教程的目的是帮助您了解如何开发区块链技术. 在这第二个教程中,我们将: 创建一个简单的钱包: 使用我们的区块链发送已签名的交易: 感觉更酷. 以上这些将使我们拥有自己的加密货币! 从上一个教程开 ...

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

    本系列教程的目的是帮助您了解如何开发区块链技术. 在本教程中,我们将: 创建你的第一个(非常)基本的“区块链”. 实施简单的工作证明(采矿)系统. 惊叹于可能性. (我假设您对面向对象编程有基本的了解 ...

  7. 基于java实现的简单区块链

    技术:maven3.0.5 + jdk1.8   概述 区块链是分布式数据存储.点对点传输.共识机制.加密算法等计算机技术的新型应用模式.所谓共识机制是区块链系统中实现不同节点之间建立信任.获取权益的 ...

  8. android和java以太坊开发区块链应用使用web3j类库

    如何使用web3j为Java应用或Android App增加以太坊区块链支持,教程内容即涉及以太坊中的核心概念,例如账户管理包括账户的创建.钱包创建.交易转账,交易与状态.智能合约开发与交互.过滤器和 ...

  9. [C#]使用 C# 编写自己的区块链挖矿算法

    [C#] 使用 C# 编写自己区块链的挖矿算法 文章原文来自:Code your own blockchain mining algorithm in Go! ,原始文章通过 Go 语言来实现的,这里 ...

随机推荐

  1. SQL CREATE DATABASE 语句

    CREATE DATABASE 语句 CREATE DATABASE 用于创建数据库. SQL CREATE DATABASE 语法 CREATE DATABASE database_name SQL ...

  2. 消耗CPU和内存的脚本

    用法 ./shell.sh 4 (4为4内核) 查看cpu内核数量 > lscpu 执行后会出现一堆kill命令,方便kill掉进程 #!/bin/bash endless_loop() { e ...

  3. [LeetCode] 5. 最长回文子串

    题目链接:https://leetcode-cn.com/problems/longest-palindromic-substring/ 题目描述: 给定一个字符串 s,找到 s 中最长的回文子串.你 ...

  4. (九)Delete an Index

    Now let’s delete the index that we just created and then list all the indexes again: 现在让我们删除刚刚创建的索引, ...

  5. Golang 入门 : 切片(slice)

    切片(slice)是 Golang 中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合.切片是围绕动态数组的概念构建的,可以按需自动增长和缩小.切片的动态增长是通过内置函数 append( ...

  6. linux 下一些命令

    1. 后台执行命令 nohup  http://blog.csdn.net/liuyanfeier/article/details/62422742 2. 查看日志文件 格式:tailf logfil ...

  7. pyspider安装出现问题参考

    File "c:\users\13733\appdata\local\programs\python\python37\lib\site-packages\pyspider\run.py&q ...

  8. 软工+C(2): 分数和checklist

    // 上一篇:题目设计.点评和评分 // 下一篇:超链接 教学里,建立清晰明确的评分规则并且一开始就公布,对于教师.助教.学生都是重要的. 公布时机 在课程开始的时候,就需要确定并公布评分机制,随着课 ...

  9. Kubernetes — 作业副本与水平扩展

    Deployment 看似简单,但实际上,它实现了 Kubernetes 项目中一个非常重要的功能:Pod 的“水平扩展 / 收缩”(horizontal scaling out/in). 这个功能, ...

  10. ReentrantLock重入锁详解

    1.定义 重入锁:能够支持一个线程对资源的重复加锁,也就是当一个线程获取到锁后,再次获取该锁时而不会被阻塞. 2.可重入锁的应用场景 2.1 如果已经加锁,则不再重复加锁,比如:交互界面点击后响应时间 ...