首页
学习
活动
专区
工具
TVP
发布

面向小白的以太坊开发教程汉化版

区块链研习社

最好的区块链学习社群

本页面的目的是介绍以太坊的基础知识,从开发的角度来看,您需要了解以太坊的基础知识,以生成合同和分散的应用程序。有关以太坊的一般介绍,请参阅白皮书,如需完整的技术规格,请参阅黄皮书,但这些不是本页面的先决条件; 也就是说,这个页面是专门针对应用程序开发人员的以太坊的替代介绍。

介绍

以太坊是一个平台,旨在让人们使用区块链技术轻松编写分散式应用程序(Đapps)。分散的应用程序是为用户提供某种特定用途的应用程序,但具有应用程序本身不依赖于任何特定方的重要属性。Đapp不是作为销售或提供特定的一方的服务的前端,而是一个不用任何集中的中间媒介而在一起互动的人们和组织的工具。

即使是通常是集中供应商的领域(例如过滤,身份管理,托管和争议解决)的必要“中介”功能,也可以由网络直接处理,或者使用诸如内部令牌系统和信誉之类的工具让任何人参与系统来确保用户获得高质量的服务。Đapps的早期例子包括BitTorrent文件共享和比特币货币。以太坊采用BitTorrent和比特币,点对点网络和区块链所使用的主要开发方式,并将其推广,以便开发人员将这些技术用于任何目的。

以太坊区块链可以被交替地描述为一个内置编程语言的区块链,或者是一个基于共识的全局执行的虚拟机。实际处理内部状态和计算的协议部分称为以太坊虚拟机(EVM)。从实际的角度来看,EVM可以被看作是一个大型的分散式计算机,其中包含数百万个对象,称为“账户”,能够维护内部数据库,执行代码并相互通话。

有两种类型的帐户:

外部拥有账户(EOAs):由私钥控制的账户,如果您拥有与EOA关联的私钥,则可以从其发送以太和消息。

合同:一个拥有自己代码的账户,由代码控制。

默认情况下,以太坊执行环境无生气,没有任何事情发生,每个帐户的状态保持不变。但是,任何用户都可以通过从外部拥有的账户发送交易来触发行动,从而使以太坊的轮子运动。如果交易的目的地是另一个EOA,那么该交易可能转移一些以太,但否则什么都不做。但是,如果目的地是合同,合同又会激活,并自动运行其代码。

代码能够读/写自己的内部存储器(数据库将32字节的密钥映射到32字节的值),读取接收到的消息的存储,并将消息发送到其他契约,从而触发它们的执行。一旦执行停止,并且由合同发送的消息触发的所有子执行都会停止(这一切都以确定性和同步的顺序进行,即子调用在父调用进一步之前完全完成),则执行环境将停止再一次,直到下一次交易被唤醒。

合同通常有四个目的:

维护一个数据存储,代表对其他合同或外部世界有用的东西; 其中一个例子是模拟货币的合同,另一个例子是记录特定组织的成员资格的合同。

作为一种具有更复杂访问策略的外部账户; 这被称为“转发合同”,并且通常只涉及在满足某些条件的情况下简单地将传入消息重新发送到某个期望的目的地; 例如,可以有一个转发合同,等待直到给定的三个私钥中的两个在重新发送它之前确认了一个特定的消息(即multisig)。更复杂的转发合同根据发送的消息的性质具有不同的条件; 这个功能的最简单的用例是一个可以通过一些更复杂的访问过程被覆盖的提取限制。

管理多个用户之间正在进行的合同或关系。这方面的例子包括一个金融合同,一些特定的调解人的代管,或者某种保险。也可以有一方开放合同,让任何一方随时参与; 其中一个例子就是一个合同,它会自动支付给谁提出一个有效的解决方案给一些数学问题,或者证明它提供了一些计算资源。

为其他合同提供职能; 基本上作为一个软件库。

合同通过交替地称为“呼叫”或“发送消息”的活动彼此交互。“消息”是一个包含一定数量的以太(在以太坊中使用的一个特殊的内部货币,主要目的是支付交易费用),任意大小的数据的字节数组,发送者和接收者的地址的对象。当合同收到一条消息时,它可以选择返回一些数据,然后消息的原始发送者可以立即使用这些数据。这样,发送消息就像调用一个函数一样。

因为合同可以扮演不同的角色,所以我们期望合约会互相影响。举一个例子,考虑一下Alice和Bob打赌100 GavCoin的情况,即旧金山的气温在明年的任何时候都不会超过35ºC。然而,Alice非常注重安全性,而且她的主账户使用转发合同,这个转发合同只能通过三个私人密钥中的两个批准发送消息。鲍勃对量子密码学是偏执的,所以他使用转发契约,只传递与传统的ECDSA一起签名Lamport签名的消息(但由于他是老式的,他倾向于使用基于SHA256的Lamport sigs版本,这是以太坊直接不支持)。

投注合约本身需要从某个合同中提取有关旧金山天气的数据,并且在需要将GavCoin实际发送给Alice或Bob(或者更确切地说,Alice或Bob的转发)时还需要与GavCoin合同交谈合同)。我们可以显示账户之间的关系:

当鲍勃想完成下注时,会发生以下步骤:

发送交易,触发Bob的EOA到Bob的转发合同的消息。

Bob的转发合同将消息的散列和Lamport签名发送到用作Lamport签名验证库的合同。

Lamport签名验证库看到Bob想要一个基于SHA256的Lamport sig,所以根据需要多次调用SHA256库来验证签名。

一旦Lamport签名验证库返回1,表示签名已经过验证,它会向代表该合同的合同发送一条消息。

投注合约检查提供旧金山温度的合约以查看温度。

投注合同认为对消息的回应显示温度高于35ºC,因此它向GavCoin合同发送一条消息,将GavCoin从其账户转移到Bob的转发合同。

请注意,GavCoin全部“存储”为GavCoin合同数据库中的条目; 在步骤6的上下文中的“帐户”一词仅仅意味着在GavCoin合同存储器中存在具有用于投注合同地址的密钥和其余额的值的数据条目。收到此消息后,GavCoin合同将此值减少一定数量,并增加与Bob的转发合同地址对应的条目中的值。我们可以在下图中看到这些步骤:

状态机

EVM中的计算是使用基于堆栈的字节码语言完成的,就像比特币脚本,传统汇编和Lisp(Lisp部分归因于递归消息发送功能)之间的交叉。EVM中的程序是一系列操作码,如下所示:

PUSH1 0 CALLDATALOAD SLOAD NOT PUSH1 9 JUMPI STOP JUMPDEST PUSH1 32 CALLDATALOAD PUSH1 0 CALLDATALOAD SSTORE

这个特定的合同的目的是作为一个名字登记处; 任何人都可以发送包含64字节数据的消息,其中32个是关键字,32个是数值。合同检查密钥是否已经在存储器中注册,如果没有,则合同在该密钥处注册该值。

在执行过程中,维持一个称为“存储器”的无限可扩展字节数组,指向当前指令的“程序计数器”和一堆32字节值。在执行开始时,内存和堆栈是空的,PC是零。现在让我们假设这个代码的合同是第一次被访问,并且一个消息被发送到123 wei(10 18 wei = 1 ether)和64个字节的数据,其中前32个字节编码了54和第二个32字节编码2020202020。

因此,开始时的状态是:

PC: 0 STACK: [] MEM: [], STORAGE: {}

位置0处的指令是PUSH1,它将一个单字节的值压入堆栈并在代码中跳转两步。因此,我们有:

PC: 2 STACK: [0] MEM: [], STORAGE: {}

位置2处的指令是CALLDATALOAD,它从堆栈中弹出一个值,从该索引开始加载32个字节的消息数据,并将其压入堆栈。回想一下,这里的前32个字节编码为54。

PC: 3 STACK: [54] MEM: [], STORAGE: {}

SLOAD弹出堆栈中的一个,并将该索引处的合同存储中的值压入堆栈。由于合同是第一次使用,它什么也没有,所以零。

PC: 4 STACK: [0] MEM: [], STORAGE: {}

不弹出一个值,如果值为零则推1,否则为0

PC: 5 STACK: [1] MEM: [], STORAGE: {}

接下来,我们PUSH1 9。

PC: 7 STACK: [1, 9] MEM: [], STORAGE: {}

JUMPI指令弹出2个值,只有第二个值不为零时才跳转到第一个指定的指令。在这里,第二个是非零的,所以我们跳。如果存储索引54中的值不是零,那么堆栈顶部的第二个值将为0(由于NOT),所以我们不会跳转,并且我们将前进到STOP指令,导致我们停止执行。

PC: 9 STACK: [] MEM: [], STORAGE: {}

在这里,我们PUSH1 32。

PC: 11 STACK: [32] MEM: [], STORAGE: {}

现在,我们再次调用CALLDATALOAD,弹出32,并将消息数据中的字节从字节32开始,直到字节63。

接下来,我们PUSH1 0。

现在,我们再次加载消息数据字节0-31(加载消息数据就像加载内存一样便宜,所以我们不费心将其保存在内存中)

最后,我们SSTORE将2020202020的值存储在索引54处。

PC: 17 STACK: [] MEM: [], STORAGE:

幸运的是,您不必在低级程序集中编程; 一个高级语言的存在,特别是为写作合同而设计的,被称为Solidity的存在,使你更容易编写合同(还有其他几个,也包括LLL,Serpent和Mutan,你可能会发现更容易学习或根据你的经验使用)。您用这些语言编写的任何代码都会被编译到EVM中,并创建发送包含EVM字节码的事务的合约。

有两种类型的交易:发送交易和合同创建交易。发送事务是标准事务,包含接收地址,以太量,数据字节阵列和一些其他参数,以及来自与发送者账户相关联的私钥的签名。合同创建交易看起来像一个标准的交易,除了收货地址是空白的。当创建交易的合同进入区块链时,交易中的数据字节阵列被解释为EVM代码,并且该EVM执行返回的值被视为新合同的代码; 因此,您可以在初始化过程中执行某些事务。新合同的地址是根据发送地址和发送帐户之前进行交易的次数(此值称为帐户现时也由于不相关的安全原因而被保留)确定性计算的。因此,您需要将其放在区块链上以生成上述名称注册表的完整代码如下所示:

PUSH1 16 DUP PUSH1 12 PUSH1 0 CODECOPY PUSH1 0 RETURN STOP PUSH1 0 CALLDATALOAD

SLOAD NOT PUSH1 9 JUMPI STOP PUSH1 32 CALLDATALOAD PUSH1 0 CALLDATALOAD SSTORE

关键操作码是CODECOPY,将从字节12开始的16字节代码复制到从索引0开始的内存中,并将RETURN返回到内存字节0-16,即。代码字节12-28(可以自由地在纸上“手动”执行,以验证代码和内存的这些部分实际上被复制并返回)。代码字节12-28当然是我们上面看到的实际代码。

加油站

EVM工作方式的一个重要方面是EVM中执行的每一个操作实际上是由每个完整节点同时执行的。这是以太坊1.0共识模式的必要组成部分,其优点是EVM的任何合同都可以以几乎零成本的方式调用任何其他合同,但也有缺点,EVM的计算步骤非常昂贵。粗略地说,使用一个好的启发是,你将无法在EVM上做任何你从1999年起无法在智能手机上做的事情。EVM的可接受使用包括运行业务逻辑(“如果这样的话”)和验证签名和其他密码对象; 在这个上限的应用程序验证其他区块链(例如分散的以太币到比特币交易所)的部分;

为了防止故意的攻击和滥用,以太坊协议每计算一步收费。费用以市场为基础,虽然在实践中是强制性的; 可以包含在一个区块中的操作数量的浮动限制迫使即使是能够承担交易费用的矿工也能够接近无偿地向整个网络收取相当于交易成本的费用; 请参阅白皮书中有关费用的更多细节,了解我们的费用和运营限制系统的经济基础。

收费的方式如下。每笔交易都必须包含一个GASPRICE和一个STARTGAS价值。STARTGAS是交易分配的“天然气”数量,GASPRICE是交易单位天然气支付的费用; 因此,在交易发送时,评估过程中首先要做的是STARTGAS * GASPRICE从发送账户余额中减去wei加上交易的价值。GASPRICE是由交易发送者设定的,但是矿工可能会拒绝处理GASPRICE太低的交易。

气体可以粗略地被认为是计算步骤的一个计数器,并且在交易执行期间存在,但不在其外部。当事务执行开始时,剩余的气体被设定为STARTGAS - 21000 - 68 * TXDATALEN,其中TXDATALEN是在交易数据的字节数(注意:零个字节将只4气体因零个字节长串的更大的可压缩)。每一个计算步骤,从总量中减去一定量(通常是1,有时更多取决于操作)。如果天然气下降到零,那么所有的执行都会恢复,但交易仍然有效,发送者仍然需要支付燃气费用。如果交易执行结束,N >= 0天然气剩余,则发送的账户将退还给N * GASPRICEwei。

在合同执行过程中,当合同发送消息时,该消息调用本身带有气体限制,而且子执行的工作方式相同(也就是说,它可以用尽气体,恢复或执行成功并返回一个值) 。如果子执行耗尽,父执行继续; 因此,如果您对子执行设置了气体限制,则合同可以调用另一个合同是完全“安全”的。如果子执行有一些剩余气体,那么该气体返回到父执行继续使用。

虚拟机操作码

EVM中操作码的完整列表可以在黄色文件中找到。请注意,高级语言通常会为这些操作码拥有自己的包装器,有时界面也会有很大的不同。

以太坊区块链(或“分类帐”)是分散的,大规模复制的数据库,其中存储了所有帐户的当前状态。区块链使用名为Patricia树(或“trie”)的数据库来存储所有帐户; 这本质上是一种特殊的Merkle树,充当通用的键/值存储。像标准Merkle树一样,Patricia树有一个可以用来引用整个树的“根哈希”,并且在不改变根哈希的情况下,树的内容不能被修改。对于每个帐户,树存储一个4元组[account_nonce, ether_balance, code_hash, storage_root],其中包含account_nonce从该帐户发送的交易数量(保留以防止重播攻击),ether_balance是帐户的余额,code_hash如果账户是合同,则代码的散列,否则storage_root是“”,并且是存储存储数据的另一个派翠西亚树的根。

每一分钟,矿工都会产生一个新的区块(在Ethereum中采矿的概念与比特币中的概念完全一样;请参阅任何比特币教程以获取更多信息),该区块包含自上一个区块以来发生的交易清单,代表新状态(“状态树”)的帕特里夏树的根哈希应用那些事务并给矿工一个创建块的以太奖励。

由于帕特里夏树的工作方式,如果做了很少的改变,那么树的大部分将和最后一块完全一样。因此,不需要两次存储数据,因为新树中的节点将简单地能够指向存储旧树的节点的相同的存储器地址,其中新树和旧树完全相同。如果千块数据在块N和块之间改变N + 1,则即使树的总大小是几千兆字节,也需要为块存储新的数据量N + 1最多只有几百千字节,通常要少得多(尤其是在同一合同内发生多重变更的情况下)。每个块都包含前一个块的散列(这使得块设置为“链”)以及辅助数据(如块号,时间戳,矿工地址和气体限制)。

图形界面(OUTDATED API)

合同本身是一个强大的东西,但它不是一个完整的Đapp。一个Đapp被定义为一个契约和一个使用该契约的图形界面的组合(注意:现在只有这样,未来版本的以太坊将包括窃窃私语,允许Đapp中的节点直接发送彼此之间没有区块链的点对点消息)。现在,界面被实现为一个HTML / CSS / JS网页,带有一个特殊的JavaScript API,eth用于与以太坊区块链一起工作。Javascript API的关键部分如下:

eth.transact(from, ethervalue, to, data, gaslimit, gasprice)- 从期望的地址(注意:from必须是私钥并且to必须是十六进制形式的地址)发送交易到所需的地址

(string).pad(n)- 将编码为字符串的数字转换为二进制形式的n字节

eth.gasPrice - 返回当前的天然气价格

eth.secretToAddress(key) - 将私钥转换为地址

eth.storageAt(acct, index) - 在所需索引处返回所需帐户的存储条目

eth.key - 用户的私钥

eth.watch(acct, index, f)- f给定帐户的给定存储条目发生更改时调用

您不需要任何特殊的源文件或库来使用该eth对象; 但是,您的Đapp只能在以太坊客户端打开时才能使用,而不是常规的Web浏览器。

作者:wiki,区块链兄弟,版权归原作者所有

英文地址:https://github.com/ethereum/wiki/wiki/Ethereum-Development-Tutorial

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

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券