科普 | Vitalik: 25分钟认识以太坊(上)

区块百科 blockchain 5个月前 (01-18) 86次浏览 1个评论 扫描二维码

编者按:以下为 Vitalik Buterin 在 Ethereum Devcon3 上的演讲《Ethereum in 25 minutes, vision 2017》的上半部分。以下中文皆直接从视频中听写并译出,如有错失,请不吝赐教。

好的,那么,这个演讲希望成为一种尽可能简洁的介绍,与此同时,能够涵盖重要的部分,比如,最基本的,从技术角度来说以太坊(Ethereum)协议在实际上看起来是什么样的。

那么,我将直接切入,下沉到以太坊之所是,以背景,亦即以太坊存在的理由,来开始基础介绍。回到我在 2013 年末写出初始白皮书的时候,公众、区块链技术、尤其是那些致力于使区块链技术超越仅仅是比特币(Bitcoin)货币的人们,已经表现出大量的兴趣。现在,人们正致力于开发以太坊应用、发行资产到区块链上、众筹、域名注册、域名币(Namecoin)这样的项目、产权登记、投机、预测市场、物联网(loT)应用、医疗应用。区块链上有许多的应用,超越了像“我有 50 个比特币,我发 20 个比特币给你,然后你就有了 20 个比特币”这样。

问题在于,那时候大多数存在的区块链都是像这样设计的。我的意思是,这种豆豆计算器有何意义呢?它可以做到这件事,它也可以把这件事做得很棒,但这也是它唯一能做到的事。诚然,如果你有一台超级棒的 TI-80(译者注:德州仪器发行的一款学生用科学计算器)或是别的,你或许能够通过某种方式在上面编写一个视频游戏,但没有人会真的想这么做。普遍地来说,它最后变成了能用来做一件事情的一个工具。

但是,如果我们想让它做不止一件事情呢?当然,你可以为 5 个不同的目的买 5 种不同的设备,但这很快就会(回到原点)。下一步是,人们开始创造像瑞士军刀一样的协议。你可能会想象,一群人走进一个房间,他们头脑风暴了一个钟,然后他们写出了 25 个不同的区块链应用,然后,他们达成了 25 种不同的交易类型。交易类型一,创建一个共筹;交易类型二,参与一个众筹;交易类型三,创建一个保险合约;交易类型四,开一个双人房;交易类型五,注册一个域名;等等,乃至他们可以想到的每一种应用。这就是我使用“瑞士军刀”的含义。

但问题又在于,如果你有了一个瑞士军刀协议,你拥有这个在一个房间里孵化出 25 种不同项目的协议,他们创建这一协议,放出这个协议,一个星期以后,一个芬兰的小伙子写出了第 26 个区块链应用,然后,你必须更改整个协议。

所以,为什么不创建一个像这个一样的协议?(屏幕上是一台 Windows Phone,屏幕下方有一行字:特别感谢微软(Microsoft)赞助本次大会。听众大笑)

为什么不做一个基本上像一台智能手机一样的区块链协议,来取代那些仅支持很少一些应用、你能做的也仅仅是这些应用的协议?因此,我们做了一个区块链协议,它支持编程语言,因此也给了你技能来创建应用。一个应用是什么呢?其实,任何人都可以写一些代码,打包这些代码并上传它,然后你就有一个 app!如果任何其他人想使用你的 app,他们下载这个 app,然后它就会出现在他们的手机上,他们可以使用它,可以运行它。对,就是这样,基本上这就是为什么一个手机可以打电话、浏览网页、听音乐、用文字与其他人会话、玩游戏;只是因为我们将数以千计的东西集成到一个设备上。这就是通用计算的力量。这也是我想带给区块链世界的一种精神。

概念

先来谈谈概念,对吧?首先,以太坊是一个区块链!耶~!(听众笑)

加法

但是,你知道,我们还增加了一些东西。首先,以太坊拥有一个内置的通用编程语言,允许你在其中编写非常多的应用。

在一个目的只是支持货币转移的区块链上,那里将只有一种类型的账户。这种类型的账户将成为这样的一个账户:它被某些用户所控制、它将保存货币。你将能够从一个账户发送这些货币到另一个。但在以太坊上我们有两种类型的账户。
1. 第一种类型的账户是被用户控制的,所以你拥有一个加密私钥,你可以用它来代表你的地址、为执行操作的信息打上电子签名。这些操作被称为交易,它们可以被广播到整个网络;如果它们被包含到了一个区块中,这些操作就会生效。
2. 另一种类型的账户在根本上由一段运行在区块链自身的代码来控制。所以,你可以拥有一个被一个计算机程序控制的账户,这个计算机程序有一些规则,它可能说的是:如果 A 发生了,那就发一些币给 X;如果 B 发生了,那就发一些币给 Y;如果 C 发生了,就仅仅保持现状。如果你发送一些币给这个账户,这个账户的代码就仅仅是这样一个东西:它在那时候起有能力将这些币转移到别的地方去。

从字面上来讲,这些就是被一个计算机程序直接控制的电子资产。当然,这些合约可以被用来做更多事情,不止于仅仅控制电子资产。它们可以被用来表示区块链应用里面任意复杂的商业逻辑。这也包括了像 ENS,以太坊域名系统(Ethereum Name System)这样的东西,它可以被用来跟踪一些区块链上的正在投票的方案;它也可以被用来跟踪链上多种多样的发行人背书资产,还有很多不同的用例。基本上,任何人都可以通过定义一个合约来创建一个应用或者任何规则。

DNS, the Hello World of Ethereum

DNS,这个以太坊的 Hello World,就是其中一个你可以写出来,并且客观来说仍然很有用的、最简单的应用。关键在这儿,这是一段代码,我的意思是,你也许已经注意到了,从去年开始代码已经发生了某种程度的变化。根本上来说,这是因为在去年,你的代码是用 Serpent 写的,而现在我们有了优于 Serpent 的 Viper,待会可能还会有人来谈这个话题。所以,你有两种函数,而这两种函数代表了通过合约你可以做的事情。

domains: {owner: address, ip: num}[bytes32]

def register(addr: bytes32):
if not self.domains[addr].owner:
self.domains[addr].owner = msg.sender

def set_ip(addr: bytes32, ip: num):
if self.domains[addr].owner == msg.sender:
self.domains[addr].ip = ip

(PPT 上呈现的代码)

首先,你有了一个关于该合约实际上储存的东西的描述。这个合约储存了关于一个域(domain)的映射,谁是这个域的所有者,这个域支持指向的 IP 地址是什么。然后,有一个函数叫做“注册”(register),如果一个域还没有一个所有者,所有者会被给这个域发送信息的人,无论是谁,所确定。所以无论是谁发送了交易,这个函数就被激活了。然后你还有另一个“设定 IP”函数,激活这个函数也是非常简单的,它仅仅只是检查一下当你试图为一个域设置 IP 地址的时候你是否拥有它,如果是,它就会把 IP 地址设置在任何你想要的地方。

所以,在一个合约中,所有信息都储存在哪里呢?在一个简单的区块链上,你可以将区块链记录的状态(state)认为是仅仅对账户的余额作了一个简单的映射。地址 12345 拥有 70 个币,地址 B7884 拥有 2 万个币,诸如此类。以太坊的状态要略微丰富一点。但也仍然是对内在于账户的东西的一个映射,但这些内在于该账户的信息可以是复杂很多的。

首先,你有账户余额,就是这个账户有多少以太币(ether)。你也有Nonce,是一个用于重播攻击保护(replay protection)的对冲措施。你有合约的代码,如果该账户是一个合约的话。你也有合约库(contract storage),它就是一种小型的数据库,任何以太坊上的合约都可以使用。在这个案例中,从域到谁拥有这个域、它的 IP 地址是什么的映射,将在实际上被保存在合约库里。区块链上的历史就是发生过的事情,所以你拥有交易记录。在以太坊上,你拥有这个叫做“收据(receipt)”的概念。就现在而言,所有全节点都储存状态,一些全节点储存历史,而不存储历史的全节点也是有可能存在的。

所以,那就是我们到达的地方。每一个账户对象都包括 4 段数据。我会打开它大概 5 秒钟,因为每个人都想拍下它。5,4,3,2,1,下一张。

state

  • State consists of key value mapping addressed to account objects
  • Every account objest contains 4 pieces of data:
    • Nonce
    • Balance
    • Code hash(code = empty string for private key-controlled accounts )
    • Storage trie root

(当时的 PPT 内容)

代码运行

每一笔交易都指定了一个 TO 地址,每一笔交易都明确了该交易的目的地或者说目标是什么。如果交易的目标只是一个普通账户,或者在任何意义上是一个真实的人;以及,如果交易包含了以太币,那么该交易就意味着从一个账户到另一个账户的转账。然而,如果交易的目标包含代码,也就是说如果交易的目标是一个合约,则目标地址的代码就会运行。代码能够做一系列的事情。因此合约也有能力发送以太币给另一个合约。它有能力读取和写入一个合约内部的库。所以,如果你回顾这个例子(译者注:上述 domain 例子),一个对注册函数(register function)的调用将变成一个交易,而这一交易将,你懂的,导致前述域的所有者被确定,以及在库中写入该信息,以及,(如果有需要)该声明从另一个库中读取信息。综上,它可以读取也可以写入库,它甚至可以调用另一个合约。这也被称为一个内部交易:合约可以与其它合约通信,其方式与外部用户与合约通信的方式完全一致。每一个区块链上的全节点都运行每一个交易并存储全部状态。我把它加粗了,因为这是重要的。

Gas

普遍来说,有一个东西被称为“停机问题”(Halting Problem),它的基本意思是,你没有办法真正从原则上断定一个程序会不会永远跑个没完。分辨该程序会不会在一系列步骤之后结束,或者将一直运行下去,是一个不管用此种还是彼种方式都不可能从数学上得到证明的东西。所以,我们用的解决方案是这样一个机制:我们根据交易消耗的运算步骤对交易收费,而我们衡量运算步骤的单位就被叫做 Gas。

Gas 不是一种货币,对吧?Gas 不是一种你可以转载或是持有的东西。Gas 只是一个计量单位。它的意思是,这个计算,如果它消耗了 3 万单位的 gas,那么它意味着该协议说为运行这一计算花费了 3 万单位的努力。同样也有特殊的 gas 费用用于占用库的操作,(因为)交易会占据空间。而以太坊网络招致的任何类型的成本都可以换算为某种类型的 Gas 支出。所以,每一笔交易都必须指定 Gas 限制,该交易必须明确它可以消耗的 gas 的最大数量;然后,当代码运行的时候,运行开始使用 Gas;如果代码运行在 Gas 被耗尽之前停止了,那么万事大吉;但如果代码运行到达了一个所有 Gas 都被花费掉的点上,那么该交易会回复原状,从空气中消失,但交易的发送者仍然必须支付一笔费用。

所以,以太坊上的 Gas 限制对应于比特币上区块大小限制,而设定它的方式也是非常简单的——基本上由矿工们投票来决定。现在,Gas 上限是 6.7 百万单位。如果我们到达了上限并且有必要提高它,矿工们可以投票。这是非常简单的。

交易

  • 以太坊上的交易有 7 个部分:
    交易 nonce,基本上就是一种反交易重播措施,如果你正在发送交易,让我们假设如果我发送了 10 个以太币给 Bob,它(nonce)防止 Bob 提取这一交易并在区块链上包含它 100 次,那样的话我就发送 1000 个了以太币给 Bob。每一个交易都最多只能被包含一次。
  • Gas 价格,就是你为你的交易所占用每一单位的 gas 付出的以太币数量,这就是给予矿工的交易费用。
  • Startgas,交易可以使用的 gas 最大数量限制,也就是该交易可以消耗的计算资源的最大数量。
  • To,就是目标。
  • 价值(Value),交易发送的以太币数量。
  • 数据,就是说,如果你的交易有一个合约目标,那么该合约就可以读取数据。所以,接着就是一种做比如明确函数争议这样的事情的方式。
  • V,R,S,就是一个 ECDSA 签名,这是解密的需要。把 V 在这儿因为你需要额外的一个部分以便从签名中还原公钥。所以,我们做的是公钥恢复,而非任何类型的验证,我们说那是比特币做事情的方式。

Log

Log 是一种只可添加、而不可被合约所读取的库的形式。关于 Log 的重点是,让我们假设,现在有一个事件在合约运行过程中发生了,我们希望让人们搜索这些事件以及侦测这些已经发生的事件变得非常容易。所以一个 Log 可以长达 4 个“topic”(32 bytes),并且,这里有一个布隆过滤器(Bloom Fliter)所以你可以非常容易地搜寻 topic。同时这也允许你存储任意数量的数据。这些 Log 被放进了一棵默克尔树,它允许非常高效的通往 Log 的轻客户端通道。如果你有一个轻客户端,你可以通过 Log 来搜索,你可以拿 topic 当作关键词,这也允许你非常容易地搜索到合约已经创建的一种特定类型的事件。这对于分散化应用(Dapp)编程来说是非常有用的。

以太坊虚拟机(EVM)

一开始,你有一个堆栈,数字可以被加入(push)栈以及从栈中输出(pop)。你拥有内存,内存就是一个虚拟机可以进入的临时数据组。所以内存只能在我短暂地处于运行环境中的时候才能存在,一旦运行结束,内存也就停止存在了。(stortage),就像合约数据库一样,是永久的存储空间。环境变量,以太坊虚拟机上的合约可以获得像是区块数量或是时间戳这样的东西。而且你还有Log次级调用(sub-calling)所以合约有能力通过发送我们说的“内部交易”来调用其他合约。

大多数时候,你并不准备直接写作 EVM 代码,因为要直接写 EVM 代码是非常琐碎的。相反,你将用高级语言写作,然后编译成 EVM 代码。这里有一些这样的高级语言,你可以用 Viper,Solidity,LLL,还有 Bamboo。再一次地你可能注意到,Serpent 不再被放在这个列表中了,如果你还在用 Serpent,我建议你转换到 Viper。

ABI

这就是函数调用得到被编译或说其代码被写到交易数据中的方式。所以如果你正在调用一个合约,那么实际上发生的事情就是它做了一个函数调用,以及,额,抱歉,如果你调用了一个函数,那么实际上发生的事情就是它创建了一个交易,并且该交易包含了在这一公式中被指定的数据。所以一开始有 4byte 是函数 ID,然后 32byte 是一个要求,再来 32byte 是另一个要求。如果你试图请求一个合约中的一个函数,那么你的客户端将创建这个交易,广播这一交易到网路上,然后合约代码就可以读取交易数据,然后它将交易数据的初始 4 个 byte 解析为被调用的函数,而其它 byte 就是其他声明。所以,基本上这就是如何简单调用函数的。


视频链接: https://www.youtube.com/watch?v=Yo9o5nDTAAQ&feature=youtu.be
作者: Vitalik Buterin
翻译&校对: 阿剑 & Elisa


区块笔记版权所有丨转载请注明原文链接:科普 | Vitalik: 25 分钟认识以太坊(上)
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(1)个小伙伴在吐槽