阅读对象
本文阅读对象,主要是希望和即将从事区块链开发的项目架构师,开发工程师,项目设计或产品设计师。要求阅读者具备一定的“区块链”基础知识、概念和以及相关的技术知识。
如果你只需要对区块链应用做一个更深更直观的了解,通过本文的例子更清晰了解区块链是怎么回事,大概是怎么开发出来的,怎么使用,那么知道一些区块链相关知识即可。
如果你是一个想从事这方面工作的人,尤其是从事开发和架构的技术人员,那么需要的技术知识就相当的多了,无法一一列举,大概一个高级网络开发工程师和中级以上的架构师水平,是需要的。
前言
很多新的概念,人们在刚接触的时候,会让人感到非常困惑,学了好多次都稀里糊涂,并不仅仅是技术,很多地方都是如此。对于比较难理解的概念,用什么办法去学习最高效呢?我一直认为,就是找一个例子,或者写一个Demo,世上无难事,for一个example即可。。。
最近一段时间,AI人工智能方兴未艾,区块链技术又迎面走来,对数字货币的崛起感到新奇的我们,估计很想知道其背后的技术--区块链是怎样的一个东西。但是完全搞懂区块链并非易事,在实践中学习方为上策。
我喜欢把程序当成诗歌来写,理所当然要通过写代码来实现并运行一个例子,来理解并学习这门技术。这里,就通过用JAVA语言实现和构建一个区块链来探讨对区块链的理解。
本文,我们要用区块链来实现这么一个例子,名字叫“区块链成语接龙”。用户通过这个例子,可以不断的接龙前面一个用户的成语,规则和普通游戏一样,前面一个用户的成语的最后一个字,作为后面一个成语的第一个字。
单单作为一个应用,这个很简单呐,问题是,我们要用区块链的原理和相关技术实现它。
OK,let’s go… …
准备工作
这个时候其实我很想大喊一声:“区块链”其实不是某一种单纯的技术,而是基于某一种思想的多种技术的结合。
需要的技术包括分布式存储,分布式计算,P2P数据同步,加密解密,安全传输,一些语言,一些开发工具。。。还有一些新型的概念 – 分布式节点,工作量证明,共识算法。。。等等
基于哪一种思想呢,大家都说是“去中心化”,我觉得就是“反垄断”“反。。。”,敏感话题,不展开了。但是我事实上是一个喜欢民主的人,所以区块链的“去中心化”对我吸引力颇大。。。all men are created equal…J
本文里面涉及到的一些例子,来源是网上,有些是Python版本,有些是Java版本,C版本,考虑到JAVA更为通用和易读写(其实我是认为JAVA语言更像诗歌了),就把他们改成了JAVA版,所以要求读者对诗歌..哦,不是,是对JAVA非常了解,能读写基本的语法框架和逻辑,并且因为这个DEMO的特殊性,需要对网络框架和HTTP请求有基本的了解。
我们知道区块链是数据块和链的存储方式的组合,是由N多个数据区块按照链的组织和记录构成的不可变、有序的链结构,记录可以是交易、文件或任何你想要的数据,同时它们是通过哈希值(hashes)链接起来的。所以,在阅读本文之前,一定要阅读几篇关于区块链的文章,了解里面块,链,数据,工作量证明等等概念,最好也了解一些相关技术比如Hash,分布式存储等等的概念。如果你还不是很了解这些,请找度娘。
如果在了解这些概念的过程中,一不小心接触到了比特币,请一定要明白,比特币只是区块链技术的一个产品实现。如果还接触到其它一些诸如以太网等等的名词,那么需要知道,这些都是区块链技术下实现的一些框架和产品。
环境准备
理论上来说,可以用任何一种语言来创建任何一种技术的例子,包括区块链的例子,我们这里选用了JAVA,所以要在自己的电脑上,准备JAVA的相关开发环境。
确保你的电脑上已经安装了较新版本的JDK,Tomcat和某一种你熟悉的最好能整合Tomcat的JAVA IDE,本例用的是Eclipse。Tomcat在我们这个例子中间,是一个WEB工具,因为我们的项目,需要基于WEB HTTP 发布和运行。
如何安装Java和各种工具,包括如何用Eclipse创建Dynamic web项目并发布到Tomcat等等步骤,既然你已经如此熟悉JAVA了,这里就不再多讲。
<小提示:如需源码,请点击这里下载>
开始创建区块链
区块或称数据块Block类
区块链中每个区块包含以下基本内容:索引(index),Unix时间戳(timestamp),数据块(data)(包括交易,文字,申明,奖励等任何和合适的内容),证明或工作量证明(proof稍后解释)以及前一个区块的Hash值,Hash 用来链接数据块,同时确保数据块不被非法修改。
以下是一个区块的结构:
public class Block {
int iIndex; //索引
String sProof; //工作量证明,在这个例子里面,其实就是一个经过验证的正确的成语
String sPreviousHash; //前一个区块的Hash值
Timestamp tsCreateTime; //区块创建时间戳
/*数据块
*
* 用户每接上一个成语,会得到系统10元钱的奖励,同时会赢得前面一个用户的2元钱
* 数据区同时需要记录自己的用户名和回答出上一个成语的用户名
*
* */
String sSender; //回答出上一个成语的用户名
String sRecipient; //回答出当前这个成语的用户名
final int iMoneyAward=10; //系统奖励,数额固定
final int iMoneyWin=2; //赢取奖励,数额固定
public Block(){
}
}
区块链实现Blockchain类
import java.util.*;
import blockchain.Block;
public class BlockChain {
//用来存储区块
private List<Block> lBlockchain=new ArrayList<>[];
public BlockChain(){
}
//创建新块
public Block NewBlock(){
Block bRet=null;
//在这里创建一个新块
return bRet;
}
//Hash 一个块
public String Hash(Block block){
String sHash=null;
//在这里Hash 一个块
return sHash;
}
//其他方法
//....
}
Blockchain类用来管理链条,它能存储和更新链数据,加入新块等等,下面我们来进一步增加和完善里面的一些方法
<小提示:如需源码,请点击这里下载>
创建新块和创世块
当一个用户按照成语接龙的规则,对上上一个成语,并且系统验证这成语正确(工作量被证明)。这个时候我们就可以创建一个新块,并且加到链里面。
一旦工作量证明确认,并且上一个块hash 生成后,就可以简单调用函数创建一个新块了。
创建新块方法如下:
//创建新块
public Block NewBlock(int i,String proof,String hash,Timestamp c,String sender,String recipient){
Block bRet=null;
//在这里创建一个新块
bRet = new Block(i,proof,hash,c,sender,recipient);
return bRet;
}
这里,我们需要提一下创世块的概念,创世块是区块链的第一个区块,它是没有前区块的。逻辑上只在第一个用户第一次启动系统的时候,才需要创建创世块,后面的都是通过同步获得。创世块索引是0,同样需要给它加上一个工作量证明,我们这里就是初始成语“海阔天空”,因为没有前面的块,所以hash=””,同时给一个固定的创建时间。方法如下:
//创始块的创建,创世块是一个块,必须是固定的信息
//逻辑上来说,只有在区块链产品的第一个用户第一次启动的时候,才会需要创建创世块
public Block CreateFirstBlock(){
try{
Timestamp t=new Timestamp((new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).parse("2018-01-01 01:01:01").getTime());
return NewBlock(0,"海阔天空","",t,"","");
}catch(Exception e){
return null;
}
}
这里顺便贴上生成块的Hash字符串的方法:
//Hash 一个块
public static String Hash(Block block){
String sHash=null;
//在这里Hash 一个块
String s=block.sPreviousHash+block.sProof+block.sRecipient+block.sSender+block.tsCreateTime.toString();
sHash = MD5(s);
return sHash;
}
public static String MD5(String key) {
char hexDigits[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
try {
byte[] btInput = key.getBytes();
// 获得MD5摘要算法的 MessageDigest 对象
java.security.MessageDigest mdInst = java.security.MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
mdInst.update(btInput);
// 获得密文
byte[] md = mdInst.digest();
// 把密文转换成十六进制的字符串形式
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
<小提示:如需源码,请点击这里下载>
理解工作量证明
新的区块生成,必须依赖工作量证明算法(PoW)来构造。
PoW的目标是找出一个能被公认的方法,来证明你所从事工作的正确性。
在当前区块链应用中,PoW经常是被设计成通过寻找某一个符合特定条件的数字来证明,这个数字可能很难计算出来,但很容易验证。
这就是工作量证明的核心思想。
为了方便理解,举个例子:
假设一个整数 x 乘以另一个整数 y 的积的 Hash 值必须以两个零 ‘00’ 结尾,即 hash(x * y) = xxxxxx...00。设变量 x = 5,求 y 的值?
用Java实现如下:
int x=5;
int y=0;
while(true){
String md5=BlockChain.MD5(""+(x*y));
if(md5.charAt(md5.length()-1)=='0'){
break;
}
y+=1;
}
最后得出 y=69
因为MD5(5*69)=D81F9C1BE2E08964BF9F24B15F0E4900
随着区块链应用的扩展,应该有更多合理的工作量证明算法。
在比特币中,使用称为Hashcash的工作量证明算法,它和上面的问题很类似。矿工们为了争夺创建区块的权利而争相计算结果,甚至动用N台电脑,这就是称之为挖矿。通常,计算难度与目标字符串需要满足的特定字符的数量成正比,矿工算出结果后,会获得比特币奖励。当然,一旦计算出来,会非常容易验证这个结果。
实现我们的工作量证明
我们的工作量证明,那就比较简单,当用户输入下一个成语的时候,我们打开成语词典或者百度,一查。。。。就可以知道它接的对还是错了。
从系统上来说,我们可以通过调用外部开发查询接口,或者自带成语词库,来实现这个工作量证明,代码如下(此处引用了一个外部成语真实性查询接口):
//验证当前的成语是否符合规则
//pre 前一个成语
//cur 这一个成语
public static boolean ValidProof(String pre,String cur){
//验证这个成语的头一个字是不是上一个成语的最后一个字
if(cur.charAt(0)!=pre.charAt(pre.length()-1)){
return false;
}
//验证是否是成语
//http://chengyu.t086.com/chaxun.php?q=%B9%E2%C3%F7%D5%FD%B4%F3&t=ChengYu
String content=httpRequest("http://chengyu.t086.com/chaxun.php?q="+cur+"&t=ChengYu");
if(content.indexOf("没有找到与您搜索相关的成语")!=-1 || content.indexOf("搜索词太长")!=-1){
return false;
}
return true;
}
小结:通过上面的讲解,描述了区块链涉及到的一些新概念,区块,创世块,链式存储,工作量证明,主数据形式和内容,Hash加密等等。同时我们通过“成语接龙”的例子,在例子中用Java构造了相关的类和方法。
具备了区块链项目的基础组件后,下一步就是将这些组件运行起来,构造一个可以真正运行起来的区块链项目。
<小提示:如需源码,请点击这里下载>
启动一个Blockchain项目
我们都知道,区块链是一个分布式存储和分布式计算互相结合的技术和产品框架。其核心是去中心化存储。这个意味着,所有区块链的数据都应该存储在用户本地而不是某个中心服务器。所以,一个真正的区块链产品,需要在没有中心服务器支持情况下,解决如下几个基本的问题:
1、 每个用户端启动区块链产品时,如何将区块数据的初始下载到本地;
2、 新增加区块时,区块链内容的更新发布以及不同用户新增区块时间冲突的处理;
3、 日常运行过程中如何保证每个用户端(节点)数据的最新和及时同步;
创建节点
区块链项目中,一个正在运行着区块链项目的用户终端,称为一个节点。
每个用户第一次启动某个区块链项目,就相当于创建了一个节点。而以后每次启动项目,都意味着启动了这个节点。
为什么说是创建一个节点?原因很简单,区块链的基本思想是去中心化,去中心化的换一种说法,中间任何一个终端,都可以是中心,各自是对等的组网模型,也就是P2P组网模型。因为任何启动的终端,除了需要完成数据下载,使用,运算之外,还需要完成对外提供数据,同步,验证等等功能。
区块链网络系统之所以选择P2P作为其组网模型,这是由于二者思想的契合度确定的;区块链的根本出发点之一是去中心化,中本聪在他的白皮书里,提到电子现金系统中,第三方系统是多余的,没有价值,意思就是整个系统不要依赖任何特殊的第三方来完成自身系统的运转;而P2P网络的天然属性,就是全网节点平等,无特殊节点;由于区块链和对等网络的建设思想,高度契合,再加上P2P网络已经是一个发展成熟的网络技术;二者走到一起,几乎是一种必然。
所以我们在这个例子里面引入Tomcat,一方面是为了将一些用户操作转换到浏览器,演示方便,另外一方面,是为了方便发布一些对外接口,用来模拟在P2P对等网络之间数据同步。
首先我们使用Eclipse建立一个动态WEB 项目,将上面相关类导入,同时新建一个类似下面的 index.jsp 欢迎页面
<%@ page language="java" contentType="text/html; charset=gb2312"
pageEncoding="gb2312"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>区块链测试</title>
</head>
<body>
<% java.util.Date d = new java.util.Date(); %>
<h1>
欢迎使用区块链成语接龙。 <br>
原文链接:https://blog.csdn.net/weixin_33806300/article/details/92287085
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。