您的位置:首页 > 编程语言

研究完比特币代码,发现了一个惊人秘密!

2018-03-28 00:00 495 查看


作者简介:段新亚,来自郑州大乘信息科技有限责任公司,公司总部位于郑州,致力于网络安全领域的技术研究与产品研发,是一家为相关部门提供计算机取证、互联网取证及信息安全产品与服务的专业化企业。本文是作者深入研究比特币代码后写的心得,帮助大家对比特币和区块链有一个全新的认识!

现在,因为比特币谈论区块链的人越来越多了,甚至将区块链作为庞氏骗局的说法都开始出现了。区块链算法本身是一种分布式存储模型,专门用于解决记账问题的算法。与其看这么多区块链的文章,不如读一下比特币的代码更可靠。

就像是我们写代码的来做一个炒菜的设备,你的关注重心应该在哪里?我觉得不应该是你用了什么语言,采用了什么框架,系统稳定性参数是多少,成本有多低,而应该是炒的菜好不好吃。正像是没人关注技术细节一样,人们关注的都是它能做什么。无论你的代码写得多好,系统架构是怎样的,硬件或者模型设计多优化,用了多么高科技的技术,但只要菜做的不好吃就是一个废品。



现在大体上只要提到区块链就是“噶韭菜”、“加密货币”、“圈钱”,但是区块链实际上只是一个为了解决中心记账问题的模型。

现在让我们回归区块链的记账系统的本质,接下来按照区块链是一个记账模型来讲。

传统会计记账的模型都是中心模型,以阿里举例,阿里中心有一个财务总部门,省级有财务部门,市级也有财务部门。阿里每天都有大量的交易产生,财务部门也会有无数的账单。市级财务部门的会计统计账单,发给省级;省级统计完市级发上来的账单,发给阿里的财务总部。

我们现在的财务记账模型看起来都是这样的,但是像阿里这样的大公司,每分每秒产生的交易额都是夸张的,在这种情况下数据量小的时候,各级财务部门自己就统计了,但是越汇总,做的帐就越是大的恐怖。如果这里面有人作假帐或者有人修改历史账单或者有人漏写了某笔帐,在无数的海量账单里,基本上就是一笔烂账了。不管管理体系做得多好,想要查出来被修改的错误账单,基本都是不可能的。

区块链就是为了解决这个财务坏账问题而使用的算法模型。

阶 段 一

这里先例举一个尽可能简单的区块链最基本的存储模型的代码。

// 块type Block struct {         // 时间戳         Timestamp     int64        // 账单数据        Data          []byte       // 前一个块的hash值        PrevBlockHash []byte       // 哈希值 Hash          []byte}

Golang的代码不用看的太明白,看注释就行。比特币代码里这个Block可以理解为在财务账单上记了一笔帐,而账单上需要写明记账的时间、账单上的交易数据。

PrevBlockHash暂且理解为一个数字,后面再作解释。

这个Hash可以理解为当前记账时间和交易数据,还有PrevBlockHash这个数字,用一个奇怪的数学公式算出来一个校验值,这个校验值是用来保护该账单不被修改的。

如果有人想来查账有没有被修改,需要看一下记账的时间和交易的原始数据,然后查一下PrevBlockHash这个数字是多少。把这三个数据都算一遍,看算出来的数字是不是Hash里面的数字,就知道账单有没有被修改了。

这样的数据块可以理解成一张一张的账单,一条一条的交易数据。后面使用账单块来称呼,每一个账单块都写上一个编号。

编号1的账单的PrevBlockHash就是一个数字,直接写成数字0,这个编号1的账单块俗称创世块。

编号2的账单的PrevBlockHash写的是编号为1的账单的Hash校验值,以此类推。

假设这个账单现在有100个账单块。如果有人想搞事情,作假帐,修改了编号为1的账单的数据。

编号1的账单的Hash数字是记账时间、账单交易内容和PrevBlockHash计算出来的数字,账单1的PrevBlockHash内容是0。修改账单记账时间或者修改账单的交易内容,都会导致Hash数字算出来会有变化。这个人要作假帐,他一定需要把Hash这个数字给改成重新算出来的数字。

但是我们的账单要求编号2的账单的PrevBlockHash这个数字要写账单1的Hash校验值。

同理因为账单2里的PrevBlockHash这个数字变化了,Hash这个数字也就变化了。

以此类推,我们现在的账单块是100个,为了修改账单1里的任何一点数据,都会导致需要将从1到100的所有账单都跟着修改,否则因为校验值错误,该账本会被作为错误账本被废弃掉。

这样一来,之前记的帐就基本不可能被修改了。这也就是区块链作为分布式存储和记账系统的优势所在,账单一旦录入基本不可能被修改。记账系统也是存储模型,存储账单的模型。

阶 段 二

上面只是讲了最基本的区块链存储模型。真实使用的时候,Data这里并不是真的账单,而是一个默克尔树的根节点的校验值。后面加上默克尔树,再重新理解一下区块链。

// 块type Block struct { // 块头 Head BlockHead // 账单数据 Data Merkle}// 块头
type BlockHead struct { // 时间戳 Timestamp     int64 // 账单数据 MerkleRoot   []byte // 前一个块的hash值 PrevBlockHash []byte // 哈希值 Hash          []byte}// 账单
type Merkle struct { // 每一笔交易记录 Data          []byte}

上面这个Merkle参数,默克尔树可以理解为就是一个账单。还是刚才的阶段一,每一个Data不是一条交易记录,可以理解为一个块记录就是一个账单。

当交易记录太多的时候,记账的交易数据量太大了,将整个账单参与Hash值的计算,运算量太大,太麻烦了,所以用Merkle树的方式记账。

关于默克尔树就不讲太多了,有兴趣的可以去查一下,跟区块链其实很像,其中每一个树节点都是这个树节点的子节点的Hash校验值计算出来的。

简单一点理解,可以认为通过Merkle树的方式做了一个账单,这个账单有一个根节点,这里记做MerkleRoot,是树结构的一个节点,不明白的还可以理解为一个校验数字。整个账单里只要有任何一个字节对不上,都会导致MerkleRoot这个数字产生变化,所以一旦这个账单做好了之后,将Merkle账单的MerkleRoot这个数字写入到区块头里面,那么整个账单的任何一个字都不能修改,一旦有任何修改,都会导致整个树结构上面的每一笔交易记录的Hash值需要重算。

最终导致MerkleRoot这个数字会发生变化,一旦有变化,就会导致块头的Hash值发生变化。导致这个账单录入之后的所有账单的PrevBlockHash值发生改变,这个块之后的所有的帐要全部作废重做。区块链就是通过这样一个管理模式来管理账单。



区块链总结
其实到此为止区块链已经讲完了。区块链其实就是一个简单的记账模型,目的是为了避免有人为意图的对账单做修改。区块链的每一个块都是在随着交易记录的增加不停地添加进来的。因为任何一个块的数据都被一个完善的数学系统锁定了,任何一个字都是不可修改的,只要有修改,都需要重算从这个账单块开始的后面所有的账单块,否则账单就是一个错误账单,不会被系统采纳了。
现在的区块链其实有三种使用模型:去中心化型、联盟中心型、多中心型。按照投票确定谁的账单是最长的,按照谁的账单作为总账。
通过这种方式,避免了中心化记账,财务总中心的人恶意修改数据,还没人管得了的问题。如果是多个中心互相牵制,每人手里都有一笔完整的帐,其一验证账单每个节点是否计算正确,来确保账单不被修改,其次验证每个块的内容,谁的账单记账数量最多(俗称区块链最长),按照谁的账单作为总账,其它所有节点接到通知之后,更新自己的账单。
去中心型是任何人都可以加入到财务中心里来,每个人都能拿到总账,都能验证总账,也都能帮忙记账。只要你算的是对的,而且算的最快,都可以被采纳。
联盟中心型是多公司互相牵制的模型,多个公司用这种模型管理总账,任何一家公司都不能轻易修改这本动态的一直在记录的账单。
多中心型类似中国银行这种,还是中央管理,但是并非一个节点记账,而是多个点同时记账,避免任何一本帐被财务总中心的人修改。
这里区块链已经需要面对两个严重的问题。区块链的每个账单块能记的账单数量是有上限的,现在一个账单块大小是2 MB,不能超过这个大小,一旦要修改这个块大小,就需要区块链系统的所有节点算法跟着变化,代价会变得很高。
这里随便说一个数字,一个块假设能保存2千笔交易记录,像是阿里今年双十一,3分01秒,成交额100亿元。除一下就是五百万,也就是说3分钟内要写入500万账单块。因为挖矿等某些原因(后面讲解),比特币平均每十分钟写入一个账单块。
每小时6个块,一天是24小时,也就是说阿里巴巴去年双十一这一天,三分钟产生的账单,需要大约34 722天,大概95年来记账。这个记账速度根本就是来开玩笑的。
这个记账速度是可以通过算法调整的,但是这么大的交易量,增加记账速度会使块容易冲突,因为需要少数服从多数投票选用哪个最长的账单,全网通知并投票选举这件事情也是需要时间的,虽然计算机很快,但是也是需要时间的。增加块大小还是加快记账速度都有很高的通信代价,也是一件账单数量过大情况下很不现实的事情。


阶 段 三

看到这里大家应该明白什么是区块链了,比特币是用区块链技术来管理它的账单的,比特币使用区块链技术如何交易也非常清楚了。但是比特币挖矿又是怎么一回事儿呢?

在这里,加密货币的加密交易过程部分就不详细讲了,有兴趣的可以自己去查一下。我这里假设明文交易的模型,每一笔交易的交易记录都不加密,直接写在账单上。

这个记账系统的管理工作都用算法实现了,需要的只有实际记下每一笔帐的“会计”,而在区块链系统里的“会计”,也就是我们俗称的“矿工”。

所谓矿工挖矿是什么意思,是指这个多中心模型里,没有财务管理,每一个人都是“会计”,每一个“会计”手里都拿着整个系统完整的账本,然后开始做账,在整个区块链里记下下一个账单块这样的工作,成功将账单写进去,而且计算正确的那个人,将自己的账单发给所有人,然后将我们每个人做的帐放到一起,计算正确的账本而且又是最长的,一定是第一个将该账单成功写进去的那个“会计”。

然后按照算法当场计算,他成功记了一笔账,应该给他多少钱,然后当场发放奖励,这就是挖矿。但是这个挖矿是有问题的,谁的算力强,算得快就总是谁拿钱,别人就没有工作的热情了,而且大家记账的速度都差不多的,很容易撞车,同时提交账单。

所以我们重新调整一下这个块的结构。

// 块type Block struct { // 块头 Head BlockHead // 账单数据 Data Merkle}// 块头
type BlockHead struct { // 时间戳 Timestamp     int64 // 难度值 Bits []byte // 目标数 Nonce []byte // 账单数据 MerkleRoot   []byte // 前一个块的hash值 PrevBlockHash []byte // 哈希值 Hash          []byte}// 账单
type Merkle struct { // 每一笔交易记录 Data          []byte}

这里在块头结构里添加了两个参数:Bits难度值和Nonce目标数。

先说一下加这两个参数的原因。刚才遇到的问题是,一屋子“会计”,每个人都在做账,谁最快做出来帐,统计投票之后所有人更新账单,按照最快做账那个人的账本更新。

但是算这个账单,虽然加了一些很麻烦的算法,还是很简单的,大家算得都很快,一起提交,而且都算得是对的,这事儿很容易产生纷争。如果有一个人算得非常快,账本总是他在记,他是不是会搞点小手段呢?所以,还是应该每人记一点帐,这个帐更可靠。

这个就是中本聪提出的“工作证明机制”,我们所有人都先别开始记账。我们都开始算一个非常难的数学题,而且是个超级麻烦,完全没有用,基本靠撞大运的数学题。谁算出来了,谁再按照流程算你的帐,计算机按照流程记账基本就是瞬间写入,但是算这个很麻烦的数学题,就需要时间了,而且是个基于撞大运的数学题,没人确保自己能算出来。通过这种方式来拖延记账时间。

如果真的拿区块链作为记账系统来用,根本不需要一个刻意去拖慢记账速度的东西,但是比特币就是这么写的。也是我认为这个“工作证明机制”是一个资源空转,纯属浪费的东西。然后我详细讲一下这个数学体是什么。

刚才讲区块头的Hash校验值计算是用记账时间、账单数据和前一个块的Hash值算出来的,我们把Bits难度值和Nonce这两个数也参与到Hash运算里来。

先说Bits难度值,这个数是依赖于之前记过的帐算出来的,可以认为在当前要记的这个帐里,它是一个确定的写死的一个数字,具体怎么来的,可以自己查一下资料。

Bits = difficulty_1_target / current_target

所以我要开始计算这个块的Hash值的时候,这个Bits可以认为不影响计算结果。

然后是Nonce目标数,记账人随便写这个数字。但是因为Nonce参与运算,所以写不同的Nonce数值,算出来的结果都是不同的。

然后接下来的工作全靠蒙,不停地尝试各种各样的Nonce这个数字,让计算出来的Hash数值小于Bits这个写死的数字。

如果你成功蒙到了这个数字,就赶紧把算好的账单,以及带着账单里的这个Nonce数字广播发给屋里所有的人,大家都验证了一下账单没问题。全靠猜写的Nonce这个数字算出来的Hash数字确实小于Bits这个数字。屋里所有的“会计”全部更新自己的账单,把你成功记账这件事情写到账单里,然后系统计算应该给你多少工资,当场结算。

因为算出来的Hash小于Bits这个数字,如果Bits这个数字太大还是会导致很多人很快能算出来。因为记账的时候账单上写着记账的当前时间,而且这个数字还是不允许修改的,所以能算出来平均你们一堆人多长时间可以算出来一个账单块,并提交写入总账本的。如果速度太快,不到10分钟就算出来了,稍微把Bits这个数字按照算法稍微调小一点,基于前面的账本记录时间计算。

因为每个人手里都有账本,这个数字要写多少,自己就直接算出来了,不需要谁来控制这个记账难度系数,继续维持区块链记账系统,无中心无管理的状态。

同时通过这种难度波动的方式控制大家的记账速度,也就是上面提到的比特币平均每10分钟记账一次,写入一个账单块,避免多人同时记账导致数据冲突。

继续吐槽一下,这个“工作证明机制”单纯的是用来拖慢记账速度的,此模式确实有点蠢,但是的确很有效,确实解决了在互相不信任的无中心模型下,怎么让互相完全不信任的人之间管理账本的问题。



补 充
其实还有很多细节没讲,比如比特币的发放这个模型。通过记账成功的方式直接按照算法发放奖励,这只是一种中本聪随手写的奖励方式。为了让大家把这个记账游戏继续玩下去。
比特币系统里能凭空获得比特币的只有“会计”挖矿,记账成功时按照算法自动获得,还有系统奖励衰减来回避通货膨胀问题等。
但是现在更多的模型是“会计”无奖励的,由系统从最一开始直接发行货币,由中心系统发放货币,其实也是有监管的,监管中心可能导致货币控制等问题。
这个记账系统没什么可记的账本,就变成了中本聪写的一个记账游戏系统“比特币”系统。在记账的过程中去产生只对“会计”发放的货币,再由参与者之间互相交易的模型。但说白了,比特币就是个游戏系统,没人用的时候就是一堆废弃的数据。尤其当“会计”从系统里消失的时候,这个记账系统就崩坏了,没有记账的“会计”,就无法成交了,所有的成交单都会成为废品。
再加上比特币的每次记账成功发放数量,平均每四年会除以二,你四年前成功记账获得一万,现在成功记账获得五千。数字是我随便写的,因为奖励发放是浮点数记录的,不是数学上那种可以无限细分的数字,所以其实从某一刻开始比特币记账就拿不到收益了。
要么有办法用其它手段让“会计”挣到钱或者采用交易提成等手段,否则“会计”一定会从这个不赚钱的游戏里退出来,也就是比特币系统一定有崩坏的那一天。
虽然比特币的游戏模型是一个注定会崩坏的模型,但它只是一个记账游戏而已。区块链技术也绝对不是什么庞氏骗局,只是一个记账系统罢了。




1.一个嵌入式老鸟的肺腑之言:空有一腔热血还远远不够!2.Linux 基金会开放ACRN管理程序,用于物联网和嵌入式设备设计!3.详解嵌入式Linux工程师的成长经历4.什么是C语言的可移植?5.区块链技术的最大价值归宿:物联网6.做了整整八年模电,却说自己根本没入门,咋回事?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐