深入浅出区块链

区块链简介

提起区块链,大家可能会想到比特币。其实呢,这些和区块链技术本身不能划等号。区块链是随着比特币的产生而产生,并且在信息传播的时候比特币和区块链经常同时出现,所以有些人就会认为区块链就是比特币。

实则不然。好比用石头建造房子,区块链技术就像石头,而比特币只是其中的一幢房子。石头本身只是基础,用石头还可以建造金字塔和长城。用区块链技术也可以用来实现更多更广泛的应用。比特币是区块链最成功的应用,而区块链技术的应用远不止比特币。

简单来说,区块链是一个分布式的账本系统。在这个分布式系统中,没有中心,每个节点都是平等的。

近年来,区块链被认为是未来几十年产生最大影响的技术之一。它将带领我们走进下一个互联网时代——价值互联网,特别是在金融、物联网、资料管理、医疗等众多领域发挥越来越大的作用。

区块链历史

区块链技术是一个很年轻的技术,起源于21世纪。

区块链1.0

在2008年的一天,一个天才,中本聪发表了一篇白皮书《比特币:一种点对点的电子现金系统》,该文提出了一种完全通过点对点技术实现的电子现金系统,它基于密码学原理而不基于信用,使得在线支付能够直接由一方发起并支付给另外一方,中间不需要通过任何的金融机构。qu

点击查看清晰大图

在下一年,2009年,又是这个天才,在他的服务器上挖出了比特币的第一个区块,区块中的内容是当天泰晤士报头版一则关于救助银行新闻标题,该区块也称为创世区块,并因此获得了得了第一批的50個比特币。

点击查看清晰大图

在接下来的时间里比特币的快速发展阶段,最初比特币的价值是由用户相互协商的。其中毕竟有名的是2010年5月21日,一个弗罗里达的程序员用1万个比特币购买了价值25美元的披萨。想想现在1万个比特币可以购买上百万个披萨,不知那位程序员现在心情如何?

到2010年底前,比特币对经济总值已超过百万美元。

在2011年,比特币开始名声大噪,2011年6月,维基解密开始接受比特币的捐赠。不久,比特币的经济总值已超过2亿美元。

随着比特币的发展,其他数字货币也层出不穷。在这发展过程中,比特币作为其底层技术开始进入大众的视野。这个阶段以数字货币为主,可以称为区块链1.0阶段。

点击查看清晰大图

区块链2.0

在区块链2.0阶段,区块链技术的应用不再只是数字货币,而扩展到了一个去中心化的应用平台,该阶段的标志就是以太坊的出现。以太坊是一个開源的有智能合约功能的公共区块链平台,允许用户在上面搭建各种应用。

2013年,创始人发布了以太坊初版白皮书《以太坊:下一代智能合约和去中心话应用平台》,以太坊要做的是将区块链怎样应用于货币以外的领域。目标就是提供一个带有内置的成熟的图灵完备语言的区块链,用这种语言可以创建合约来编码任意状态转换功能,用户只要简单地用几行代码来实现逻辑,就能够创建以上提及的所有系统以及许多我们还想象不到的的其它系统。这种合约称之为智能合约。

2014年4月, Gavin发表了以太坊黄皮书,作为以太坊虚拟机的技术说明。按照黄皮书中的具体说明,以太坊客户端已经用7种编程语言实现(C++, Go, Python, Java, JavaScript, Haskell, Rust)。并且做筹集资金开始预售以太币。以太币是以太坊货币单位。

2015年,正式启动,第一个版本名为前沿。开始用的是工作量證明(proof-of-work)POW的算法,但未来可能考虑轉換成权益證明(proof-of-stake)POS。

以太坊最重要的技術貢獻就是智慧合約。

点击查看清晰大图

区块链3.0

随着区块链的发展,去中心化的模式变得越来越复杂。人们利用这一技术,在全球各地构建去中心化的组织或社区。这些去中心化的组织或社区不是完全的公有链,也称为联盟链或私有链。私有链,组织或社区构建的,只能得到内部少数人可以使用,信息不公开。联盟链则介于公有链和私有链之间,由若干组织或社区一起合作维护一条区块链,该区块链上有权限的管理,在若干组织之间公开。

超级账本项目是首个面向企业的开放区块链技术的重要探索。在 Linux 基金会的支持下,吸引了包括 IBM、Intel、摩根等在内的众多科技和金融巨头的参与。超级账本在之前的区块链技术基础上实现了完备的权限控制和安全保障。

超级账本包括多个框架项目,其中广为人知的是Fabric项目,Fabric 致力在一个共识网络内,对指定资产资产的信息进行互换、维护和调阅。

原理和特点

区块链是一个去中心化的分布式账本系统,是基于密码学原理而不基于信用,不需要第三方中介的参与,由分布式网络中的所有节点共同维护的系统。

点击查看清晰大图

其原理如下:

1.当分布式系统中一个节点进行一笔进行交易时,该节点会输入交易的编号,交易的数量,然后用自己的私钥生成数字签名,写上接收方的地址,最后发送整个分布式网络;

点击查看清晰大图

2.在分布式的p2p网络中,一个消息会辐射式从周边节点扩散,这样所有的节点都能知道新的交易的产生;

点击查看清晰大图

3.当其他节点收到交易内容后就对交易的数目和签名进行校验,确认签名无误并且发送者的确拥有足够多的资产,则会将该交易信息纳入一个区块中;

4.每个节点都尝试在自己的区块中找到一个具有足够难度的工作量证明,这个工作量证明就是区块链中的共识机制之一,这个过程通常称之为挖矿;

点击查看清晰大图

4.当一个区块找到了一个工作量证明后,该节点就能得到一定的报酬,类似于劳动所得,这个劳动主要是指计算机的计算和消耗的电费,而报酬一般是电子货币,比如在比特币系统中报酬就是一定数量的比特币,同时它向全网进行广播;

点击查看清晰大图

5.当且仅当包含在该区块中的所有交易都是有效的且之前未存在过的,其他节点才认同该区块的有效性;

6.其他节点表示他们接受该区块,而表示接受的方法,则是在跟随该区块的末尾,制造新的区块以延长该链条,而将被接受区块的随机散列值视为先于新区快的随机散列值。

节点始终都将最长的链条视为正确的链条,并持续工作和延长它。如果有两个节点同时广播不同版本的新区块,那么其他节点在接收到该区块的时间上将存在先后差别。当此情形,他们将在率先收到的区块基础上进行工作,但也会保留另外一个链条,以防后者变成最长的链条。该僵局的打破要等到下一个工作量证明被发现,而其中的一条链条被证实为是较长的一条,那么在另一条分支链条上工作的节点将转换阵营,开始在较长的链条上工作。在交易中也会扣除少量比例的数额作为手续费发送给挖矿者,

打个比方来说。存在这样一个小镇,这个小镇上没有银行(去中心化),但小镇上的每一个人都有一个匿名账号和一本小镇所有记录的账本(所有的账本可以自动同步),两个人之间进行交易可以直接进行,无需通过第三方机构,这叫去信任。

匿名账号只有拥有才能使用该财产,镇上的交易可以通过这些匿名账号进行的。而且因为是匿名的,所以拥有者的个人隐私不会被泄漏。(匿名性)

当镇上的张三想把他的一部分资产转移到李四那里,他会把需要转的这部分资产打包起来并用李四给他的锁把资产全部锁住。这样,除了拥有钥匙的李四之外其他人都打不开。然后,张三登录他的匿名账户在这个包裹上进行签名和标记资产数量,并写明是转移给李四的匿名账户上。完成后就通过广播把这个交易发送给镇上所有人。

这样每个人都知道了这笔交易,以后想否认也不可能。(不可撤销)

知道消息后其他人得来验证,第一验证这个签名是否有效,有效是指确实由张三的匿名账户发出,第二会从公开账本上验证张三的匿名账户上是否拥有该部分资产。当验证ok后,就将这笔交易记录到公开账本上。而进行这些操作的那个人也会得到一定数量的奖励。

经过这些步骤后,张三的这部分资产实际上已经转移到李四那里了。当李四需要的时候就可以用他唯一的钥匙打开这部分资产。

因为账本是所有人共同维护的,而且公开透明的,任何人想要知道某个账号上有什么财产上,都可以在这个账本上查到,任何人想在账本上做手脚也不太可能,广大人民群众的眼睛是雪亮的,细微的改动都能被发现。

在比特币系统中的共识机制是工作量证明,但在工作量证明的计算中有很大一部分会被抛弃,造成严重浪费,所以在以太坊中,还引入了另一种共识机制叫做权益证明。它类似于股东机制,拥有股份越多的人越容易获取记账权。此机制不需要大量的计算,而是通过保证金(数字货币、资产等具备价值属性的物品)来证明,收益为抵押资本的利息和交易服务费。提供证明的保证金越多,则获得记账权的概率就越大。

区块链基础

在前面区块链的架构部分介绍过区块链的产生过程,如下图

简单来说,区块链就是把(加密)数据存入区块中,经“挖矿”加入整个链条,生成的永久、不可逆向修改的记录。在本节中,将从代码的角度深入理解这一过程。实践是最好的老师,下面将动手实现一个简单的区块链。

为方便讲解区块链基础,在下面开始用Python实现一个简化版的区块链。区块的数据结构包含下面几个字段:

identifier: 一个唯一的字符串作为标示

previous_hash: 前一个区块的哈希值

data:区块中的数据

nonce:随机数,用来找到正确的哈希值

其中identifier这个唯一的字符串可以用python的uuid库uuid4()生成。previous_hash是在接入区块链的时候赋值。data是区块中写入的任意数据。比较特别的是nonce,它有什么用呢?它的作用很简单,用来找到正确哈希值。

至于为什么要找正确的哈希值,就要讲到区块的有效性。由上图中可以看到,区块链中的区块不是新生成就完成,而是需要通过“挖矿”这一步骤才可以。简单来说,挖矿的本质就是找到一个合适的nonce值使得区块的哈希值有效。

挖矿

哈希值是通过哈希算法计算得到的一段二进制值,不同的数据得到不同的哈希值。

In [1]:

# 这里举个简单的例子

# 导入相关类库

import hashlib

# 定义数据

data = "Hello World"

# 计算哈希值

msg = hashlib.sha256()

msg.update(data.encode('utf-8')) # 主要计算前必须将数据转成utf-8

msg.hexdigest()

Out[1]:

'a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e'

上面就一个哈希值,如果修改数据,比如添加一个nonce值就可以产生不同的哈希值

In [2]:

nonce = 0

msg = hashlib.sha256()

msg.update(data.encode('utf-8'))

msg.update(str(nonce).encode("utf-8"))

msg.hexdigest()

Out[2]:

'1370eeaaba7a6c7a234b1f82cc3b6d013a0088fd5e16408300f05b28b0015463'

在区块链中区块的哈希值必须满足一定条件才能算是有效的区块。这里设定区块的哈希值必须以0000开头才是有效的区块。为了得到以0000开头的哈希值,需要不断的修改nonce(挖矿)直到满足条件。下面定义一个函数来寻找该nonce值。

In [3]:

def mine(data):

nonce = 0 # nonce初始值为0

# 寻找正确的哈希值

while True:

msg = hashlib.sha256()

msg.update(data.encode("utf-8"))

msg.update(str(nonce).encode("utf-8"))

hash_code = msg.hexdigest()

# 如果满足条件,打印相应值并退出循环

if hash_code.startswith("0000"):

print("nonce:{}".format(nonce))

print("hash:{}".format(hash_code))

break

# 否则继续寻找

else:

nonce += 1

In [4]:

mine("Hello, World")

nonce:104803

hash:000022635160d3ae1c8c90261e0df5eb6538d7f6d42108d6ffdec17b585fb464

上面只是用data和nonce来计算哈希值,实际区块链中还会包含其他字段。下面定义一个区块的数据结构。

实现区块结构

In [83]:

# block.py

import hashlib

import uuid

class Block(object):

def __init__(self, data=None, previous=None):

self.identifier = uuid.uuid4().hex # 产生唯一标示

self.previous = previous # 父节点

if previous:

self.previous_hash = previous.hash() # 父节点哈希值

else:

self.previous_hash = None

self.data = data # 区块内容

self.nonce = 0 # nonce值

def hash(self):

'''

计算区块的哈希值,包括区块的标示、数据、前一区块的哈希值和nonce值

'''

message = hashlib.sha256()

message.update(self.identifier.encode('utf-8'))

message.update(str(self.nonce).encode('utf-8'))

message.update(str(self.data).encode('utf-8'))

if self.previous:

message.update(str(self.previous_hash.encode('utf-8')))

return message.hexdigest()

def refresh_hash(self):

if self.previous:

self.previous_hash = previous.hash() # 父节点哈希值

else:

self.previous_hash = None

def mine(self):

'''

挖矿函数

'''

# 初始化nonce为0

cur_nonce = self.nonce or 0

# 循环直到生成一个有效的哈希值

while True:

if self.hash_is_valid(): # 如果生成的哈希值有效

break # 退出

else:

self.nonce += 1 # 若当前哈希值无效,更新nonce值,进行加1操作

def hash_is_valid(self):

'''

校验区块哈希值有否有效

'''

return self.hash().startswith('0000')

def __repr__(self):

return 'Block'.format(self.identifier)

以上就是一个区块结构,这里的区块包含一个唯一标识符、父节点的哈希值、nonce值和该区块的内容字段。其中定义一个mine函数用了寻找合适的nonce值。另外定义了一个hash_is_valid函数用来判断这个是否以0000开头,即是否有效。下面对这个区块结构进行初始化。

In [84]:

# 创建一个内容为hello world的内容块

block = Block('Hello, World')

In [85]:

# 区块链的有效性

block.hash_is_valid()

Out[85]:

False

In [86]:

# 挖矿,循环直至找到合适的nonce

block.mine()

In [87]:

# 再次检查区块的有效性

block.hash_is_valid()

Out[87]:

True

至此,第一个有效的区块生成完成,下面开始实现区块链。

实现区块链结构

In [88]:

class BlockChain(object):

def __init__(self):

self.head = None # 指向最新的一个区块

self.blocks = {} # 包含所有区块的一个字典

'''

添加区块函数

'''

def add_block(self, new_block):

new_block.previous = new_block.previous

new_block.mine()

self.blocks[new_block.identifier] = block

self.head = new_block

def __repr__(self):

num_existing_blocks = len(self.blocks)

return 'Blockchain'.format(

num_existing_blocks,

self.head.identifier if self.head else None

)

定义好区块链结构后,下面就开始初始化一条区块链。

In [89]:

# 初始化

chain = BlockChain()

# 打印

chain

Out[89]:

Blockchain

In [90]:

# 添加区块

chain.add_block(block)

# 打印

chain

Out[90]:

Blockchain

In [91]:

# 添加更多的区块

for i in range(6):

new_block = Block(i)

chain.add_block(new_block)

# 打印

chain

Out[91]:

Blockchain

In [92]:

for i,v in chain.blocks.items():

if v.hash_is_valid():

print("{} is valid".format(k))

else:

print("\033[0;31m{} is invalid\033[0m")

a70c66dec8154a37864838638bc1ef71 is valid

a70c66dec8154a37864838638bc1ef71 is valid

a70c66dec8154a37864838638bc1ef71 is valid

a70c66dec8154a37864838638bc1ef71 is valid

a70c66dec8154a37864838638bc1ef71 is valid

a70c66dec8154a37864838638bc1ef71 is valid

a70c66dec8154a37864838638bc1ef71 is valid

以上就是一个简单区块链,可以看到当前的区块都是有效的。但是,值的注意的是,每个区块包括前一个区块的哈希值,所以,当区块链中一个区块被改变后,这个区块的哈希就会改变,从而影响到这块区块之后的区块。

In [93]:

# 比如改变第一个区块的内容

block.data = "Modify Data"

block.hash_is_valid()

Out[93]:

False

这将使这个区块哈希值改变并导致区块无效,并且,这个修改将影响之后的区块,因为之后的区块中的previous_hash依赖于前面的区块。改变如下:

In [95]:

for k,v in chain.blocks.items():

# 更新区块

v.refresh_hash()

if v.hash_is_valid():

print("{} is valid".format(k))

else:

print("\033[0;31m{} is invalid\033[0m".format(k))

b41171e618334412871495fb6d6f1a28 is invalid

1294d073adf5476db720d7b2e752d62b is invalid

97dd4e3905584c18ab2028c92b3afaad is invalid

02cb150841d6420ead9388d0ecfa3eef is invalid

7f8291bedac845af8637112136c41fd3 is invalid

2cfe78eac1db48f099a10ea968d468dd is invalid

2119e357b03442e1bbc12f355ffdf00c is invalid

可以看到由于前面区块的改变导致之后的区块也无效了。

以上模拟了单个用户的区块链操作,在实际过程中挖矿和校验的行为由区块链中其他用户进行的,并根据挖矿产生的劳动得到对应的报酬。这样就保证了单个用户无法修改区块链中的数据。并且这个过程是通过加密算法进行的,这就实现了区块链的去信任。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180502A0O09T00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券