"上一篇" 介绍了MetaMask钱包的安装和使用,并成功获取到部分测试以太币(ETH)并向另外一个账户发起了一笔转账,这笔转账称之为"交易",我们将在本篇来介绍它。

1. 以太坊的账户

首先,在学习交易之前,我们需要了解以太坊的账户体系。

以太坊的账户分为两种:外部账户和合约账户。

  • 外部账户:外部账户一般由钱包创建,具有私钥,通过私钥控制和区块链网络和智能合约的访问;

  • 合约账户:以太坊中智能合约部署后对应着一个合约账户,合约账户拥有智能合约代码,并受其逻辑控制。

简单而言,外部账户就是区块链的用户通过钱包创建的账户,而合约账户由合约代码编写者所有,对应着一个智能合约,由 EVM 执行。

合约账户和外部账户地址没有明显的区别,都是长度 20字节、160 位、转为十六进制(0x开头)后为 40 个字符的一个串,形如 0x829BD824B016326A401D083B33D092293333A830

两者的区别:

  1. 启动交易者(首先发起交易的一方)必须是拥有私钥的外部账户,也就是说只有用户可以启动交易;但是智能合约可以通过调用别的智能合约来对交易做出响应,比如,用户A通过智能合约A发起了一笔交易,虽然智能合约A调用智能合约B也可以发起了一笔交易,但是这整个过程中交易的启动者还是用户A的外部账户

  2. 外部账户和合约账户都可以发送和接收区块链货币(如以太币),但是交易目标如果是合约账户,则会使得合约账户拥有的智能合约代码在 EVM 中执行,外部账户则不会

  3. 合约账户没有私钥,智能合约编写者通过代码逻辑来保证安全性,外部账户拥有私钥,用户需要通过妥善的保管私钥来保证账户的安全性

2. 以太币单位

交易与货币息息相关,以太坊发行的货币为以太币(Ether, ETH,符号 Ξ),其基本单位为 wei,ETH与wei的关系如下:

1 ETH = 10^18 wei

此外,还有比较常用的 gwei (gigawei):

1 ETH = 10^9 gwei
1 gwei = 10^9 wei
Table 1. 以太币的面额和单位
值(以wei为单位)指数通用名称标准名称

1

1

wei

wei

1,000

103

babbage

kilowei or femtoether

1,000,000

106

lovelace

megawei or picoether

1,000,000,000

109

shannon

gigawei or nanoether

1,000,000,000,000

1012

szabo

microether or micro

1,000,000,000,000,000

1015

finney

milliether or milli

1,000,000,000,000,000,000

1018

ether

ether

1,000,000,000,000,000,000,000

1021

grand

kiloether

1,000,000,000,000,000,000,000,000

1024

megaether

3. 区块链浏览器

前边说过,区块链的本质是一个共享的超级账本,每一笔交易都在账本上记录在案,而且任何人都可以查看。那么,如果产生了一笔交易,我们如何能够查询到它的详细信息呢?

交易数据存储在区块链上的,为了便于查看、跟踪链上的数据,区块链管理者会提供一个Web的页面工具来供任何人查询链上的数据,这个web页面工具称为"区块链浏览器"。当然,除了区块链浏览器之外,还可以通过多种手段查询到交易数据,比如通过rpc直接访问api。

就以太坊而言,其区块链浏览器地址为: https://etherscan.io/

etherio

界面如图所示,最核心的是一个搜索框,可以通过输入地址、交易的hash、区块高度等查询交易明细,然后下边是概览信息,包括当前以太币(ETH)的价格(Ether Price)、当前交易的TPS(每秒的交易数)、基础的GAS费(Med Gas Price)、总市值(Market Cap)、挖矿难度(Difficulty)、以太坊最近12小时的处理速度(Hash Rate)等。

下边分为两块区域,左边的 Latest Blocks 展示了当前最新的区块列表。

etherio block

右边的 Latest Transactions 则是最新的交易列表。

etherio tx

点击交易列表的任意一笔交易,可以看到交易的详细信息,如下图所示:

etherio tx detail
Figure 1. 交易明细

4. 交易简介

交易的数据比较多,涉及到的概念相对较多。

什么是交易?交易是由外部账户发起的经过签名的消息,经过区块链网络传播,由矿工打包记录到区块链上。简单而言,交易就是记录在"超级账本"中的每一笔消息,如收入、支出、转账,此外,合约创建以及涉及资金出入的合约方法调用等都是交易。区块链中涉及状态改变的操作,都是通过交易实现的。

4.1. 交易的结构

一笔交易的明细如图交易明细所示,区块链浏览器上展示的信息如下:

  • Transaction Hash: 每一笔交易都有唯一的hash值用来标记这笔交易,其实就是这笔交易的ID

  • Status: 交易状态,Pending为确认中,确认成功后会有 Success,或者失败为 Failed

  • Block: 这笔交易所在的区块高度

  • Timestamp: 这笔交易被打包的时间,也就是出块的时间

  • From: 交易发起方的地址

  • To: 交易接收方的地址

  • Value: 交易的金额

其余一些字段,如nonce、gas price、gas limit、gas fees、data等包含在交易结构中。

交易本质上是一串打包在一起的二进制数据,包括如下内容:

Nonce

交易的随机数,其实是交易的序列编号,由创建交易的外部账号提供,用于防止 重放攻击

Gas Price

交易的 Gas 费(燃气,单位为: Wei),由交易发起者设置,表示其愿意为这笔交易支付的Gas单价,Gas Price越高,打包越快,往往通过增加 Gas 费从而达到加快交易打包的目的

Gas Limit

Gas 上限数量,表示交易发起者愿意为这笔交易支付的最大 Gas 数量

Recipient

交易目标地址,可以是外部账户或合约账户地址

Value

这笔交易发送给以太坊的以太币数量

Data

交易的附加数据

v,r,s

有创建交易的外部账户提供的 椭圆曲线签名 的三个参数

首先,来重点看一下交易的 Nonce。

4.2. 交易的随机数

Nonce 字段本意是随机数,为每一笔交易提供唯一的标记值,但实际上,以太坊中将其设计为一个递增的有序序列编号, 以太坊黄皮书中的定义如下:

nonce: A scalar value equal to the number of transactions sent from this address or, in the case of accounts with associated code, the number of contract-creations made by this account.

翻译过来就是:nonce是一个标量值,等于账户地址已经发送的总交易数量,如果账户关联智能合约,那nonce等于账户已经创建的智能合约数量。

通常,外部账户在钱包中发起交易时,钱包会通过 web3.eth.getTransactionCount api获取当前的交易数量并作为 nonce 值,这个函数能获取到当前已经被确认的交易数量,nonce 从0开始,比如,账户A 有2笔确认的交易数量,那么,nonce分别为0和1,下一个nonce值则是2,也就是上边这个api返回的值。

如何生成Nonce?

以前,web3.eth.getTransactionCount 只能返回已经确认了的交易数量,不过现在,可以将 pending 的交易数量纳入统计了:

web3.eth.getTransactionCount(address [, defaultBlock] [, callback])

第二个参数支持传递 latest, earliest, pendinggenesis,默认为 latest,只查询确认的交易数量,传递 pending 则可以查询待确认的了。

如果自己开发一个钱包应用,可能存在多人对同一地址发起交易的情况,如果只查询已确认的交易数量,此时的 nonce 可能与 pending 状态的交易nonce重复,则会出错。比如,账户A有一笔 nonce 为1的交易正在 pending,而由于多人同时发起交易,账户A现在又发起了一笔,nonce 同样为1(因为交易未确认),而且其给的 gas price 低于上一笔 pending 的交易,那么这笔交易永远也不会执行,此时就会产生 replacement transaction underpriced 的错误信息。此时,需要给 web3.eth.getTransactionCount api传递第二参数 pending

Nonce的顺序

以太坊中,交易是按照nonce的顺序依次处理的,中间不能间断。比如账户A发起一笔nonce为0的交易,接着又发起一笔nonce为2的交易,此时即使第一笔交易完成,第二笔交易也不会执行,因为一直在等待nonce为1的交易,如果没有填上,那么后续所有交易都会被堵住。

4.3. 交易的Gas费

"以太坊和图灵完备" 中,我们已经介绍了为什么以太坊设计了 gas 费,其目的就是在于节约能源,避免资源的浪费。

在以太坊中,每一笔交易都需要消耗一定数量的 gasgas 是通过 ETH 以太币来支付的。因此,交易发起方需要设定 gas limitgas price (gas的单价) 并在发起交易时支付自己设定的 gas 费用,如果gas不足则交易失败并抛出 out of gas 异常,gas足够则交易成功,并会退还剩余的gas。

实际上,gas 使用的是一种单独的货币而不是 ETH,gas与eth存在着汇率关系,gas price就是设置gas与eth的汇率

再来回顾一下 gas 的几个概念:

transaction gas
  • Gas Price:交易发起人设定的gas单价,价格越高,交易越容易先被矿工打包

  • Gas Limit:交易发起人设定的完成这笔交易的gas上限,超过上限则交易失败,并返回 out of gas,一般 gas limit 不少于 21000个

  • Gas Used:实际使用的gas数量,乘以gas price就是实际消耗的gas费,剩余的会退还

  • Transaction Fee: 实际消耗的gas费

4.4. 交易的接收者

From 字段表示交易的发起者地址,To 字段表示交易的接收者地址。

需要注意的是,以太坊没有办法验证接收者地址的合法性,任何20个字节的值都被认为是合法的地址。因此,接收者地址验证工作应该在DApp应用侧来实现,以太坊的改进提案 EIP-55 提出了一种地址校验机制。如果向一个不存在的地址转入以太币,相当于销毁以太币。

4.5. 交易发送的以太币和数据

交易数据中的两个核心是 valuedatavalue 代表这笔交易发送的以太币数量,data 表示交易发送的长度可变的编码过的附加数据。这可以分为几种情况:

  • 交易只有 value,没有 data:一般用于外部账户之间的转账,转给目标地址(to)一定数量的以太币

  • 交易既有 value 也有 data:这种情况通常是调用智能合约的方法,调用方法的信息通过 data 传递给智能合约,并附带 value 数量指定的以太币。此外,外部合约转账其实也可以附加 data,只是以太坊协议并不会处理 data,这与钱包实现的逻辑有关,可能钱包可以读取 data 并做一定的逻辑处理

  • 交易只有 data,没有 value:这种情况通常是在创建智能合约,或者调用智能合约的方法

  • 交易既没有 value 也没有 data:这种情况纯粹是在浪费 gas,一般可能是参数传递错误造成的

特殊的交易:创建智能合约

智能合约创建时,也是一笔交易,只是这笔交易的to地址为一个特殊的地址——零地址(0x0000000000000000000000000000000000000000,简写为0x0),此时交易的 data 存储的是编译后的智能合约字节码,value 也可以附带值,用来设置智能合约创建后的余额。

data如何表示智能合约的方法?

调用智能合约方法的交易中,to表示智能合约地址,而具体的方法存储在data中,并且是一个十六进制编码的数据,包括两个部分:

  • 函数选择器:指的是被调用函数原型的Keccak-256哈希值的前4个字节,这样EVM就可以识别出调用哪一个函数了

  • 函数参数:根据EVM多个规则定义的编码结构,通常是将参数值转为Hex编码后的值

关于智能合约的创建和方法调用,我们将在后续文章中重点讨论。

5. 总结

本文介绍了以太坊的账户系统,然后介绍了交易的数据结构。交易是区块链中非常重要的概念,区块链上每一个状态转换的操作都是通过交易来实现的,比如转账、创建合约、燃烧代币等等操作。后续在介绍智能合约时,我们还会详细的介绍交易的 valuedata 属性。


相关阅读