美文网首页
Teahour.fm #92 怎么撸一条链

Teahour.fm #92 怎么撸一条链

作者: cryptojan | 来源:发表于2018-07-14 19:57 被阅读142次

    本文是Teahour.fm第92期的文字版,音频版本可以戳这里

    D:Hi,大家好,欢迎来到新一期的 Teahour,我是今天的主播 Daniel。现在坐在我旁边的,算是我们的老朋友了,他曾经来过我们 Teahour 做客,跟大家讨论 Blockchain 和 Ethereum 的问题,他就是谢晗剑同学。Jan, 欢迎你。

    J:大家好,我是谢晗剑。

    D:我相信,很多熟悉 Teahour 的朋友已经很久没有听过我的声音了。我现在能回忆起来的上一次录制 Teahour 的时间,大概可以追溯到 2015 年 10 月份。为什么停更这么久?你们懂的,肯定有很多原因,时间关系大家可以当做我已经把这些原因都讲过了,并且大家也都理解了,所以我们先快进这一段。好消息是,现在 Kevin、我和 Terry 我们三个主播现在都在同一家公司工作。既然我们三位聚在一起,肯定要做点什么,所以我们决定把 Teahour 重新捡起来,也就是说 Teahour 以后正式恢复播出!当然,也因为我们目前在从事 Blockchain 这个行业,所以我们马上也会开一个 Teahour 的分支—— Forkit,它会专注于区块链相关的话题。那么今天,我们请到谢晗剑同学来录制这新一期的 Teahour ,也是希望我们能够联合录制几期关于区块链的讨论,这几期会同时在 Teahour 和 Forkit 播出。希望大家能一如既往地支持我们,也多多关注 Forkit。

    J:这里我们说的是 Forkit,Forkit 是非常文明的一个名字。

    D:Jan 还记得你上一次来 Teahour 录制的那两期节目是什么时候吗?

    J:我记得,应该是在 15 年底的时候,还没到 16 年。

    D:是的,第一期在 15 年底,第二期在 16 年的年初,1 月份。那个时候,以太坊还处于在国内刚刚起步的阶段。我们请你录制了这两期节目以后,你知道这两期节目后来有多大的反响吗?通过我们后台的数据统计,这两期节目是我们 Teahour 所有的节目中播放和回放次数最多的,而且我在很多场合都听到别人跟我提起:“嗨,我就是因为听了你们 Teahour 的那两期节目,才理解了 Ethereum 是什么,并且从此正式入坑”。所以你的那两期节目真的让很多人进入到了这个行业中。谢谢你,Jan。

    J:听到这个消息我真的非常开心。我想这也是我们一直想做的事情——把区块链和以太坊介绍给大家,让大家知道世界上有这么一个很有意思的东西,这么看来目的是达到了。

    D: 在区块内行业里有一句话叫做币圈一日人间一年。如果我们掐着日子算一下,那两期节目迄今为止大概已经过去了 27 个月,如果我们假设每个月有 30 天的话,27×30 是810天。 好,Jan,请告诉我,这过去的 800 年都发生了哪些让你印象很深刻的事情?

    J: OK,因为当时那两期节目是在 15 年 16 年交界的时候,我们当时是用 solidity 去写合约的,而且那个时候,你根本看不到什么文档,也没有什么资料告诉你说,以太坊它的工作原理是什么?它内部是怎样一个机制?很多事情你都是靠猜,靠摸索。当时给我的感觉特别像是在七八十年代,你手上有一台巨型计算机,而且它已经是最新的计算机了,你需要用打孔的方式进行编程的,还要进行 debug,使用起来各种不方便。尤其是,像我们的背景都是 Ruby 程序员, Ruby 本身就是一个特别高级灵活的强大的语言,这种感觉就像是突然从天堂掉到了地狱。原本你在一个很现代的语言环境里面生活了很久,突然一下被拉到 70 年代。

    D: 对,我能理解。那个时候,solidity 这个语言刚刚诞生不久还在发展的阶段,而 Ruby 在那个时候可能已经有超过 20 年的历史了,它的完备性也好,它的生态也好,还有它的工具链和社区的知识,以及在生产环境中的大量的打磨,都已经趋于一个非常完善的状态。回过头来看,两年前的 solidity 和 Ethereum 确实存在着巨大的不完整性和开发上的一些不便之处。现在两年过去了,这一点有改观吗?

    J: 我觉得这两年过去了,这一方面的改观非常有限。

    D: 非常有限?

    J: 对,可能仅仅是从打孔的时代,前进到了用汇编的时代。在以太坊上,我们很多时候还是要直接去面对 EVM 这样一个指令集的 OPCODE,包括这个级别的编程和优化。所以很多时候你会发现,用 solidity 写出来的合约,可能它的 gas 消耗很大,对吧?那怎么办?那只有直接用汇编去写,在 solidity 合约里嵌入汇编的代码。

    D: 所以说它还是算非常新,非常早期的。

    J:对,这也是当时我会想加入 Ethereum 的这个项目的原因。

    D:那你当时这样的考虑,是以开源的方式去贡献代码,还是一个学习的目的?

    J: 这里的原因有很多,学习的目的肯定是其中之一,因为只有自己动手做过,才会有最深刻的理解。

    D:当时你是以怎样的一个身份,加入 Ethereum 的这个项目的?

    J:我是开源运动的支持者,我从大学就开始用 Linux 直到现在,大概有十几年了。我一直非常热爱开源运动、开源精神,参与各种各样的开源项目。包括我在做 Ruby 程序员的时候,我自己也做过一个开源的项目,叫 Ruby-pingying,是把汉字翻译成拼音的形式,这样一个库,还有挺多人使用的。我除了自己做一些开源项目,也给 Rails 项目贡献过代码,也给其他一些项目贡献过代码,所以当我看到区块链的时候自然是非常喜欢,因为无论是 Bitcoin 还是 Ethereum ,它们都是开源项目。当时我想要加入 Ethereum 的时候,其实并没有想过要很正式的加入或者什么,我只是想着把代码弄清楚,把整个技术栈弄清楚,然后自己也能做这样一个事情。我自己是 Ruby 程序员,我就是很自然地想要用 Ruby 去撸链。Ethereum 基金会在一开始做 Ethereum 的时候,一共出了三个版本,一个是 Go-ethereum,一个是 Py-ethereum,还有一个 Cpp-ethereum,用三种不同的语言写,Ethereum 基金会这么做其实是为了增强一个分布式系统的健壮性,如果大家都遵循同样的 spec,用不同的语言去实现,那么每一个版本犯同样错误的概率是很小的,所以他们想通过这种方式来加强整个分布式系统的建设。

    D:所以你当时作为一个 Ruby 程序员,看到基金会在同时支持一个 Go 版本、一个 C 版本,还有一个 Python 版本的时候,你就义无反顾地选择为基金会贡献一个 Ruby 版本。

    J:对,因为 Ethereum 基金会非常鼓励做出不同语言的版本,但他们也没有很多人手和资金去支持,所以我自己花了很多时间去做。

    D:好的,这就切入到正题了。这也是今天请 Jan 来和我们一起探讨的主题,他当时用 Ruby 去实现了一个 Ethereum 客户端,这个事情很有意思。我想先问一下,在实现了 Ethereum 的客户端之后,你是不是就加入了 Ethereum 的 foundation,也就是以太坊基金会?

    J:没错,在我完成 Ethereum 大概百分之八九十的时候,恰好 Vitalik 在找人支持他做 Py-ethereum 的开发,就是 Python 那个版本。我们都知道,以太坊的一些最新想法,包括 Vitalik 最新的想法、研究的东西都是在 Py-ethereum 上做原型的,所以 Vitalik 其实缺少人手帮他把想法实现出来。

    D:所以,你就拿着你做的这个 ruby 版本的实现给 Vitalik 看了。

    J:对,我主要跟 Vitalik 说,我愿意来做 Py-ethereum 的开发,但我目前也还在做 Ruby-ethereum,所以希望能多给我一点时间,让我把 Ruby-ethereum 撸完,之后再来加入 Py-ethereum。Vitalik 觉得很好,没问题。所以我当时是先把 Ruby-ethereum 整个做完了,做完的意思是说当时的 Ruby-ethereum 能够通过 Ethereum 完整的测试框架。这个测试框架,其实是由大量的测试用例,去保证几乎完整(99.9%)地符合黄皮书的 spec。所以只要你通过那个测试,就可以证明说你的项目可以 cover 各种 Edge Case。

    D:所以,你最后就是拿着这样一个完整的测试用例的实现版给 Vitalik 看,说我这个 Ruby-ethereum 已经完整实现了,我现在希望能加入到社区,然后 Vitalik 怎么说的?

    J:我印象中,Vitalik 也没怎么说,但他应该觉得不错。至少是很认可我,觉得我对 Ethereum 很懂,很欢迎我加入 Py-ethereum。Vitalik 当时在做 Casper 的设计,一些早期的 POC 设计。正好我们之前也做了 Casper,所以我从 Ruby 切到 Py-ethereum 以后,就去做 Casper 了。

    D:OK,可以简单介绍一下 Casper 这个项目吗?

    J:Casper 是以太坊下一代的共识算法。我们都知道,以太坊最终的目标是 POS 的共识,proof of stake,对吧?但是由于时间问题,包括其他各种各样的问题,导致以太坊的团队难以在短时间内形成一个成熟而且安全的 POS 算法设计。所以,以太坊一开始上线的时候,用的是工作量证明(POW,Proof of work)的算法;以太坊上线之后,POS 的工作一直在持续地进行和持续地研究,Casper 就是这个 POS 算法的名字。

    D:如果我没猜错的话,你 2016 年加入 Ethereum 合作基金会的时候,就已经开始跟 Vitalik 做 Casper 的这个原型的实现了。

    J:没错。

    D:那现在这个代码,包括当时 Casper 的实现,实际上都可以在 GitHub 上查到?

    J:是的,这些都在 GitHub 上。当然 Casper 现在也经历了很多很多的变化,如果大家去翻以前的关于 Casper 的文章,再和现在的 Casper 比较,你会发现之前的其实是一个过渡版本。我们现在把这个 Casper 叫做 Hybrid Consensus(混合共识),它是 POW 和 POS 两层叠加起来的共识。而 16 年早期的Casper,是 POC-3、POC-4,其实是纯粹的 POS 共识。

    D:你有这 一段跟 Vitalik 合作做 Casper 的经历,肯定能从他身上学到一些东西,和他有很多有趣的讨论,这个过程中肯定发生了一些故事,我相信这绝对是个非常值得深聊的话题。先留个悬念,我们可以放在下一次讨论。我现在特别想问的问题是,你是唯一一个加入 Ethereum 核心开发团队的中国工程师吗?

    J:当时肯定是的。现在应该不是了,据我所知,现在应该还有其他的中国工程师在 Ethereum 这个团队里。

    D:嗯,不错不错。这也说明了,越来越多的优秀中国工程师开始为国际的顶级区块链项目贡献代码,这是好事。但当时很长一段时间内,是不是就只有你一个人?

    J:当时的确只有我一个人。在这个领域的中国人还是太少了,所以我也希望大家能够多参与开源项目,多贡献代码,多去参与这些项目,这对你们非常有帮助。至于过去 800 年发生的事情,除了我加入了以太坊,其实还有另外一个关于我自己的。那期节目之后没多久,我就从原来的公司离职,开始自己创业,成立了一家自己的区块链基础技术公司,叫 Cryptape,秘猿科技。相信很多区块链行业的朋友都听说过。现在回想起来,这也是一件非常有意思的事情,当你对区块链有所了解之后,你不仅仅能看到公有链很多不成熟的地方,你也能看到区块链并不是整个未来的全部。我们看到的那个未来除了公有链,还有很多其他的东西。

    D:比如说?

    J:比如我们现在大家都很熟悉的许可链联盟链。 但是在 16 年初的时候,我觉得大部分人对它是没有概念的。我记得当时是 Tim Swanson,他写的一篇 paper 详细地分析了各种公有链的项目、金融行业的想法、他们需要怎样的区块链。你看了之后,你会发现他分析地非常有道理。金融行业或者说我们的社会,有很多记名的资产。

    D:记名的资产?

    J:也就是说,资产所有权的确定是通过登记的方式来实现的,比如说房产。还有一大类这样的场景:金融资产、房产债券股票都是记名资产。但是,比特币给我们呈现的是另一种资产——无记名的资产(Bearertoken),相当于如果你捡到这样的资产,那它就是你的,比如你在路上掉了十块钱,被谁捡了这十块钱就是谁的。

    D:对,那这十块钱就是他的。

    J:这样的资产只需要持有就确权了,它不需要登记。这种不记名资产用公有链是挺适合的,因为公有链强调匿名性。如果你想要记名资产的话,这时候会有一个很有意思的问题:如果资产都是需要名字的,那就说明这个体系里,我们需要的不是匿名而是身份,只有拥有身份才可能进行记名。这样的话,我们是否需要为了保证匿名这个设计目标,做很多的妥协,比如我用 POW 去实现共识,做各种各样的考虑,对吧? 如果你选择放弃掉匿名这个性质,去拥抱记名的资产,拥抱 KYCF,拥抱 AML,从根本上来说目标已经发生了变化,区块链的设计思路也应该随之发生变化。这个时候我需要的不是一个开放的匿名的共识协议,而是一个封闭的记名共识协议。我觉得,联盟链和许可链的出现最直接的原因在于,金融行业发现他们现在的很多需求跟公有链、跟 cash 其实是不一样的。

    D: 很有意思,在 2016 年的时候就已经开始从这个角度去考虑公有链和联盟链的场景和关系,算是非常非常早了。

    J:是的。那个时候最主要的话题还是比特币,是我们创造的这一种点对点的支付方式,其实后面的很多东西大家还没有发现。这也是为什么我们在创立秘猿科技的时候从联盟链入手,到现在我们依然这样认为:联盟链或者说许可链,它始终是着非常重要的地位。一个是刚才说到的这种原因,因为在很多场景里面确实需要身份,这非常重要。另外一个原因是联盟链的共识范围更小,因为公有链是一个全球范围的共识,而我们希望构建的这个网络里有不同范围的共识,我们希望这个共识的范围是灵活的,并不是所有东西都要用全球范围的共识去实现。

    D:在过去“800年”的时间里,你不光是撸了一条用 Ruby 完整实现的 Ethereum,成功加入以太坊的核心开发团队,并且还创立了自己的 startup,一家提供基于联盟链的解决方案的公司——秘猿科技。哇!真的是币圈一日一年。

    J:是的。

    D:我今天想跟你聊的其实是一切的原点。2016 年的时候,是你刚刚开始研究以太坊的时候,你走出的这第一步,就是去撸一条链。我们先定一下“撸”这个词,你怎么定义“我要撸一条链”,这个“撸”是什么意思?什么叫撸?

    J:什么叫撸?我觉得程序员应该都能理解这个词,你每天晚上……这一部分是不是要剪掉?

    D:好的,我能用造轮子来?

    J:但是我觉得造轮子是个好事情。

    D:我比较疑惑,其实区块链是认知门槛极高的。用一个把它完整实现的方式,作为一个切入点去学习,这种方式非常 Hardcode,那你现在还认为它是对的方式吗?

    J:其实有两个方面,我觉得一个是因为当时那个环境,在 2016 年初的时候以太坊的资料是非常少的,甚至你可以认为当时是没有资料的。在这种情况下,你想去弄明白它是怎么工作的,那么只有一条路——看代码。但是你看代码不可能每一行都琢磨很久,一个上午最多看 500 行代码吧?可能看完就看完了,你不会理解为什么代码这么写。你只知道最后的结果是这样,但并不知道为什么。而且你不会意识到会不会有其他的写法,对吧?那么我写代码的时候,面临着 ABC 三条路。

    D:如果你没有意识到他为什么这么写,甚至你觉得你有更好的写法,然后当你做了一番努力和尝试之后,大多数情况下你会发现其实现成版本的代码是非常有道理的,并且可能是最好的或者说最折中的实现。

    J: 你说的没错。如果你不去写的话,你并不知道为什么当前的代码是有道理的。

    D: 但是在那个时候,你有没有去评估过,你要掌握 Ethereum 的一些比较内核比较底层的东西,要用 Ruby 重新实现它的工程难度或者工程量?你有没有在做这件事之前先想明白它大概是什么样的体量?毕竟只有你一个人。

    J:其实没有评估。

    D:好直接。

    J:这就是年轻的好处,我可以什么都不想,我就觉得:唉呀,我这么 NB 肯定能搞定它。

    D:那你为什么不挑一个小一点的目标,或者说简单的目标?

    J:比如说?

    D:比如 Ethereum 这条链包含了很多东西,像 EVM 本身就包含很多。那你为什么没考虑先撸一条比特币?

    J: 这个也对。主要也是因为我当时对比特币已经挺了解了。我们之前是做交易所的,也就是貔貅,这是一个开源的交易所。想要做好,你必须对各种各样的链都有一些理解,这样你才能做 deposit 和 withdraw 这两个模块,你才知道什么样的情况下币算是真的确定地充值到交易所,什么样的情况下才是取走了,对吧?这里面需要记账,也涉及到资金的管理风险,这就要求你必须对链有比较深刻的理解,才会对自己设计的这部分东西有信心。而且比特币是 09 年的项目,到 2016 年的时候已经发展很久了,它的资料相对齐全,我觉得我对比特币的理解是相当有信心的。本身比特币也是相对简单的,因为它的设计目标很窄——做点对点的现金支付, 这是一个很清晰的一个定位,它只需要 focus 在这一点上,并不复杂。

    D: 我明白了,结合当时的环境和你的想法,就是要想找一个大的目标来挑战,而比特币这个目标有点小。

    J: 没有,不敢,我其实非常喜欢比特币,非常喜欢它的设计。无论哪个方面,Satoshi 还是它的设计本身,都是传奇。

    D: 这一点毋庸置疑啦。但是,就算你一开始没有评估这个工作的工作量,没有评估实现这么一个目标需要的规划,等你真的开始做了,比方说做了一段时间之后,我相信你慢慢地就会有一个清楚轮廓,告诉你正在做的这件事情是怎样一个体量,或者是怎样一个规模,对不对?

    J: 对。其实你做了之后就会发现,这个工作量确实有点庞大,跟我们以前做的各种项目都不太一样。

    D: 有没有沮丧过,万一做不完怎么办?

    J: 有过,过程中肯定有的。因为这个项目花了我很久的时间,说实话最后也的确没有完全做完。因为最后的网络协议总是有这样或者那样的问题。在一个比较良好的网络环境中它可以工作,但是当你把它放到公网上的时候,你总是会遇到各种各样奇怪的网络状况。你也会发现其实网络上有很多奇怪的节点,它不是标准的客户端,而是改造过的客户端,总是会给你发各种奇怪的网络消息,你的节点就会因为各种奇怪的原因崩溃,当然你也就很崩溃。另外这个项目也没有 spec,对吧?你不知道正确的做法是什么。当时我主要参考的是 Py-ethereum 的实现,当你按照它实现已有的东西之后,你会发现还有很多参考实现之外的东西,你要去 handle 那些复杂的情况,你要花大量的时间去抓那些情况。

    D: 那假如说从 1 到 10 来去评估你的工作量或者说完整程度,你会给它打几分?

    J: 我觉得是 8,我主要对网络协议那部分不太满意。后来我也没有太多时间再去一个个跑节点,这很耗时间,而且你需要等。

    D: 80% 的完成量,我觉得已经非常可观了。

    J: 对,其实整个过程非常艰难,遇到了很多坑。这整个项目我估计做了有三个月,这三个月是非常高强度的开发,几乎是 7×24 小时。我印象特别深刻,那三个月还横跨了春节,你们可以看我 github 上那个小格子。

    D: 那个我知道,就是每日的 active.

    J: 对,那段时间是没有空白的,包括春节。

    D:就是说这三个月的时间,每天都有代码提交,包括春节?

    J: 包括春节,那时候是很疯狂地在做这个事情。

    D: 我想了解一下当时是一个怎样的工作状态,能不能描绘一下?你是全天候在写代码,还是说会花很多时间去研究一个具体的问题,找到方案,然后用编码实现出来。

    J: 都有,写代码是一部分,同时你也得看别人是怎么做的,还得设计从哪个点开始切入,这是一个很庞大的工程。我记得我最早做的是 RLP 的实现,RLP 是以太坊里面一个序列化的格式。我先做的是 RLP 一个非常基础的库,然后用它去序列化反序列化以太坊上所有的数据。RLP 本身是比较简单的,但是你做 RLP 的时候,你要去考虑怎么能够让上面的组建更好地使用RLP。比如我可以很方便地序列化一个 Ruby object,而不仅仅是做 Ethereum 的一个模块,很机械地去序列化 indeger、stream,导致上层写应用的时候会很麻烦。因为上层我是用 Ruby 写的,会有很多高级的抽象,结果在序列化的时候强迫我去用一些低级的抽象进行序列化反序列化。为了解决这个问题,就需要把 RLP 的库变得更复杂。但是后来回想起来,我发现 RLP 其实是最简单的,这也是我印象中比较坑的地方,除了我之前提到的网络层。

    D:就是你现在最不满意的这个。

    J:对,这个网络层确实遇到了很多问题,Ethereum 也没有很好的 spec,没有经验可以借鉴。

    D:网络层也只是其中一点,还有若干其他的?

    J: 没错。第二个我觉得比较坑的地方是,我觉得 Ruby 是有缺陷的,很多密码学的库是缺乏的。密码学的库,比如说以太坊用的是 secp256K1 这个椭圆曲线算法,还有那个 sha3,但应该是 Keccak-256 不是sha3。

    D: 对,Keccak-256。

    J: 这个地方也很坑,因为在代码里面名字都叫 sha3,sha3 是基于 keccak 的一个算法。但它和 keccak 又不太一样,实际上以太坊用的是 keccak,不是 sha3。

    D: 从实现层面上看,keccak 和sha3 其实是等同实现,从安全度和强度来看,基本是差不多的。没有任何的证据表明哪种更好,但 sha3 的版本经过了一个标准委员会认证,变成了一个语言内置的标准哈希摘要库,而不是 keccak。但是 Ethereum 好像在选择使用 keccak 的时候是比较激进的,它所在的那个历史时间点刚好是sha3成为标准库之前。Ethereum 选择了这个算法,所以就错过了后面使用正式标准库的那个版本。

    J: 对,我也觉得当时应该已经确定 sha3,因为它是一个公开的标准嘛,已经确定是走 keccak 这条路了,但当时 finallines 的标准还没有出来,而以太坊又必须往前走。所以它选了一个未来大概率会成为标准的一个算法,其实是并没有什么区别。

    D: 但是 sha3 库和 kaccak 库还是不能互换呀?

    J: 不能互换,但是算法是一样的,主要是一些参数上的区别。因为当时标准没出来,所以没办法。也不能算什么缺陷。但问题在于代码里的名字都叫 sha3,而实际上用的是 kaccak,所以我在写代码的时候很自然地觉得我应该用 sha3 的库来做,最终你会发现怎么做都不对。因为它不是 sha3,而是 keccak。

    D: 当你意识到这一点之后,你会发现那个时候的 Ruby,对于不管是标准还是非标准的密码学库的支持是非常有限的。

    J:刚才说到两个问题,一个是以太坊很坑,它其实用的是 kaccak,但所有的命名都是 sha3,你也找不到任何文章,不管 Google 上还是文档上,在任何地方你都看不到任何提示,告诉你这里其实是 keccak。这是一个很玄幻的事情。

    D: 所以当你说 sha3 的时候,我脑子里第一时间就会弹出来 keccak 这个词,因为我在这个坑里面踩了很久。

    J: 对,后来我记得你在 imtoken 的时候还是其他什么时候,来问过我这个事情。另外一个事情就是说 Ruby 本身的问题,它的这个密码学的库不够丰富。

    D: 那怎么办?

    J:最后我的解决方法有两种,我两种路都走了,一种是用 Ruby 实现,我印象中是 Ruby 实现的那个库,性能不是很好。

    D: 这我能理解。

    J: 对,性能不是很好。后来我就又用 FFI 封装了一个 C 的库。我把 Bitcoin 仓库里的 secp,它应该已经是一个单独的仓库、一个带独立的 C 库了,然后我再用 Ruby 来 FFI 给它包装一层。

    D: 对,我记得关于 Ruby 分装和基于 Ruby 如何去调用 secp256K1 的这个库的问题,其实里面有大量的坑,这个坑又来自于 Bitcoin 的这个库自己的实现过程。 如果你不是它的核心开发者,你不太会了解这些坑。我记得我在做 imtoken 的时候也在这个层面上跟你谈论过很多,但这个是后话啦。反正就感觉你做 Ethereum 的开发,从做应用的开发开始是一步一个坑,对吧?bug drive development,你在做底层实现的时候也依然是一步一个坑。

    J: 对,非常非常多的坑。我记得当时我试过很多种方案,Ruby 也能够做。我也封装过 OpenSSL 里面的那个曲线,我记得 OpenSSL 里面是有 secp 这个曲线的,最后都封装好了,又发现另外一个比较有趣的地方:Ethereum 用了 secp 的 recovery 的模式,就是把这个 pubkey 给封装到一个签名里,在 transaction 里面是不存 pubkey,只存一个签名,然后通过签名来 recover 这个 pubkey。这个事情我不知道有没有记错,反正我有这么个印象,就是说我记得 OpenSSL 里面是没有这个功能,然后你如果要……

    D: 还有一个神奇的 magic number,我记得很清楚,就是当用 recover 模式的时候,你要创建公钥的话,你要传入一个 cipher 的 number,当你 recover 的时候也要用同样的一个 number,用了这个之后你才能正常地把 publicKey 给 recover 出来。我很清楚那是 16 年的事情,因为 16 年的时候我当时也在创业,在跟何斌一起做 imtoken。我们也在这个地方踩了无数的坑,因为 imtoken 做的是钱包,跟 SECP256 这个库打了很多交道,其实也没有遇到太多的密码学的其他的大坑,整体情况还算好。但是远远没有想到,你在做 Ethereum 核心实现的时候,会有遇到这么多的问题。

    J: 因为主要是用 Ruby 在做,我觉得就这方面来讲 Python 真的比 Ruby 强很多。Python 的库非常丰富。

    D: 这个得认,有一说一。回过头来看的话,你花了这么多的时间精力在做这个事,那我现在问你个问题,就是手动地去撸一条链出来,都需要哪些知识、哪些技术储备,才有可能保证你有这个能力一步一步地把这条链给撸出来。

    J: 我觉得我撸这条链最大的感受就是,大学的时候学的课包括操作系统编译原理,这些知识好像都能用上,还有像离散数学。甚至说密码学里面全是一些数学的知识,需要算来算去。

    D: 哇!我一开始后背发凉,这个都还给老师了,怎么办?

    J: 虽说遇到了很多困难,但整个感觉太赞了,确实是觉得大学没有白学。 因为大学毕业之后,花很多时间做的那些事情,并没有多难,也没有用到很深的东西。

    D: 我知道你在做这件事之前,你已经做了很多年的互联网应用、web 应用的全栈工程师,突然转到做一个底层的事情,而且三个月就能把 Ethereum 的客户端撸出来,这个过程是不是觉得很酸爽。

    J: 肯定是很酸爽。但是我觉得其实我是做好准备的。我之前是有很多 C 和 C++ 的经验,Java 的经验我也有,我在大学的时候最喜欢的语言是 C++,我当时还做过很长一段时间的学校 BBS 上 C++ 版主,对 C++ 有很多研究。后来工作之后就去用 Java,又慢慢地转成 Ruby。既然我能用 Ruby 解决问题,我为什么不用,写起来又方便。我觉得这个其实是工作所限,工作并没有给你很多机会,让你去触及一些需要的更底层的知识、底层的语言去解决的问题,对,所以这个是……

    D: 所以你的工作经历和工作经验可能没有太多的储备或者说积累,能帮助你去做这件事情。

    J: 对,工作储备没有太多帮助。

    D: 反而大学的时候打下的基础,和自己在之前做过一些 C 和 C++ 的经验,会给你带来一些帮助。我猜可能主要的东西还是你在整个过程中自己边做边学掌握的, 而不是事先积累好的。

    J: 没错。主要密码学这方面可以给大家推荐一下,我相信现在 coursera 上面还有 Stanford 密码学的课,就叫 Cryptography。还有 Dan Boneh,密码学大神。当时也是学习这些,确实是觉得很有意思,还把课都做完了。

    D: 你的这一段经历确实非常有意思,不管你之前有没有工作经验的积累,如果你愿意去做 lowlevel,边做边学,只要足够努力并且坚持下来,这件事情依然是可以做到的。至少我觉得对我来说也是可以做到的。你从第一行代码开始撸,是直到三个月后这个代码才跑起来吗?

    J: 那倒不是,我觉得这个方面其实是得益于十几年的工作经验了。工作给你带来的其实是工程方面的专业度,就是你如何工程化的去推进和实现,这个是大学教不了你的。咱们做 Rbuy 的,就是 TDD 啊,BDD 啊,敏捷开发这些,那一套东西都玩得还挺溜的,对吧?我在做 Ruby-ethereum 的时候,也是把这些工程化的经验灵活运用。从小的东西开始不停的迭代,不是说我敲完代码三个月之后才跑几个东西。是一开始先做到一个它自己能run的某一个状态,然后再持续的把它变得越来越模块化。

    D: 是这样做。那你回头来讲这个事的话,有没有大概几个里程碑的事件?

    J: 这个,我可能记不得了。

    D: 那我就问,你是什么时候做到可以跟主网做数据同步?

    J: 跟主网做数据同步,是比较后期的事情了。因为网络是最后去做的。

    D: 一旦你能正常地跟主网做数据同步(大多数的节点只能实现跟主网去同步数据,不需要参与共识。因为能参与共识只有矿池才能做到),它就已经走到了一个相对完备的状态。那已经是相对后期的事情,我觉得做到这一点上来讲的话,应该是一个非常大的里程碑。

    J: 对,这个其实是比较后期的。前期的里程碑,首先肯定是网络层 mock 掉,就是内存里面的几个进程,或者说几个线程相互之间能通讯就行,模拟几个节点把网络上给 mock 掉,比如之前提到的 RLP,最早的里程碑可能是你输入一个 transaction,看它这个序列化之后的格式能不能对上,然后再后面就是去实现这个数据结构,实现这个 block 实现 transaction。然后这些数据结构系列化之后,首先是 RLP 的这个格式的数据都对的上,然后第二就是签名,交易的签名,这个牵出来的签名都没问题,然后也可以验签也可以 recover。 这个 pubkey,然后各种各样的事情都能做。再然后我觉得应该就是 EVM,就是说你怎么去处理这些交易?怎么样去 process 一个 log,怎么样去 process 是一个 transaction,然后这里面必然会涉及到你要去实现 EVM,然后实现 EVM 就是说必须得力赞一下这个以太坊这个测试框架,以太坊有一个仓库叫 tests。就在 ethereum 这个 organization 下面有个仓库叫 tests,它里面是包含了可能有至少是万这个数量级的吧,万还是几十万的fixtures。就是测试的用例。ethereum tests 也是一个就是说跟语言无关的一个测试库,它测试用例都是用 json 写的,然后会详细的说明就是输入是什么?输出是什么?然后交易是什么?所以如果你去实现 EVM 的时候,你就是说把输入丢给这个 EVM,把当前的这个 world state 丢给 EVM,然后对比最后产生的新的 world state,然后你就可以知道你的这个实现是否能够通过这个测试或者说是通不过这个测试。这套东西是非常有帮助的,对你实现 EVM。到这个阶段的时候,其实你就是不停的去死磕那些测试一个一个的过,我可能改一点东西。过了一百个测试,再改一点,过了 1000 个,再改一点过了 1 万个,再改一点,只能过 5000 个了。

    那很有意思,这个 progragh 的话通过测试反馈是有可以感觉到的,它是个进度条,到最后的话把所有的测试全部都能过去,我们 EVM 就是 fully compatible.我记得就是百分之百通过的时候我是非常非常兴奋,然后还发了条 twitter。 然后我另外一个很兴奋的是说我的 Ruby-EVM 的实现比 Py-ethereum 的 EVM 快很多。

    D: 为什么?是因为你做了很多的优化吗?

    J: 为什么?我觉得跟程序,跟代码的写法有一些关系。肯定有优化,有各种各样的原因。

    D: 所以性能好不好,主要看架构,而不是看语言。

    J: 对,架构非常重要。

    D: 架构非常重要。

    J: 其实语言程度上 Ruby 可能还慢一点。

    D: 那共识协议这一块呢?当时在做的时候有没有遇到什么问题,或者有什么坑在里面?

    J: 共识协议还好,我猜应该是在 EVM 之后去实现的,这个是 POW 那部分,那是一个单独的仓库,叫 Ethash,那个算法叫 Dagger Hashimoto 算法,然后我记得我是先用 Ruby 实现一遍,生成 DAG,一个大的文件,再用各种各样的方法去生成,去找到 nonce,然后用 Ruby 实现了一遍,发现 Ruby 还挺慢的,感觉我最后做出来的这个东西可能不太实用,所以后来就把 Ruby 搁到一边了。后来又去封装了一下,C++ 里面实现的 Ethash 算法,用 Ruby 封装之后我发现这个效率还可以。所以当时确实是奔着希望做成一个实际可用的客户端去的。 最后在 Ruby-ethereum 里面,其实这两个实现都支持,为了这个实现我还把接口抽象了,你可以指定用 Ruby 的 ethash,还是要用 cpp 的 Ethash。

    D: 也就是说,你选择了两个实现都支持的方式,一个出于研究目的,一个充分考量生产环境?

    J: 对,不只是研究目的,我是真的想让它跑起来。

    D: OK,因为在一些部署环境和生态环境的时候,最少的对于 C 啊或者说是对于其他类型的库,外部依赖最容易方便你部署,那整个过程听起来从头到尾都是 Hardcode,是非常 hard 的模式。

    J: 对,其实遇到挺多问题的。

    D: 让你觉得最难的就是网络层。

    J: 对,这是一个很有意思的现象,在整个分布式系统中这个领域都是成立的,网络会带给你很多不确定的惊喜。因为我们之前做的都不是分布式系统,它们都是一个受控网络环境内的系统,你其实是在跟大概率确定的事情打交道。当你在一个分布式系统中,尤其是在公有链这样一个开放的环境里,你是在跟不确定的事情打交道,这是一个非常有意思的转变。很多以前做互联网服务的开发者,当他转到区块链的时候,很多人的 Mindset 可能会有一段时间转不过来,因为你已经习惯了,习惯了假设大家都是好人,但其实我们现在的编程环境里大家都是坏人,你必须适应公有链的这个环境。这里不仅仅有 51% 攻击那种高成本的事情,在网络层在你们看不到的地方更是暗流涌动,有各种奇怪的事情。想象一下,在 16 年还是很早期的时候已经是这样,那现在更是这样了。 所以你能看到各种各样黑客事件的发生,这个绝对不是偶然。不是偶然。不是偶然。

    D: 经历这么一个 Hardcode 模式,你在整个实现过程中会不会有 depletion、压力甚至会伴随着沮丧。然后少有的完成了里程碑以后,让自己非常非常开心。

    J: 没有沮丧,这个我记得很清楚,整个过程我都很兴奋。

    D: 整个都很兴奋?

    J: 对,全程都是很兴奋的,否则我也会觉得没有动力,否则我也不会大过年的时候非得去撸代码。这个事情我印象特别深刻,就是那种特别值得的感觉,你知道吗?觉得自己的大学四年没白活,终于找到有意义的事情。

    D: 为了给大学四年一个交代,这也太……

    J: 我觉得这跟个人性格有关吧。我觉得我做很多事情没有太多特别的目的,可能人生有意义的地方就是在于你做的那些没有什么目的的事情。它常常会带给你很多惊喜。这是我自己的一个看法。

    D: 嗯,收获肯定是蛮多的。

    J: 收获很多。

    D: 那我们讲讲,你现在能深刻体会到的做这样一个事情最大的收获和最大的改变。

    J: 我觉得最大的收获是对创业的帮助吧。

    D: 对创业的帮助?

    J: 对,这个过程让我看到了一个未来的世界。首先你去撸这个链的时候,你会做大量的研究,不仅仅是撸代码,你会看很多很多的东西,包括你会去思考很多事情的本质,也会去跟别人交流。在这个过程中我也很幸运地认识了 Vitalik,很幸运地碰到了以太坊那个团队的人,和他们交流,了解他们的想法,他们怎么看待未来。这一点对我的帮助非常非常大,也让我非常开心。

    D: 认知升级了。

    J: 前面说大学没白学,因为你会看到一个技术占有非常重要地位的未来。通过技术、通过科技能够改变很多事情,能够实现很多事情,你会对此很有信心,你也会去很坚定地往那个方向去走。

    D: 我现在决定把这一期的 podcast 放出去之后,它的标题就叫作:我是如何撸出一条以太坊的区块链的。

    J: 我是如何撸的?

    D: 对,“我是如何撸的”,副标题是“我大学真没白学”。整个这个过程你是在一种很微观的层面上,在非常 detail 的 lowlevel 上跟代码打交道,跟协议打交道,把整个这一部分走了一遍。最后跑通之后,你告诉我,你的结论是你看到了一个更好的或者说更理想的技术的世界。这让我觉得挺不可思议的,非常有意思。

    J: 因为区块链真的是一个非常大的概念,里面涵盖的学科和知识很多。就计算机方面,分布式系统、密码学、P2P 网络,编译原理、编译器,各种各样的东西你都能涉及到,还有经济学博弈论等等。你研究得越多,你会发现其实它研究的是我们的整个社会,研究我们的人类社会系统是怎么运作的,这把你的视野变得非常开阔。还告诉你,这个世界上有这么多很好玩的东西,而且他们在某种程度上是相通的,比如计算机系统架构方面的设计,你可以对应这个人类社会的系统的设计,它们之间有哪些是相同的,有哪些是不同的。这样一整套东西混在一起,你会发现:哇,还有这么多有意思的事情。还有另外一点,当你能够看清楚那个未来、了解底层的很多细节和现状的时候,你就能够明白,未来和现在之间的 gap 有多大?未来非常美好,但它离我们真的挺远的,中间有很多很多事情要去做,那么这个未来会是你一个很坚定的目标,它是你要去实现的那个东西,你必须得想出一条可行的路径出来,你必须一步一步走过去,甚至中间会有一百步一千步一万步。我们现在离那个未来还很远。这个对创业的帮助是非常大的,我就会很实际地去找那条路径。

    D:作为一个曾经的创业者,我对这一点感受非常深刻。尤其是对技术型创业,在一个有很多不确定性的环境下,如果你是认真地扎进去,探索得很深的时候,对底层的理解很深刻的时候,你再浮出水面,再看一下未来,你对之前走过的道路感触会尤其深刻,这个很难去解释。我们做技术创业的时候,这种情况真的是一而再再而三地发生。

    J: 其实这个也决定了,为什么我们会选择从许可链到公有链这样一条路径。当我去参与 Ethereum 的开发,参与各个层面的开发之后,会很容易认识到:许可链,从技术上来说确实容易很多。毕竟许可链是在一个许可的环境里面,它的不确定性没有那么大。那么很多事情做起来就方便很多,包括架构的设计、细节的设计方案。但是公有链其实非常难,它各个方面涉及的东西远远超过很多人的想象。在你准备不足的情况下,贸然去做这样一个事情,是很难、风险很高的。所以,我们会选择一个相对简单的点、一个场景去切入,通过这样一个事情去培养我们的工程团队,加深我们对区块链的理解。等准备充分之后,再去做公有链,这是一个更加可行的路径。

    D: 我非常认同这一点。你通过撸链获得的感触,影响了很多人,包括我们自己的工程师,和那些希望在区块链这个领域中做点事情的广大的优秀工程师,鼓励他们试着从撸链的角度去学习和认知区块链这样一个崭新的事物,我觉得这点非常好。如果,让你重新做一遍的话,基于你现在的这个工作,还有什么地方你觉得可以改进和提升?

    J: 我觉得网络肯定是一个,再说我满意的部分,我对 EVM 这个部分是挺满意,因为有很多测试。

    D: 还有很好的性能。

    J: 对,还有很好的性能,我觉得挺开心的。如果说要改进的地方,让我再做一遍的话,我希望架构上有一些新的东西放进去,怎么说呢?因为后来我发现一个问题,以太坊的哲学其实是通过硬分叉来升级。那么硬分叉以太坊里面,硬分叉这个模式基本的一个设计模式是什么?是说我指定一个区块号。在这个区块号之前,我是怎么样一个处理逻辑,在这个区块号之后区块高度之后是怎么样一个处理逻辑,代码里面有不少if...else 这样硬编码的东西,这个是我当时很受不了的,但是又没有想到很好的方法就冲上去了。如果我再做一遍 Ruby-ethereum,我一定会想办法把它处理掉,避免这些 if...else,用一个比较优雅的方式去处理。

    D: 我能明白。其实 ethereum 每一次大的版本升级,从 Frontier 到 Homestead,再从 Homestead 走到下一个阶段的 Serenity 都是有这样的 if...else,在那个区划版本号之后的话,完全转那一套新的代码,但是在高度没有到那一块或者投诉的时候,它要去执行老的代码,就说老的代码、新代码向两份拷贝通过 if...else 把它给去隔开,确实是一个在看代码的过程中非常非常觉得有点不舒服的地方。我明白你的意思。

    J: 所以我们现在做底层也会反过来想,就是说如果我们以后要硬分叉,或者如果我们要有一些其他不同的一些 Carments 方面的设计的话,底层需要去怎么样做一些比较漂亮的支持,就是说不是每次 if...else 这种方式,然后可以用一个比较优雅的方式来处理这些问题。其实现在也会反过来这样想。

    D: 其实有一点我是知道的,但是可能很多听众不知道,可能听到现在很多听众只是觉得你用 Ruby 把以太坊的客户端重新撸了一遍,但其实你应该说是做链这件事的话,你撸了不止一遍,对不对?到底撸过几遍?

    J: 对,Ruby 是一遍,然后最后确实还有做过一些其他的事情,但至少说在python 那边,就是加 入ethereum 之后,用 python 其实就写很多,包括写 Casper 很多东西。就三四遍吧!

    D: 三四遍。Ruby、Python,还有秘猿的CITA这个产品的技术架构主要是 Rust 的语言,对吧?然后也就相当于,其实已经是不管是 Ruby、Python 都做一遍,其实你是最有资格的去评判不同的语言在做这件事情或者一些差别,为什么没有 Go?

    J: 我说一下,就是说我们选择这种语言的考虑吧,其实 Python 和 Ruby 非常好理解。Ruby 是因为我自己的背景,然后觉得需要有一种新的一个实现,然后Python 其实很好理解,就是 Ruby 和 Python 其实都一样,就是说做原型很方便,然后反正功能有了,功能可以很快的实现出来。这个就是它最大的一个目的,就是用 Ruby 和 Python 最大的目的,然后用 Rust 没有用 Go。我觉得有几个方面的原因,就是说可能 Go 是一种有 GC 的语言,我们希望追求的是最极致的一个性质。这个 GC 和最极致的性能是有冲突的。我希望的是不仅仅在架构上,我们可以去实现高性能。我们在这个架构的每个具体实现的细节里面,我们也去追求最高的性能,我们想做的是一个最极致的东西,就是世界第一。我们做 CITA 的时候,目标就是世界第一。然后我们也觉得我们能做到这一点。然后我觉得现在 CITA 确实是性能,我没有觉得有谁性能比它好。我觉得其实这方面是有影响。然后另外一个原因是说,Rust 是一种比较现代的,吸收了很多现在语言特性的语言,我非常喜欢它的设计,就是因为我在做 Ruby 程序员的时候,其实花了很多时间去研究 haskell。非常喜欢 haskell,haskell 是一种非常数学非常纯粹的一种语言,它是 funtional,然后追求 pure funtional program。haskell 的这个哲学就是说 avoid success at all costs,它是一个很学术派的语言,我不想成功,我就是要美,我就是要漂亮,这就是我的哲学,所以说haskell就是它的美是让你震撼的那种,就说哇你太美了。但是你要我用到工程里面,我会觉得好像有点过了,对吧?因为这不是你追求的东西,但是 rust 出现就让你觉得这个东西就是我想要。就是我把 haskell 还有 ocaml,就是说是近 10 年 20 年这个类型系统这方面的进展,研究成果都吸收过来,然后我又去追求 C++ 的这种性能,我又去结合一些 funtional 的东西,这个我觉得,哇,完全就是你怎么知道我是怎么想的,就这种感觉,我想的就是这个东西,你把我想的东西全都做进去了,这东西太牛逼了。当你看到就是说你在 Rust 里面是可以写非常高阶的一些语法,然后你看到它看起来像 Ruby。通过编译器的一些技巧,把它编译成一种非常高性能的汇编代码的时候,你会觉得这个东西太 nb 了。所以我觉得这是为什么 Ruby 社区有很多人转向 Rust,包括我们认识的 Yehuda,超级大神,直接去搞 Rust。

    D: 反正我自己也非常非常喜欢,然后最近也把自己就是,我说这话有点政治不正确,因为我本人还是 Ruby 社区的一个管理员,这一段我不能放。

    J: 反正我是觉得我肯定是个 Rust 吹了,但是我觉得 Rust 和 Ruby 是这个非常有血缘关系的语言。为什么呢?

    D: 因为他们都姓 R。

    J: 说对了一半:因为他们前两个字母是都是 RU(笑)。是不是说对了一半。然后这是一个方面吧,就是我觉得 rust 它非常好。然后第三个方面是我觉得它非常有潜力,这个有潜力是几个方面,首先 rust 本身是有一个社区推动的一个语言,这个事情本身和区块链是非常契合的。区块链的项目其实也是社区推动,然后通过比如说 EIP 啊 BIP 啊这些提案去推动,Rust 其实也是 Mozilla 基金会支持的一个项目。然后它有一个 Rust 社区,然后有在 Rust 里面叫 rust-RFC 吧,也是各种提案去推动这个语言的演化,通过社区的力量去推动,对这个我非常喜欢,我觉得就是说开源项目还有就是社区的力量是非常非常强大的。虽然说它一开始可能给你的感觉很弱小,就是它的这个产品给人感觉很弱小,但是它的生命力是非常旺盛。它是个开放的语言,它有一个开放的社区,它的整个的这个 Rust 背后的这套工程上的东西,流程上的东西,我觉得做得非常好。

    D: 你们在秘猿通过用 rust 重新实现了这一套叫做 CITA 的这一套联盟链的blockchain solution,这一整套的代码和这个产品的话,在 GitHub 上都是开源的都非常好,那如果要是在这一点感兴趣的听众的话,也可以线下的去 GitHub 上做学习和研究,我觉得这个非常好。我们以前谈了这么多,从你们当时做链的这一段经历和收获,从 Ruby 到 Python,再到 Rust,然后三遍到四遍做链,哇,你真是一个做链方面的专业户,anyway,这是一个褒义词,我们今天这个 podcast 的话也要接近尾声了,其实我还有最后一个问题,通过自己手撸一条链出来,然后让它能 work 能 function,去跨界的一个非常好的方式。那么如果我们都相信这一点的话,能不能给一些后面如果还想通过这种方式去学习的这些人和一些工程师们一些建议和一些意见?

    J: 我觉得其实现在来说,撸一个链其实确实是比较 Hardcode 过程,就是说时间成本是比较高的。但是我觉得学习的效果是最好的。这个我觉得看在于每个人自己的取舍,所以我前面也说了,你如果要是撸一个完整的一个实现的话,我觉得现在可能还是会需要当初那么多时间。因为一个方面来说,你能获得的资料更多,能参考的东西更多,但是另外一个方面来说,以太坊和不管什么链,它其实都是在一直发展的,就是说我如果那个时候是在两年前,它后面又比如说硬分叉,又加进很多东西,又有各种各样的东西,然后网络上有各种各样的进化,这个网络协议层,当时的比如说什么什么版本,现在跳到什么什么版本。

    D: 它的黄皮书也是在更新。

    J: 对,其实你要做的事情是越来越多的,那么我觉得工作量可能不会差太多,可能不会差太多。所以这个还是比较花时间的。那么另外一个简单一点的事情可能就是说,你可以撸一个简单版本的链,就是它不一定是说要走向生产要完全兼容的,而是说大致的一个区块链的概念,它是一个原型,对吧?它麻雀虽小五脏俱全的那种感觉的原型,就是有挖矿,有交易,有 block,有几个节点可以连在一起,然后连起来之后就可以不停地挖矿出块,然后各种各样的东西,做到这一步也是很有意义。然后还有一点就是说你不一定要做一个完整的东西,但是你可以在里面选一小块出来,写一写。我觉得这种也是挺有意义的一种练习吧,比如说 RLP,或者说我要实现这个 merkeltree,或者说我去实现 Local Patricia-Tree,就需要去做这种小的点,其实你弄明白之后,也是很有意义的。我能想到的刚才讲的还有就比如说钱包里面的这个私钥的加密。

    D: 那个 ethereum 的这个 keystore V3 这个协议加密。

    J: 有很多小的点,就有点像小的编程挑战那样。

    D: 对,而且其实这几个点的话,如果我要是猜的没错的话,大概也就是四个点、五个点,不超过六个点,都玩一圈的话,整个这条链的底层的知识框架的概念就打通了, 最后是能连起来。

    J: 对,最后也起来了。

    D: 非常好,非常好,非常感谢 Jan 今天跟我们分享了这么多有趣的故事和经历。太有意思了。非常开心能跟大家分享,我们T eahour有一个传统环节,每次邀请的嘉宾到最后的环节都要有一个叫 pick 环节,让嘉宾给大家带来一个他推荐的一个什么东西,一本书,一部电影,一段音乐,或者说一个他觉得好玩的东西,带给大家作为一个临别的一个小小的礼物送给大家,那Jan今天你会给大家带来一个怎样的 pick?

    J: 我就推荐一下。一个特别好的最好的一个资料吧,就是说大家有兴趣的话可以去看一看 Nervos 的白皮书。那应该严格来说应该是 Nervos-CKB 的白皮书,是我们现在在做的一个公有链的项目。CKB 的白皮书其实谈到了很多我对PDC 还有 ethereum 的看法,然后也有一些就是说区块链设计上的思考,架构上的思考,NervosCKB 其实就是凝结了我在这两年对区块链思考想出来的一个设计,然后包括你们也提到一些有意思的想法,比如说 Common Knowledge Base 这样一个东西。

    D: 对,我知道这是一个非常非常厉害的东西。

    J: 我觉得这个我就不多说了,就推荐大家,有兴趣可以看一下。

    D: 好,那我们要在这卖个关子留一个悬念,因为在我的规划当中的话,未来都会给大家录制一到两期关于这个项目的一些内容,我相信也会非常精彩, 非常有趣。那轮到我了,那今天我给大家带来的 pick 其实是一个小东西,我有点后知后觉,就是我原来没有意识到降噪耳机这个东西能给我的生活带来如此大的一个改善和提升。因为在出差的一个间隙的时候,突然有一天,我在机场,在逛一个像数码玩具的一个商店,然后突然看到有卖 Bose 的 QC30 的一个降噪耳机,我买了这个耳机之后,在我的出行和我的生活中突然发现,我可以随时随地找到一个让我的心灵马上达到 harmony 的那种境界的一种道具。所以我突然就有一种发自内心的想要去推荐这么一款产品,虽然我知道 Jan 一定会嘲笑我,因为当时我说 Jan,你看这个耳机非常非常赞,然后 Jan 立马来了一句,哇,这个做工实在是太矬了太丑了,但是它真的很好用 ,真的很容易让你很快的达到一种安静和内心的平衡,所以我要强烈的推荐 Bose 的 QC30 这款蓝牙无线降噪耳机,这是我今天的 pick,你要是有反对意见可以保留。好,谢谢大家,再一次感谢大家来给我们 Teahour 节目,下期再见,谢谢大家!

    相关文章

      网友评论

          本文标题:Teahour.fm #92 怎么撸一条链

          本文链接:https://www.haomeiwen.com/subject/dnoypftx.html