"上一篇" 介绍了MetaMask钱包的安装和使用,并成功获取到部分测试以太币(ETH)并向另外一个账户发起了一笔转账,这笔转账称之为"交易",我们将在本篇来介绍它。
1. 以太坊的账户
首先,在学习交易之前,我们需要了解以太坊的账户体系。
以太坊的账户分为两种:外部账户和合约账户。
外部账户:外部账户一般由钱包创建,具有私钥,通过私钥控制和区块链网络和智能合约的访问;
合约账户:以太坊中智能合约部署后对应着一个合约账户,合约账户拥有智能合约代码,并受其逻辑控制。
简单而言,外部账户就是区块链的用户通过钱包创建的账户,而合约账户由合约代码编写者所有,对应着一个智能合约,由 EVM
执行。
合约账户和外部账户地址没有明显的区别,都是长度 20字节、160 位、转为十六进制(0x开头)后为 40 个字符的一个串,形如 0x829BD824B016326A401D083B33D092293333A830
两者的区别:
启动交易者(首先发起交易的一方)必须是拥有私钥的外部账户,也就是说只有用户可以启动交易;但是智能合约可以通过调用别的智能合约来对交易做出响应,比如,用户A通过智能合约A发起了一笔交易,虽然智能合约A调用智能合约B也可以发起了一笔交易,但是这整个过程中交易的启动者还是用户A的外部账户
外部账户和合约账户都可以发送和接收区块链货币(如以太币),但是交易目标如果是合约账户,则会使得合约账户拥有的智能合约代码在
EVM
中执行,外部账户则不会合约账户没有私钥,智能合约编写者通过代码逻辑来保证安全性,外部账户拥有私钥,用户需要通过妥善的保管私钥来保证账户的安全性
2. 以太币单位
交易与货币息息相关,以太坊发行的货币为以太币(Ether, ETH
,符号 Ξ
),其基本单位为 wei
,ETH与wei的关系如下:
1 ETH = 10^18 wei
此外,还有比较常用的 gwei
(gigawei):
1 ETH = 10^9 gwei 1 gwei = 10^9 wei
值(以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/
界面如图所示,最核心的是一个搜索框,可以通过输入地址、交易的hash、区块高度等查询交易明细,然后下边是概览信息,包括当前以太币(ETH)的价格(Ether Price)、当前交易的TPS(每秒的交易数)、基础的GAS费(Med Gas Price)、总市值(Market Cap)、挖矿难度(Difficulty)、以太坊最近12小时的处理速度(Hash Rate)等。
下边分为两块区域,左边的 Latest Blocks 展示了当前最新的区块列表。
右边的 Latest Transactions 则是最新的交易列表。
点击交易列表的任意一笔交易,可以看到交易的详细信息,如下图所示:
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
, pending
或 genesis
,默认为 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 费,其目的就是在于节约能源,避免资源的浪费。
在以太坊中,每一笔交易都需要消耗一定数量的 gas
,gas
是通过 ETH
以太币来支付的。因此,交易发起方需要设定 gas limit
和 gas price
(gas的单价) 并在发起交易时支付自己设定的 gas
费用,如果gas不足则交易失败并抛出 out of gas
异常,gas足够则交易成功,并会退还剩余的gas。
实际上,gas 使用的是一种单独的货币而不是 ETH,gas与eth存在着汇率关系,gas price就是设置gas与eth的汇率
再来回顾一下 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. 交易发送的以太币和数据
交易数据中的两个核心是 value
和 data
,value
代表这笔交易发送的以太币数量,data
表示交易发送的长度可变的编码过的附加数据。这可以分为几种情况:
交易只有
value
,没有data
:一般用于外部账户之间的转账,转给目标地址(to)一定数量的以太币交易既有
value
也有data
:这种情况通常是调用智能合约的方法,调用方法的信息通过data
传递给智能合约,并附带value
数量指定的以太币。此外,外部合约转账其实也可以附加data
,只是以太坊协议并不会处理data
,这与钱包实现的逻辑有关,可能钱包可以读取data
并做一定的逻辑处理交易只有
data
,没有value
:这种情况通常是在创建智能合约,或者调用智能合约的方法交易既没有
value
也没有data
:这种情况纯粹是在浪费 gas,一般可能是参数传递错误造成的
特殊的交易:创建智能合约 智能合约创建时,也是一笔交易,只是这笔交易的to地址为一个特殊的地址——零地址(0x0000000000000000000000000000000000000000,简写为0x0),此时交易的 |
data如何表示智能合约的方法? 调用智能合约方法的交易中,to表示智能合约地址,而具体的方法存储在data中,并且是一个十六进制编码的数据,包括两个部分:
|
关于智能合约的创建和方法调用,我们将在后续文章中重点讨论。
5. 总结
本文介绍了以太坊的账户系统,然后介绍了交易的数据结构。交易是区块链中非常重要的概念,区块链上每一个状态转换的操作都是通过交易来实现的,比如转账、创建合约、燃烧代币等等操作。后续在介绍智能合约时,我们还会详细的介绍交易的 value
和 data
属性。