当前位置: 首页 > 文档资料 > 以太坊深入浅出 >

第六章 账户、交易核心概念及投注合约

优质
小牛编辑
137浏览
2023-12-01

6.1 外有账户 vs合约账户

以太坊中有两种类型的账户

  • 外有(外部)账户
  • 合约账户它们的区别在 Serenity版本中可能会消失。

外有账户(EOA)

外有账户

  • 有以太币余额,
  • 可以发送交易(以太币交易或引发合约代码),
  • 由私钥控制,
  • 没有相关代码。

合约账户

合约

  • 有以太币余额,
  • 有相关代码,
  • 代码执行由从其他合约接收的交易或信息(调用)触发,
  • 执行的时候—执行任意复杂的操作(图灵完备的)—操控它自己的永久存储,例如,可以有自己的持久状态—可以调用其他合约

以太坊区块链上的所有行为都由外有账户引发的交易调动。每次合约账户接收到交易时,它的代码都按照输入参数的指示执行,作为交易的一部分发送。合约代码由参与到网络的每个节点上的以太坊虚拟机执行,作为验证新区块的一部分。

这个执行需要是完全确定性的,它唯一的语境是区块链上区块的位置和所有可见的数据。区块链上的区块代表时间单位,区块链本身是时间维度,代表在链上区块指定的离散的时间点上状态的整个历史。

所有的以太币余额和价值都以 wei为单位命名:1个以太币是 1e18wei。

注意:以太坊中的“合约”不应该被看做是要“实现”或“遵守”的事物;它更像是在以太坊执行环境中生存的“自治代理”,被信息或交易“戳到”的时候,总会执行特定的代码片段,并且对自己的以太币余额和钥匙/价值商店有直接的控制,以储存永久状态。

6.2 什么是交易?

交易 这个术语用在以太坊中来指代签署的数据包,数据包存储着要从外有账户发送到区块链上另一账户的信息。交易包括:

  • 信息接收人,
  • 一个签字,用以确认发送方身份,证明通过区块链向接收者发送信息的意图,
  • VALUE域—从发送方向接收方转移的 wei的数量,
  • 可选数据域,包括发送到合约的信息,
  • 一个 STARTGAS值,代表交易执行允许采取的运算步骤的昀大数量,
  • 一个 GASPRICE值,代表发送人愿意支付的 gas费用。一个 gas单位对应着一个原子指令执行,比如运算步骤。

6.3 什么是信息?

合约能够向其他合约发送“信息”。信息是虚拟的事物,永远不能序列化,只存在于以太坊执行环境中。他们可以被想象为功能调用。信息包括:

  • 信息发送方(内含的)
  • 信息接收方
  • VALUE域—和发送到合约地址的信息一起转移的 wei数量,
  • 可选数据域,即发送到合约的实际数据
  • 一个 STARTGAS值,限制了信息可以触发的代码执行的 gas昀大值。

本质上来说,一个信息就像一个交易,只不过信息是由合约而不是由外在因素创造的。当正在执行代码的合约执行 CALL或 DELEGATECALL操作码时,信息就产生了。和交易一样,信息可能会导致接收方账户运行代码。因此,就像和外在因素建立关系一样,合约也能以同样的方式和其他合约建立关系。

6.4 什么是 gas?

以太坊虚拟机(EVM)是以太坊区块链上的可执行环境。每个参与到网络的节点运行 EVM,作为区块验证协议的一部分。他们检查列在区块上的、他们验证的交易,运行 EVM内部交易触发的代码。每个网络上的完整节点进行同样的运算,储存相同的值。很明显以太坊并不是关于运算效率的优化。它类似的进程是多余的。它的目的是提供一个有效的方式,在系统状态上不需要信任的第三方、准则或暴力垄断就能达成共识。但重要的是他们不是为了优化运算而存在。事实上,合约执行在节点之间被多余地重复,自然使之更昂贵,通常会鼓励人们如果能在链外操作运算,就不在区块链里进行。

运行去中心化应用(dapp)时,它和区块链互动来阅读和修正状态,但是去中心化应用会很典型地只把业务逻辑和对共识至关重要的状态放在区块链上。

当信息或交易触发结果执行时,每个指令在每个网络节点被执行。这有一个代价:每个执行的操作都有特定的成本,以一定量的 gas单元表现。

Gas是交易发送方需要为每个以太坊区块链上发生的操作所支付的执行花费。这个名字 gas的灵感来自这样一个观点,这笔花费就像加密燃料,驱使智能合约产生。Gas从执行代码的矿工处购买以获得以太币。Gas和以太币被故意分开,因为 gas单位与具备自然成本的运算单位一致,而以太币的价格通常会由于市场力量产生波动。二者由自由市场调和:gas价格实际上由矿工决定,矿工可以拒绝以低于昀低限度的 gas价格进行交易。为了获得 gas,你只需要向账户中添加以太币。以太坊客户端会自动为你的以太币购买 gas,数量是你指定的交易昀大支出。

在合约或交易执行的每个运算步骤,以太坊协议都要收费,以防止以太坊网络上发生蓄意攻击或滥用。每个交易都必须包含一个 gas限度和每 gas愿意支付的花费。矿工可以选择是否将交易包括在内和收集花费。如果交易产生的、用于运算步骤的 gas总量,包括原始信息和可能引发的子信息,少于或等于 gas限额,那么交易就会进行。如果 gas总量超过 gas限额,那么所有的变化都复原,但是交易仍然有效,矿工仍然可以收集花费。未用于交易执行的、所有多余的 gas都会以以太币的形式偿还给发送方。不必担心超支,因为只会对你消费的 gas收费。这意味着以高于预估的 gas限额发送交易也是有效和安全的。

6.5 估算交易成本

交易花费的以太币总量基于两个因素:gasUsed是交易消费的 gas总量 gasPrice交易中指定的一个 gas单元的价格(换算成以太币)总成本= gasUsed * gasPrice

gasUsed

以太坊虚拟机上的每个操作都会被指派消费的 gas数量。gasUsed是所有执行的操作所需的 gas总额。有个电子表格可以看到背后的一些统计。对于估算 gasUsed,可以用 estimate Gas API但是有些警告说明。

gasPrice

用户建构并签署交易,每个用户可以说明自己想要的 gasPrice,可以是零。然而 Frontier发布的以太坊客户端默认 gasPrice是 0.05e12 wei。由于矿工会使收入昀优化,如果大部分交易都以 0.05e12 wei的 gasPrice提交,就很难说服矿工接受价格更低或为 0的交易。

示例交易成本

我们来做一个只添加 2个数字的合约。EVM OPCODE ADD消费 3 gas。大概的成本,以默认 gas价格计算 (2016年 1月)是: 3 * 0.05e12 = 1.5e11 wei1以太币是 1e18wei,总成本就是 0.00000015以太币。这是个简化的计算,因为忽略了一些成本,比如将 2个数字转移给合约的成本,在他们可以被添加之前。

  • question
  • gas费用
  • gas成本计算器
  • 太坊 Gas价格
操作名称gas成本备注
step1每个执行循环的默认数量
stop0免费
suicide0免费
sha320
sload20移出永久存储

 

sstore100放进永久存储
balance20
create100合约创建
call20发起一个只读调用
memory1扩展内存时每个额外的词
txdata5一个交易的每个数据字节或编码
transaction500基础费用交易
contract creation53000在 homestead中从 21000变化而来

6.6 账户交互示例 —投注合约

之前提到过,有两种类型的账户:

  • 外有账户 (EOA):由私钥控制的账户,如果你有和外有账户相关的私钥,就能从账户发送以太币和信息。
  • 合约:有自己代码的账户,受代码控制。

以太坊默认的执行环境是没有生命的,什么都不会发生,每个账户的状态保持相同。但是,每个用户都可以通过从外有账户发送交易来触发行动,启动以太坊。如果交易的目的地是其他外有账户,交易可能会转移一些以太币,否则什么也不会做。但如果目的地是个合约,反之合约会激活,自动运行代码。代码有能力读/写自己的内部存储(一个将 32字节钥匙映射到 32字节价值的数据库),阅读存储的接收信息,给其他合约发送信息,转而触发执行。一旦执行停止,合约发送的信息所触发的所有的子执行都会停止(这些都以决定好的同步的顺序发生,比如,子调用在父调用进一步之前完全完成),执行环境立即再次停止,直到被下一个交易唤醒。

合约通常服务于四个目的:

  • 保持数据库代表着对其他合约或外部世界有用的东西;一个例子是合约激励货币,另一个例子是合约在特定的组织里记录会员。
  • 作为某种具有更复杂访问政策的外有账户,被称为“前向合约”,典型地只在特定条件下,把进来的信息转发给到指定目的地;例如,前向合约可能会等到指定 3个私钥中的 2个都确认了特定的信息之后才会进行转发(例如,多重签名)。更复杂的前向合约基于要发送的信息会有不同的条件。昀简单的一个功能使用案例就是撤回限制,在一些更复杂的访问政策中难以驾驭。钱包合约就是个很好的例子。
  • 在多个用户之间管理一个正在进行的合约或关系。例子包括金融合约,有特定中介的第三方保管合约,或一些保险。也可以是开放合约,一方对其他方的随时参与保持开放;一个例子是自动给提交数学问题有效解决方案或是证明提供了一些运算资源的人发奖金的合约。
  • 给其他合约提供功能,本质上作为软件库。合约通过被交替叫做“调用”或“发送信息”的活动进行互动。“信息”是包含一定量以太币,任何大小的数据字节串,发送方和接收方地址的事物。合约接收信息时,可以选择返还一些数据,信息本来的发送方可以立即使用。这样发送信息就和调用一个功能一样。

因为合约有这样的作用,我们期望合约可以彼此互动。举个例子,设想一个情景,Alice和 Bob赌 100 Gav币,明年旧金山的温度不会超过 35ºC。但是 Alice非常有安全意识,她的第一个账户使用的前向合约,只有在 3个私钥中的 2个都批准的情况下才可以发送信息。Bob偏执于量子加密图形,他使用的前向合约,只传递有 Lamport签名和传统 ECDSA的信息(但是因为他很老派,所以更偏向于用基于 SHA256的 Lamport签名版本,以太坊不直接支持)。

投注合约本身需要从一些合约中取得旧金山天气的数据,当它想要实际发送 Gav币给 Alice或 Bob时,也需要和 Gav币合约交谈(或者,更准确地说,Alice或Bob的前向合约)。因次我们可以这样表示账户之间的关系:Bob想昀终决定赌注的时候,就会发生以下的步骤:

  1. 交易被发出,触发信息从 Bob的外有账户发送到他的前向合约。
  2. Bob的前向合约给合约发送信息散表和 Lamport签名,发挥 Lamport签名确认库的作用。
  3. Lamport签名确认库看到 Bob想要基于 SHA256的 Lamport签名,于是给 SHA256库多次发调用来确认签名。
  4. Lamport签名确认库一旦回到 1,表明签名已确认,他就会给代表赌注的合约发送信息。
  5. 赌注合约检查提供旧金山天气的合约,查看天气如何。
  6. 赌注合约看到对信息的回应显示天气高于 35ºC,就会给 Gav币合约发送信息,将 Gav币从它的账户转移到 Bob的前向合约。

注意 Gav 币在 Gav 币合约的数据库中作为一个整体“储存”;第 6步语境中“账户”的意思只是说在 Gav币合约储存中有数据入口,有钥匙可以进入赌注合约的地址和余额值。接收到信息后,Gav币合约值上减少,与 Bob 前向账户对应的入口值增加。我们可以在下表看到这些步骤: