区块链原理(很详细很全面)

本文最后更新于:3 个月前

去中心化

  • 中心化:我们使用支付宝、微信来支付,这就是中心化的应用,它存在一个中心机构来管理服务。
  • 去中心化:再比如自己寝室里室友之间代替付费,一天室友A给室友B出了一顿饭钱,室友B下午又给室友C出了一顿饭钱,室友B就告诉室友A去找室友C要钱就好了。这就是一个去中心化的系统,室友之间互相交易,没有一个中心机构,但是这样的系统要求互相信任。你敢和学校外一个陌生人这样交易吗?

本篇文章将使用区块链来解决一个实际问题,从而将区块链讲清楚。

交易

学校里每个同学手里都有二手书,平时同学们交易二手书要么就是自己用人民币私下交易,要么就是卖到二手书店和去二手书店买书,这都是中心化的模式。

有一天,李四看上了张三的一本二手书,张三要求李四也能给他一本二手书作为交换。如果李四有张三中意的二手书,那么交易会顺利完成。但是张三并没有看上李四任何二手书,但是张三相信李四以后终究会有一本二手书能入他的眼。

李四拿走张三的书并留下签名的单子

李四就给张三写了个交易单,还在上面签了自己的名字。张三以后可以拿这个交易单找李四换取二手书。
李四写给张三的交易单

这样李四拿着二手书回家,张三收获一张随时向李四索取一本二手书的交易单然后回家,交易皆大欢喜。

扩大交易

这个时候,张三看上了王五的一本二手书,但是王五也要求张三拿一本二手书和他交换,张三没有书能让王五看上,张三就和王五介绍他和李四之间的交易,说他有从李四那拿取一本二手书的权利。张三给王五写了张交易单并签名。

张三拿走王五的书并留下交易单

王五心想自己以后可以拿这个交易单去换取一本未知的二手书,于是答应了张三的交易单。

张三写给王五的交易单

于是张三拿着二手书开心回家,王五拿着交易单开心回家。皆大欢喜

如果王五找到李四,李四核验张交易单上的签名确实是张三的,hsah值也确实是自己交易单的hash值,就会给书给王五。

重复消费问题

但是上面的交易中存在一个严重的问题。
如果张三足够聪明,他可以马上再去找柳六,用说服王五的方式来再换取一本二手书。
这明显是交易的漏洞,将来就会有许许多多的人去找李四要二手书,而李四只和张三交易了一本书,却给予了张三无限的信任。

李四发现交易存在漏洞

三方验证

在这个漏洞被发现后,李四找到张三,重新商定交易方式。李四找了小明作为公证人,把原来的借条上多加了小明的签名,说张三要想和王五交易,要求得到小明的签名验证,否则交易不生效。

公证人小明参与交易
有小明公证的交易单

这样就解决了重复消费的问题,如果张三重复消费,很快就会被小明发现。

但是这样又很容易陷入中心化的思想,小明就成了中心机构。

如果小明和张三合作,则可以重复消费,如果和李四合作,则张三无法消费。大权就被握在小明手中了。

摆脱中心机构小明

显然大权不能握在小明一个人手里,需要能够让人放心的把权力交到第三方,比如让全校给这次交易作证。
如果让全校都在交易单签名,那么足够让人放心。
但是:

  • 全校人并不想参与进来
  • 并且全校都聚齐,难度大
  • 系统效率很低

于是李四提出相出方案:

  • 第一个在我交易单上签名的人,我奖励他能到我这里换取1/10本二手书
  • 给所有想得到奖励的人拉入一个p2p网络,在某人第一个在我交易单上公证签名后就广播告诉所有人
  • 其他人在得知交易单被公证签名后,就应该放弃继续在我交易单上公证签名,并且将这次公证进行确认

这样一来,大家为了谋求李四在自己交易单上给出的小费而竖着耳朵等李四发布交易单。

直到这里,会发现有一个很严重的问题:
如果李四两次从张三处拿走两本一样的书,那么这两张交易单就是一样的,然后就会出现错误了,李四可以说只发生了一次交易罢了,从而逃避一次交易。
所以我们需要在交易单上注明时间。像这样:

具备时间的交易单

交易单拓展:
我们的交易最终想面向所有的二手书,但你觉得500页的二手书和20页的二手书能等价交换吗?所以我们在交易单上额外增加一列页数来表明价值:

标明价值的交易单
再加上之前说好的小费是1/10本二手书,我们把它换算成页数也表明在交易单:

标明小费的交易单

多个公证人竞争下的交易

到这里,再梳理一下:

  1. 李四想要张三的二手书大学英语
  2. 李四写了上面的交易单注明时间、出书人、交易内容、页数、小费,然后自己亲笔签名,并且发布
  3. 一群公证人收到交易信息,抢着在交易单上签名,最终小明是第一个签名的
  4. 小明将小费收入袋里
  5. 其他公证人确认这个交易单的小费已经被小明拿走了

引入区块链

前面讲这么多,始终是基于交易单在讲,现在引入区块链的概念。

由于一个交易单的小费是有限的,于是约定所有公证人要一次凑齐10个交易,打包成一个区块,一次性给10个交易签名,这样就可以获得较可观的小费了。

区块

区块链就很多个这样的区块,这些区块都记录他们的上一个区块的hash值,然后使得它们类似一个链表结构一样。
从这个链结构里我们也可以看出区块排列在越前方,就越难以篡改,也就是说一个区块后面的区块越多,就越安全,这在我们后面解决链冲突时总是选择最长的链接相呼应。

节点

每个公证人就是一个节点,他们下面都有一条链,有若干个区块,理想状态下,各个节点的内容是相同的,因为每个节点在打包交易单生成一个区块时立即会广播到其他节点,然后其他节点就会验证此区块然后直接添加到自己的链当中,来保证每个节点都是同步的。

节点都有一条区块的链

但遗憾的是,在这样分布式的系统中,不可能绝对的同步。

分歧

p2p网络本身就有不确定性,无法确定有多少节点,无法确定谁与谁连接,因此各个节点的内容存在差异是必然的,所以我们需要解决问题的方法,既然有差异当然要消除差异,两个节点相比,无非就是两个里面取一个作为结果。我们的策略是:

  • 只保留最长的链。

比如,小明和小王都是公证人,他们都是一个节点,他们都有一个区块的链,一般而言,他们的链上的区块的内容是一致的,但有一次他们两个几乎同时打包并发布了一个index相同的区块,虽然两个区块都是合理的,但是对于整个网络来说,大家的链里面的区块不再一致了,因为小明和小王在打包区块后会马上签上自己的名字然后广播给其他节点,其他节点验证后确实是有效的区块,就会接受,然而也会有其他节点是先收到小王广播的区块,那么就有分歧了。

假如现在小明收到了小王广播来的区块,小明发现自己的链里面已经有了这一号区块,小明该怎么办?

解决链冲突

小明应该比较自己的链和小王的链谁更长,如果自己的链更短,那么很遗憾,自己的这条链要作废了,马上要从小王那里把整条链都复制过来。这是明智之举,因为在整个网络中,始终相信最长的才是有效的,遇到比自己长的直接放弃短链才能继续生存。

这样一来,你或许可以知道:

  • 没有绝对不会被撤销的区块
  • 越长的链越安全
  • 区块排在链的越前方越安全
  • 区块后面的区块越多越安全

但是这个解决链冲突的原则存在一个重大的问题,严重挑战整个系统的安全:
有坏心思的人,可以创建多个节点,日以夜继不停的自己发布交易,自己打包区块,然后只要他速度够快,就能摇身一变最长的链,那么其他正常的链遇到它就会被同化。

这样一来,所有节点开始了无用的速度竞赛。

为此我们在必须限制打包生成区块。

工作量证明

你可能已经发现我们前面的区块中有一个字段:工作量证明proof,那么它有什么作用呢?
proof:一个很难计算的,但是却很容易验证正确与否的数据。
工作量证明有很多种,比较常见一种:

一个区块有index,time,data等信息,如果用sha256算法给他们生成一个散列值,比如:

1
var hashString=sha256(index+time+data);

那么hashString的值可能是这样的:2e64a78bcad546901...,不难看出它没有任何规律,现在我要求多加入proof使得hashString的值能够以两个0开头

1
var hashString=sha256(index+time+data+proof);

于是:

  • 令proof=0,计算hashString,不是两个0开头
  • 令proof=1,计算hashString不是两个0开头
  • 令proof=2,计算hashString不是两个0开头
  • 令proof=324,计算hashString终于是两个0开头

所以324就是工作量证明,而在正常情况下,会要求hashString以4个0开头或者其它,难度要求会变得特别高,以至于你想要给一个区块计算出proof可能要很长时间,甚至机器运行消耗的电费都是不小的费用。

这样就可以很好的避免坏人不停的自己生成无用处的区块而变得很长很长的链从而覆盖掉正常的链。

如果你是坏人,你觉得你的机器和算力有实力和整个网络作比较吗?即便你想干坏事,你最明智的做法是先把已有的最长的链拉取到自己的节点下,然后开始日以夜继的在做计算,如果你的算力真的足够强,你确实可以变成最长的链,而且很快就会有大批的节点把你的链拉取过去,此时他们依旧可以继续下去,不过中间这些原有的区块就因为你而被覆盖或者撤销掉了。但是你也受到很大损失,你奋斗的链越长,你的损失就越大。

N确认交易

聪明的同学们在二手书交易时,当然会意识到自己所作的交易很有可能被撤销,所以在自己的交易单所在的区块在链上上的位置不够深时,他们不会认为交易已经结束。
比如:

  • 李四想要张三的二手书大学英语,并写了交易单给张三
  • 交易单马上被公证人小明打包到区块里,小明完成工作量证明后就马上广播
  • 这个时候就会有很多人接受这个区块
  • 整个网络里的人依旧在不停的生成区块并且添加到此区块后面
  • 在张三觉得自己交易单所在的区块后面的区块足够多时就觉得比较安全了,就可以把二手书交给李四,完成交易。

0确认交易:不必等待交易单被打包进区块就完成交易
1确认交易:当自己的交易单被打包进最新的区块里就完成交易
N确认交易:当自己的交易所在的区块后面跟进了N-1个区块时完成交易

N的值越大,交易越安全,在交易时,根据商品价值大小和对对方的信任程度来确定N的值

p2p网络

大家看到这里,会发现还有一个重要的问题:我们的各个节点之间是怎么连接的?新产生的区块是怎么广播给其他节点的?各个节点间是怎么同步信息的?

这是一个很有难度的问题,解决的方法也是很多。下面讲几个p2p网络需要解决的重要问题:

  • 节点间如何联系?
  • 怎么样实现广播?

由于我们的p2p网络不希望有中心服务器来操控,所以我们应当在我们的区块里保存一些和节点有关的信息,比如:

  • 每个区块都有打包的公证人签名,如果我们额外加上这个公证人节点的ip地址呢?
  • 每个交易单上都有消费者(入书人)的签名,如果我们额外加上消费者的ip地址呢?

通过这样的方式,即便没有中心服务器,我们各个节点之间只要分析自己本地的链就可以得知其他节点的位置,自然就可以建立连接发送区块。而广播就是向自己已知的这些节点发送信息。

用公私钥来保证交易安全

再看看我们的交易单:

朴素的交易单

上面的李四是消费者,这个交易单好比从李四的账户上扣除了500页余额一样,但是是不是所有人都能以李四的名义消费呢?答案是不能,因为上面有李四的签名,只有李四才能签出这样的字。
而在我们的区块链中,我们当然不是这样签名,而是由公私钥加密的形式来保证交易安全。

首先,你需要知道什么是公钥,什么是私钥?

公钥和私钥是一对夫妻,公钥加密过的东西只有私钥能解密,私钥加密过的东西只有公钥能解密。所以一般会把公钥公开,所有人都能知道你的公钥,但私钥只有你知道。

在你消费时,你用你的私钥把交易单加密,这样别人只能用你的公钥来解密查看交易单,而不能用你的私钥来生成交易单以你的名义支付。

结尾

就讲这些吧,欢迎到我的个人博客查看更多文章。