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

在本教程中,我们将:

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

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

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

1,安装

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

你需要:

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

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

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

2,制作区块链

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

 

  哈希=数字签名

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

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

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

 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. //Block Constructor.
public Block(String data,String previousHash ) {
this.data = data;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();
}
}

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

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

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

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

 import java.security.MessageDigest;

 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);
}
}
}

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

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

 public String calculateHash() {
String calculatedhash = StringUtil.applySha256(
previousHash +
Long.toString(timeStamp) +
data
);
return calculatedhash;
}

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

 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.
}

  是时候做些测试了

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

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

 public class NoobChain {

     public static void main(String[] args) {

         Block genesisBlock = new Block("Hi im the first block", "0");
System.out.println("Hash for block 1 : " + genesisBlock.hash); Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
System.out.println("Hash for block 2 : " + secondBlock.hash); Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
System.out.println("Hash for block 3 : " + thirdBlock.hash); }
}

  输出如下:

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

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

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

 import java.util.ArrayList;
import com.google.gson.GsonBuilder; public class NoobChain { 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);
} }

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

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

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

 public static Boolean isChainValid() {
Block currentBlock;
Block previousBlock; //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;
}
}
return true;
}

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

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

3,开始挖矿

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

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

 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;
} public void mineBlock(int difficulty) {
String target = new String(new char[difficulty]).replace('\0', '0'); //Create a string with difficulty * "0"
while(!hash.substring( 0, difficulty).equals(target)) {
nonce ++;
hash = calculateHash();
}
System.out.println("Block Mined!!! : " + hash);
}
}

  实际上每个矿机都从一个随机点开始迭代。一些矿机甚至尝试随机的nonce的值。更困难的可能不仅仅是整数。MAX_VALUE情况下,矿机可以尝试改变时间戳。

  mineBlock()方法输入一个整数变量difficulty,这是矿机必须找到的0的数量。在大多数计算机上可以立即处理1或2个0的情况,我建议用4到6个0进行测试。在写本文时,莱特币的难度大约是442592.

  我们将difficulty作为静态变量添加到NoobChain类:

public static int difficulty = 5;

  我们应该更新NoobChain类来触发每个新区块的mineBlock()方法。isChainValid()方法应该检查每个区块是否通过采矿得到哈希值。

 import java.util.ArrayList;
import com.google.gson.GsonBuilder; public class NoobChain { 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: blockchain.add(new Block("Hi im the first block", "0"));
System.out.println("Trying to Mine block 1... ");
blockchain.get(0).mineBlock(difficulty); blockchain.add(new Block("Yo im the second block",blockchain.get(blockchain.size()-1).hash));
System.out.println("Trying to Mine block 2... ");
blockchain.get(1).mineBlock(difficulty); blockchain.add(new Block("Hey im the third block",blockchain.get(blockchain.size()-1).hash));
System.out.println("Trying to Mine block 3... ");
blockchain.get(2).mineBlock(difficulty); System.out.println("\nBlockchain is Valid: " + isChainValid()); String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(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;
}
}

  运行结果如下

  挖掘每个区块需要一些时间(大约3秒)。你应该更改difficulty的值(即挖矿难度)来看看对挖矿时间的影响。

  如果有人篡改了你的区块链中的数据:

  • 他们的区块链是无效的;
  • 他们不能创建一个更长的区块链;
  • 在你网络中诚实的区块链会在最长的链上有个时间优势。

  一个被篡改的区块链不肯赶上一个更长且有效的链。

  除非他们的算力比你网络中其他所有节点的算力总和还要多。

  你已经完成了基本的区块链!

  你的区块链:

  • 由存储数据的块组成。
  • 由数字签名把区块 链接起来。
  • 需要工作量证明挖矿来验证新的区块。
  • 可以验证其中的数据是否有效且未被篡改。

项目文件 : https://github.com/CryptoKass/NoobChain-Tutorial-Part-1

原文:https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa

使用 java 创建你的第一个区块链(第一部分)的更多相关文章

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

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

  2. 用Java编写第一个区块链

    原文地址:https://www.cnblogs.com/zacky31/p/9057193.html 目标: 创建一个最基本的“区块链” 实现一个简单的挖矿系统 前提: 对面向对象编程有一定的基础 ...

  3. 只用120行Java代码写一个自己的区块链-3挖矿算法

    在本系列前两篇文章中,我们向大家展示了如何通过精炼的Java代码实现一个简单的区块链.包括生成块,验证块数据,广播通信等等,这一篇让我们聚焦在如何实现 PoW算法. 大家都无不惊呼比特币.以太坊及其他 ...

  4. 从零开始用golang创建一条简单的区块链

    区块链(Blockchain),是比特币的一个重要概念,它本质上是一个去中心化的数据库,同时作为比特币的底层技术,是一串使用密码学方法相关联产生的数据块,每一个数据块中包含了一批次比特币网络交易的信息 ...

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

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

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

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

  7. 只用120行Java代码写一个自己的区块链

    区块链是目前最热门的话题,广大读者都听说过比特币,或许还有智能合约,相信大家都非常想了解这一切是如何工作的.这篇文章就是帮助你使用 Java 语言来实现一个简单的区块链,用不到 120 行代码来揭示区 ...

  8. 只用120行Java代码写一个自己的区块链-2网络

    已经看完第一章的内容了吗,欢迎回来. 上一章我们介绍了关于怎么去编写自己的区块链,完成哈希和新块的校验.但是它只是在一个终端(结点)上跑.我们怎么样来连接其他结点以及贡献新的块呢,怎么样广播到其他结点 ...

  9. 只用120行Java代码写一个自己的区块链-4实现真正的p2p网络

    在之前的文章中,我们模拟了节点网络通讯,很多朋友反馈说,他们想看真正的节点网络通讯而不是单节点的模拟.本章将满足你们.

随机推荐

  1. nginx的请求限制

    一.http协议的连接与请求 总结: HTTP请求是建立在一次TCP连接的基础之上. 一次TCP请求至少产生一次HTTP请求. 二.连接限制 limit_conn_module 配置语法: Synta ...

  2. android dialog使用自定义布局 设置窗体大小位置

    AlertDialog.Builder builder = new Builder(mContext); builder.setTitle("更新进度"); final Layou ...

  3. ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] - Data truncation: Incorrect datetime value: '' for column 'pubdate' at row 1

    之前的Connector/J版本是:mysql-connector-java-5.0.4-bin.jar 后来换成mysql-connector-java-5.1.45-bin.jar,问题解决 20 ...

  4. 生成iOS-Xcode技术文档

    从源码中抽取注释生成文档的专用工具: [doxygen](http://www.stack.nl/~dimitri/doxygen/index.html):适于生成html文档与pdf文档. 支持的语 ...

  5. 【D3D12学习手记】4.1.6 Resources and Descriptors

    在渲染过程中,GPU将写资源(resources)(例如,后缓冲区,深度/模板缓冲区),读资源(例如,描述表面外观的纹理,存储场景中几何体3D位置的缓冲区).在我们发出绘图命令之前,我们需要将资源绑定 ...

  6. Day6 && Day7图论

    并查集 A - How Many Answers Are Wrong 题意:已知区间[1,n],给出m组数据,即[l,r]区间内数据之和为s,求错误数据的数量. 拿到这道题,真的没思路,知道用并查集, ...

  7. vscode 配置 GOPATH

    我已经放弃goland开发工具了,所以用万能的vscode 作为我学习go的开始: 按照网上的教程一步步配置了GOROOT,GOPATH等等,执行go env 也是没有问题的,但是当我用vscode写 ...

  8. python基础知识(元组)

    元组 不能更改内容 元组 (元素1,元素2) 元组的创建和删除 使用赋值运算符直接创建元组 元组名 = (元素1,元素2........) 只创建一个元素的元组    元组名 = (元素1,) 创建空 ...

  9. P1820 【寻找AP数】

    超级题目链接 这题程序实现其实并不难,难的是数学的思想及证明,这在真正的比赛考场上其实是不容易想到的 去年的年赛题目也是在往更难的数学思想上靠拢,并不是一味的编程,需要一定的数学基础 这个..数学性质 ...

  10. 【转载】深度学习中softmax交叉熵损失函数的理解

    深度学习中softmax交叉熵损失函数的理解 2018-08-11 23:49:43 lilong117194 阅读数 5198更多 分类专栏: Deep learning   版权声明:本文为博主原 ...