原文标题:《成为链上数据分析师之路——读懂以太坊交易》
原文来源:OKLink
原文作者:Mabrary
链上数据分析的流程可以从数据出发来解读行为,再到意图直至交易心理。其中,行为可以是交易者的行为,可以是合约的行为,也可以是市场的行为。对交易者意图的判断和长期的观察可以得出其交易心理,从合约行为可以更精准地了解合约创建者(项目方)的意图,代码不说谎。最后,对某些特定行为和意图的分析可以得出市场整体的心理状态和心理预期。
而链上数据的核心就是交易数据,那么本文我们就从交易数据开始解读,从浅入深,按照从整体到细节的顺序,以以太坊的工作原理为基线理解浏览器中的交易数据。
我们把交易数据中需要了解的概念按照从浅到深的顺序分为三级,大家可以根据自己的基础有选择地阅读:
一级关键词:普通交易|合约交易
二级关键词:外部账户|内部账户|内部交易
三级关键词:Transfer|Transaction|事件|日志
一、以太坊交易类型
首先,以太坊中的交易可以大致分为两种:外部地址交易 (图 1)&合约交易 (图 2)。
图 1:外部账户地址交易概览页
普通地址交易是指仅涉及以太坊原生Token (native token)Ether 的转移,不涉及合约的调用以及以太坊中其它 Token 的交易。普通交易中的数据可以大概分为四大块:交易哈希、时间等归于交易索引 (index),提供定位交易的信息。交易金额具体是指 Ether 转移的数量,交易的发送方 (sender) 和接收方 (receiver) 互为本次交易中的交易对手。Gas 费的消耗是本次交易发送方需要承担的交易成本。
图 2:0x513d 和 Metamask Router 合约交易概览页
我们看到,涉及智能合约的浏览器交易概览页会多出三块内容:
(1) 以太坊执行交易的内部过程(内部交易);
(2) Token 转账的结果( Token 转账);
(3) 合约执行的入参(输入数据)
相比普通交易,合约交易页顶部还多了两个标签(蓝色):内部交易和事件日志。
那么,什么是内部交易?为什么普通地址之间的交易没有内部交易的标签?内部交易标签内呈现的信息如何解读?内部交易 (Internal Transaction) 和普通交易 (Transaction) 的区别在哪?
要回答上面前三个问题我们需要了解两个概念:外部账户&内部账户
二、外部账户&内部账户
以太坊的地址(账户)分为外部账户(即实体账户)和内部账户(即合约账户)两种。
用户通过手中的私钥访问外部地址,而内部地址不能被当作钱包直接访问,只能通过调用它们的函数使用。
外部账户就是以太坊以外世界的实体 (人) 想访问以太坊世界的代理,也是以太坊这个世界计算机的状态发生改变最初始的源头。我们知道以太坊状态的改变由交易(普通交易)发起,如果交易对手为一个智能合约,则交易中的输入数据 (input) 就会作为虚拟机执行合约时的入参触发合约方法。合约方法被调用执行后可能还会触发其它合约中的方法,如此形成一个链式反应,这些链式反应的中间过程即为内部交易。如图 3:
图 3
现在,我们再来看一下浏览器中的普通地址交易 (图 1),就明白为什么没有内部交易的标签项了——因为这是一个从外部账户到外部账户之间的转账,发送方没有在输入数据中附加代码,接收方也没有可执行的合约方法。而图 2 的合约交易由 0x514d 的外部账户地址发起至 0x881d 的合约账户,发起方 0x514d 通过输入数据 (input data) 告诉合约 0x881d 所需调用的合约方法 (function) 以及方法所需传入的参数。合约中的方法被调用后会继续调用其他合约中的方法。比如,在第一条内部交易中 Metamask 的 Router 合约会继续调用 (call) 接收方 0x74de(Matic Token 的合约地址) 中的方法……最终形成一个调用链条,这就是我们所说的内部交易。
图 4:0x513d 和 Metamask Router 合约交易内部交易标签页
注:内部交易详情页记录的交易只涉及原生 Token Ether 的转移。
需要注意的是,由于以太坊区块链中只存储以太坊虚拟机 (EVM) 处理交易后的状态,并不存储计算过程。所以,以上展示的内部交易信息并不存储在区块链中,而当中发生以太坊转账(红框)的结果则最终会更新在 t+1 的世界状态中。其中一部分执行结果会体现在「 Token 转账」(Token Transfer) 里。
图 5:Token Transfer 部分
回过头来,我们再来回顾一下外部账户的概念。虽然外部账户的行为有时并不直接导致以太坊世界状态的改变(外部账户余额的变化或合约账户状态的变化),但追踪这些变化的源头一定来自外部账户,而这时直接导致改变的原因就是合约方法的执行。
读到这里,大家在脑中可能已经积累了一些疑问:
·我们经常会在一些描述中看到两个词:Transfer 和 Transaction,两个词都可以被翻译为转账,那它们有何不同呢?
·上面提到的 0x881d 合约如何知道被调用了哪个合约方法?
·第三个标签事件日志 (Log) 是什么?它的作用在哪里?它们都会记录在区块链上吗?
我们一个一个来回答~
三、交易和事件 1. Transfer 和 Transaction 有何不同?
Transfer 通常指 Token 归属权的转移,可以分为原生 Token 的转账和其它标准 Token 的转账 (如,ERC20、ERC721 等);而 Transaction 是指交易的发起者,也就是 from 地址 (外部账户),向矿工提交的交易请求,如果被矿工成功纳入到区块中并完成共识,则该笔交易生效,否则会被告知交易失败。
那发起者提交的交易到底包含哪些信息呢?这就需要我们了解一个交易是如何在链上发生的。
图 6:Transaction 数据组成
我们重点解释第三部分。这部分从程序执行逻辑上是交易发送者输入以太坊虚拟机执行此交易的初始信息: 虚拟机操作对象(接收方 To)、从交易发送方转移到操作对象的资产(Value),以及虚拟机运行时入参 (input)。其中 To 为空时,意味着虚拟机无可操作对象,此时虚拟机将利用 input 内容部署一个新合约。
2. 下面我们还是以上面的合约交易(图 2)为例回答第二个问题:0x881d 合约如何知道被调用了哪个合约方法?
这需要我们对入参进行解析。输入数据去除 0x 后的前八位代表合约方法识别符 (5f575529),后边数据为方法所需的参数。
Input Data:
0x5f57552900000000000000000000000000000000000000000000000000000000000000800000 000000000000000000007d1afa7b718fb893db30a3abc0cfc608aacfebb0000000000000000000 000000000000000000000000000007d59f7b054aa6bc0000000000000000000000000000000000 000000000000000000000000000000c00000000000000000000000000000000000000000000000 0000000000000000136f6e65496e6368563446656544796e616d69630000000000000000000000 000000000000000000000000000000000000000000000000000000000000000002000000000000 000000000000007d1afa7b718fb893db30a3abc0cfc608aacfebb0000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000007d59f7b054aa6bc000000000000000000000000000000000000000000000000000102 04aab87265e2000000000000000000000000000000000000000000000000000000000000012000 00000000000000000000000000000000000000000000000002591872913bde0000000000000000 00000000f326e4de8f66a0bdc0970b79e0924e33c79f1915000000000000000000000000000000 000000000000000000000000000000000100000000000000000000000000000000000000000000 000000000000000000c82e95b6c80000000000000000000000007d1afa7b718fb893db30a3abc0 cfc608aacfebb0000000000000000000000000000000000000000000000007d59f7b054aa6bc00 00000000000000000000000000000000000000000000000001044bbac12d5ad500000000000000 000000000000000000000000000000000000000000000000800000000000000000000000000000 00000000000000000000000000000000000140000000000000003b6d03407f8f7dd53d1f3ac105 2565e3ff451d7fe666a311ab4991fe000000000000000000000000000000000000000000000000e5
其中,合约方法识别符为合约方法经过 SHA-3 哈希算法后保留前八个字符得到的。因此,虽然我们不知道合约源码,但是根据前八位的识别符,我们可以在其它已知方法源码的记录中匹配到该方法:
swap(string aggregatorId, address tokenFrom, uint256 amount, bytes data)。
由于智能合约中的方法经常会被复用其他合约中,因此同一个方法(识别符)可能对应多个合约。
图 7:输入数据解析
3. 第三个标签事件日志 (Log) 是什么?它的作用在哪里?它们都会记录在区块链上吗?
在一个合约源码中,不仅会定义合约方法 (function),还会定义事件 event abc() 和提交事件 emit abc(),执行过提交的事件就会被记录在日志中,最后日志会被记录在一个调用合约的交易的 receipt 函数中。我们以 SushiSwap 的合约0x7f8F7Dd53D1F3ac1052565e3ff451D7fE666a311的源码为例,他们定义了 Sync 事件,还会提交该事件并记录在日志中。
图 8:SushiSwap 合约部分源码
然而,在日志中存储事件并不是为了日后可以被智能合约访问,**智能合约是不能监听 (listen) 到日志中的数据的。**事实上,事件用于通知外面的用户区块链上发生的事情。例如,当你在以太坊地址上收到一笔 Token 时,钱包的接口就会为你推送一条到账提醒,这实际上是钱包的前段接口监听到了链上发生的一个事件。由于事件提交事件的代码在合约源码中,它的执行也是以去中心化的方式进行,且最终被保存在区块链上。因此,日志中的数据是可信的。另一个开发者使用事件的原因是日志是一种更便宜的存储方式,日志中存储数据的成本大约是 8 gas/byte,而在合约变量中存储数据的成本为 625 gas/byte。
图 9:0x513d 和 Metamask Router 合约交易事件日志标签页
为了描述事件,一条日志通常会包含几个有索引 (Indexed) 的 Topic,和没有索引的 Data。其中,Topic0 为通常包含发生事件名称的签名 (keccak256 哈希值),包括其参数的类型 (uint256,字符串等)。还是以上面 0x513d 和 Metamask Router 合约交易为例,红字部分的日志中记录了在执行 SushiSwap 合约时在日志中记录的事件。
[Topic0]:0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1
就是将事件 Sync (uint112 reserve0, uint112 reserve1) 运行 Keccak256 算法得到的。另外,…1f0f 和…d552 是事件中的两个参数。
我们调取了 OKLink 全节点一整年的事件日志(2021.3.15-2022.3.16),我们看到 Transfer 的事件是最多的,上面分析的 Sync 事件排名第三~
图 10:事件方法排名
四、小结
在本文中,我们从两种交易类型的概览入手,分析了外部账户地址之间的交易数据和外部账户地址触发的合约方法执行过程。两种交易都包含交易索引、对手方、交易金额和成本。合约交易中,合约方法的调用过程除了在发起方和接收方之间的一次会被区块链记录,其它合约内部的调用过程均不上链,只有执行的结果和提交事件会被记录在区块链中。