以太坊支付是这样运作的
wxf2017
发表于 2022-12-27 19:21:04
88
0
0
& @$ E& K* Q) G3 A8 v
以太坊有一个非常重要的概念是费用的概念。因在以太坊网络上交易而消耗的计算都会产生费用,正所谓天下没有免费的午餐。支付的费用以“gas”来计算。
# k% L4 h/ v5 |
gas是用于衡量特定计算所需费用的单位。gas价格是你愿意花费在每单位gas上的Ether总量,用“gwei”来衡量。“Wei”是Ether的最小单位,1^018 Wei代表1 Ether。1gwei是1,000,000,000Wei。) h$ M* S& @$ Y& y$ f+ H
7 o7 |! ~* |' H. d
每次交易,交易发送人(转账人)都会设置gas的limit和gas价格。gas价格和gas limit代表了发送人愿意为交易支付的最大数量的Wei。例如,我们假设发送人设置gas limit是50,000,gas价格是20gwei。这意味着交易发送者愿意支付最多50,000*20gwei=1,000,000,000,000,000Wei,也就是0.001Ether用来执行该交易。
请记住,gas limit代表了交易发送人愿意支付的最大费用。如果他们的账户余额可以覆盖这个最大值,就不会有问题。交易结束时,发送人会收到未被使用的gas资金退款,并按最初价格交易。
如果交易发送人没有提供足够的gas来执行交易,交易会用光gas,并且该交易无效。在这种情况下,交易过程中止,发生的任何状态更改都会被逆转,这样交易会结束,并回到交易前的以太坊状态。此外,还会记录交易失败,显示什么交易试图发起并在哪里失败。同时,既然在用光gas之前,机器已经花费了努力进行计算,逻辑上来说,这些花费的gas不会再退还给交易发送人。" h" U( X1 R V& o- f' \! f
gas资金到底去哪里了?交易发送人花费的所有gas资金都被发送到“受益人”地址,这通常是矿工的地址。既然矿工花费努力来计算和验证交易,矿工收取gas费用作为奖励。
6 P9 ?8 `0 u a/ w* `
通常,交易发送人愿意支付的gas价格越高,矿工从交易中获得价值越大。因此,矿工也会选择价格高的交易。这样,矿工自由选择他们愿意验证的交易。为了引导交易发送者设置gas价格,矿工可以选择宣传他们会执行交易的最低gas价格。) C7 ]. q- J' p; J) N0 L" a% ]; I, Y
, G4 W+ @/ u9 C6 `2 _
存储也需要费用。- S; U$ _1 d$ [5 M$ o/ H/ k
4 Z" @7 g; c% d8 b
gas不仅用于支付计算步骤,也用于支付存储费用。存储所需的总体费用跟使用32字节的最小倍数成正比。5 O; w7 N, S- V& i' u$ k
存储的费用有一些细微差别。比如,既然不断增加的存储增大了所有节点的以太坊状态数据库的大小,那么有动机来保持小的数据存储量。因此,如果交易具有可以清除存储中的条目的步骤,则免除执行该操作的费用,并且为了释放存储空间还可以退还费用。: y" b* k8 m* W. ~" a
费用有什么目的?7 `# n! Z0 l3 t2 W% t% Z9 \" S* N$ U1 @
以太坊运行的一个重要方面是网络执行的每个操作都同时受到每个全节点的影响。然而,在以太坊虚拟机上的计算步骤是非常昂贵的。3 L5 A& g; Z# T) N) R& Z2 N0 Q. U- k- ^
因此,以太坊智能合约最适用于简单任务,例如运行简单的商业逻辑或验证签名和其他加密对象,而不是更加复杂的用途,如文件存储、邮件、机器学习等,这些会给网络带来压力。征收费用可以防止用户过度使用网络。
以太坊是图灵完备的语言。简言之,图灵机是能够模拟任何计算机算法的机器。这允许循环,并使以太坊容易受到停顿问题的影响,这个问题让你无法确定程序是否会无限运行下去。如果没有费用,恶意行为者能够轻易尝试破坏网络,方式是通过在交易中执行无限循环却不用担心成本。因此,费用可以保护网络免受恶意攻击。你可能会想,“为什么我们还需要为存储付费?” 好吧,就像计算一样,以太坊网络上的存储也有成本,整个网络不得不为此承受负担。
! `1 w: t1 ]8 S$ q! I
交易和消息+ C7 v* `, Y& \2 G+ a
我们注意到以太坊是基于交易的状态机。换言之,发生在不同账户之间的交易推动着以太坊的全球状态从一个状态转换到另外一个状态。
3 f$ v' C" k1 |# u4 O, \% V& x
在最基本的意义上,交易是加密签名的指令,它由外部账户生成,并序列化,然后提交到区块链上。有两类交易:消息调用和合约创建(即创建新的以太坊合约的交易)。
所有交易包含如下部分,无论其类型如何:: u, @1 O/ f6 \
Nonce(随机数):交易发送人发送的交易数量的计数。(蓝狐笔记译注:跟比特币的Nonce概念不同。)
; t% Y, J" _* d9 z( E) h$ |3 L) R
Gasprice:交易发送人愿意为执行交易所需的每单位gas支付的Wei的数量。- H9 n6 u7 L0 F1 ~8 i; o
- r4 k0 j: e% k/ N3 m3 B: \0 \$ |0 G
Gaslimit:交易发送人愿意为执行交易支付的最大gas数量。数量是设置并预付的,在任何计算完成之前确定。
To:接收人的地址。如是创建合约的交易,合约账户地址还不存在,所以使用的是空值。
; ~, e+ m+ d9 U1 P3 |# w9 T" O
Value:从发送人转移到接收人的Wei总量。在创建合约的交易中,这个值作为新创建合约账户的初始余额。; s5 `3 |& [7 A- J- r
V,r,s:用于生成签名,该签名可以标识交易的发送人。
1 x# E: ? h; s3 d5 j
Init:仅用于创建合约的交易。它是EVM代码片段,可用来初始化新的合约账户。Init只允许一次,然后被抛弃。首次运行init时,它会返回账户代码的正文,这段代码与合约账户产生永久关联关系。
数据:仅用于消息调用的可选字段。它是指消息调用的输入数据(即参数)。比如,如果智能合约充当域名注册的服务,对合约的调用可能需要输入字段如域名或IP地址。/ ]4 L) `. q4 R" o6 g
# \( k" ^# N. {) b- e( t8 m& [
在账户的章节,我们了解到交易,如消息调用或创建合约的交易,这些交易总是由外部账户启动并提交到区块链。另外一个思考的方式是,正是这些交易在外部世界和内部以太坊之间起到桥梁作用。
但这不意味着这些合约不能跟其他合约沟通。存在于以太坊状态范围内的合约能够与其他同样范围内的合约进行对话。它们沟通的方式是通过“消息”或“内部交易”。我们可以将消息或内部交易看作与交易类似,主要区别在于它们不是由外部账户生成。相反,它们由合约生成。它们是虚拟对象,与交易不同,它们不会序列化并且只存在于以太坊执行环境中。
3 M& T5 z6 k4 R: F! c
当一个合约发送内部交易到另外一个合约,接收人合约账户的关联代码就会执行。7 F/ `' l: C0 }' {# i8 b5 F v
' F5 r) a% ^0 x4 h3 A
需要注意的是,内部交易或消息并不包含gaslimit。因为gaslimit是由原始合约的外部创建者来确定的,即是一些外部账户。外部账户设置的gaslimit必须足够高,以执行交易,这些交易包括了任何子执行,子执行也是由交易导致的。比如,合约到合约的消息。
. g i, X& f5 M: t7 G
如果,在交易和消息的链中,特定的消息执行耗尽了gas,消息的执行会还原,同时还原的还包括任何由执行触发的后续消息。然而,父执行无需还原。
区块. N# L- O1 Z. _9 F
所有的交易组成一起进入区块。区块链包含一系列链接在一起的区块。以太坊中,一个区块包含:( y7 k6 c4 ^9 ]
2 D$ H' l$ c" z# [# i- `/ R
区块头7 ~. ?8 J9 v$ w ~* U& E$ e
! B: I8 r% e8 J5 M8 u+ V- D
关于区块中包含的一组交易的信息% J: z" R3 z2 l$ e: b5 e3 h* ~) s6 w
. \: u1 Z& s) L
当前区块的ommers的一组其他区块头关于Ommers
ommer到底是什么?ommer是一个区块,它的父区块相当于当前区块的父块的父块。快速了解一下ommer用于什么,为什么区块包含ommers的块头?
. M+ b* t) o p, q
由于以太坊的构建方式,出块时间比其他区块链更短,比如它约15秒/区块,而比特币的出块时间是10分钟/区块。这让它拥有更快的交易速度。然而,更短出块时间的一个不足之处是矿工会发现有更多的竞争区块。这些竞争区块也称为“孤块”(即所挖出的区块并没有进入主链)。
ommers的目的是帮助奖励矿工包括这些孤块。矿工包含的ommers必须是“有效”的,意味着当前区块的六代之内或更小范围内。在六代之后,老旧的孤块不再被引用,因为包括较老的交易会让事情变复杂。
Ommer区块获得的奖励比全区块要少。尽管如此,对矿工来说,这依然有激励,让他们把这些孤块包括进来,由此收获奖励。
区块头
让我们回到区块。之前提到过每个区块都有区块头,它究竟是什么?4 P/ ~" E; w, p- p( p1 E2 }& {
区块头是区块的一部分,包括:6 K! E6 G( }+ D$ n3 M4 H/ ?
3 W6 m: s" ] F" B( q2 `7 B, ?
parentHash:父区块头的哈希值(这也是让区块连成链的原因)$ o7 Q6 s- O5 A2 Q# g
% m. M. H6 z' c9 m1 L( o8 X
ommersHash:当前区块的ommers列表的哈希值
受益人:接收挖矿费用的账户地址* c5 `# r4 H5 x% g$ Z: B: f
2 h* ]2 @8 |; g @
stateRoot:状态trie的根节点的哈希值(状态trie存储于区块头并且更方便于轻客户端验证状态的任何信息)
transactionsRoot:包含区块中列出来的所有交易的trie的根节点哈希值
receiptsRoot:包含区块中列出来的所有交易收据的trie的根节点哈希值
logsBloom:Bloom过滤器(数据结构),它包含日志信息' m9 N, {( g" W! q! t
difficulty:区块的难度级别2 w$ l* g- ~/ P
number:当前区块的计数(创世区块的区块号是0,此后的每个后续区块都按顺序增加)
gasLimit:当前的每区块的gaslimint
d3 j$ j1 @3 {9 r5 I3 O
timestamp:区块开始的unix时间戳0 m8 e6 ], ]- W9 D0 z+ J% H
extraData:跟区块相关的额外数据9 |8 } x8 n6 I* s: j4 Z; Q' A1 [
mixHash:也是一个哈希值,当它结合nonce时,证明该区块已经执行足够的计算- y$ ~& B: ?/ u! a& A! A
nonce:也是一个哈希值,当它结合mixHash时,证明该区块已经执行足够的计算) t2 M8 u/ i2 i% l$ z9 Z: }, |
. p$ Z& A2 `- H* R0 j4 V, p
注意每个区块头是如何包含三种trie结构:" U( O4 }$ `4 X
状态(stateRoot). X: @; X4 I$ [5 M% k+ W5 a9 @
2 t2 O3 T. Z! D* p- K5 y5 x$ T
交易(transactionRoot)6 |/ p5 \6 R) w/ T; V
收据(receiptsRoot)这些trie结构只是之前提到过的Merkle Patricia tries。此外,以上的描述中一些术语需要澄清。) K; X% ^6 Q9 Y6 Z ^2 B( ^
Logs
0 k+ ]* R8 K" |# s+ _- {7 M
以太坊允许logs,以便于追溯各种交易和消息。合约可以通过定义“事件”来清晰生成日志,这里的“事件”则是想要记录日志。
log条目包含:8 D. g1 O* P% h5 M* f( d
日志者的账户地址+ I- n. E1 z$ v6 O5 o0 r5 O
一系列的主题,这些主题代表本次交易执行的不同事件# L4 w" b5 \$ u J8 H3 T
9 E3 o, |& F ~! ^% y- E
跟这些事件相关的任何数据日志存储在bloom过滤器中,该过滤器以有效方式存储无尽的日志数据。
交易收据: X) Y3 k# K5 V3 S4 A
存储在区块头的日志来自于包含在交易收据中的日志信息。正如你在商店购物会收到收据一样,以太坊也会为每笔交易生成收据。正如你所期望的,每张收据都包含交易相关的一些信息。收据包含如下内容:( X+ n/ o/ {! _
: F) j# Y/ o! D; X/ |( D$ I: b, f
区块编号' i1 S1 u/ i2 j, J; X1 k7 \
区块哈希* C7 p' \1 a& K0 W z
交易哈希1 A. a! h m- H5 }2 y
! F2 n# S7 t+ d
当前交易使用的gas# }. A- ~& g2 ^' y: }6 x) a# k
当前交易执行后当前区块所使用的累积gas
当执行目前交易创建的日志
; X/ `5 D8 x! h9 V( C: y
......等等区块难度
$ b! P# k& ~* ~% X& U
区块的“难度”用于实现一致性,它可以让验证区块所花费时间基本一致。创世区块难度是131,072,此后用特别公式来计算每个区块的挖矿难度。如果某个区块的验证速度快于之前的区块,以太坊协议会增加出块难度。9 U7 ^4 U' A! M: q& q: F
: W! U3 Y* Z) t* U8 J: X' N
出块难度影响nonce,这是一个哈希值,矿工必须在挖区块时使用PoW算法计算出来。区块难度和nonce的联系在数学上可以形式化为:0 Y! `: q0 n: o I4 `' m
其中Hd是难度。$ o3 F( [" G' ~. M* ~+ T8 |( x
- R& T- q& _# j$ L" [5 r9 x+ @
找到满足难度阀值的nonce的唯一方法是使用PoW算法来穷尽所有可能性。找到解的期望时间跟难度成正比——难度越高,找到nonce的就越难,验证区块越难,这会导致验证新区块花费更长时间。所以,通过调整区块的难度,协议可以控制验证区块需要耗费的时间。
4 ^* v0 f& g2 R/ i, c- p
另外一方面,如果验证时间变长,协议就会降低难度。通过这种方式,验证时间自我调整,以此保持一个恒定速率——平均每15秒出一个区块。
& e" U- u! K3 b9 p
交易执行
) G8 A% D- i$ p4 W, ^8 T
我们来到以太坊协议中最复杂的部分之一:交易的执行。假定你发送一个交易到以太坊网络进行处理,将以太坊的状态转换为包含你的交易会发生什么?
u& U$ D- | o% k- f
首先,所有交易必须满足一组初始的设置要求才能执行。这些包括:) B- q: t( w3 b: F" M9 n4 T
交易必须是格式正确的RLP。“RLP”代表“递归长度前缀”,是一种数据格式,它用于编码二进制数据的嵌套数组。RLP是以太坊用于序列化对象的格式。+ `* F! _; J5 h2 a
, X5 H4 _1 R3 I
有效的交易签名
有效交易nonce。回想一下,一个账户的nonce是从该账户发送过来交易计数。为了有效,交易nonce必须等于发送者账户的nonce。( g& v. S& Y& Y" @& b) U
1 D- t& c L) \- x# Y
交易的gas limit必须等于或大于交易使用的固有gas。固有gas包括:1.为执行交易预先定义的成本21,000的gas
2.与交易一起发送的数据的gas费用(每字节数据或代码相当于零时则是4gas的费用,每非零字节的数据或代码是68gas费用)& A% l. \0 R; H4 _ _2 B% I, M
4 k Q. Q& e/ Z9 n1 c
3.如果交易是创建合约的交易,则额外增加32,000gas
/ \$ @: s% B: d5 T1 b4 e2 ?% n
发送人的账户余额必须有足够的Ether覆盖“预定”gas成本,这是发送人必须支付的。“预定”gas成本的计算是简单的:首先,交易的gas limit 乘以交易的gas 价格,可以得出最大的gas成本。其次,最大的成本被加入到总值中,总值是指从发送者转移到接收者的总价值。, }6 l, _1 D v
如果交易满足所有以上的有效性要求,我们继续下一步。
首先,我们从发送人的余额中扣除预定的执行成本,并将发送人的账户的nonce增加1以计入当前的交易。此时,我们可以算出剩余的gas,它们作为交易的总gas limit减去使用过的固有gas。
9 w+ e7 b" P- `1 i& a2 \% {
接下来,交易开始执行。在交易的执行过程中,以太坊跟踪“子状态”。该子状态是记录交易过程中产生的信息的方法,这些信息在交易完成后被立即需要。具体来说,它包括:7 q' Y' f5 ?& q( I: A2 ?# H
自毁集:在交易完成后被抛弃的一组账户(如果有)
" G: d, V7 @5 ~+ T
日志系列:虚拟机代码执行的归档及可索引的检查点。! L% X) y) w7 Z- U9 T9 r. `; e
5 T' {1 @4 m) A8 ]! P0 D8 r+ o
退还余额:交易后退还给发送人账户的金额。还记得我们提到的以太坊存储需要花费,并且发送人会为清理存储而退款?以太坊会使用退款计数器来跟踪此事。退款计数器从零开始,每次合约清除存储时会递增。接下来,处理交易要求的各种计算。2 w3 u7 Y M4 l6 W h
一旦交易要求的所有步骤都被处理完毕,假定没有无效状态,则通过确定要退还给发送人的未使用的gas金额来实现最终状态。除了未使用的gas,发送人还可以从上面提到的“退款余额”中获得一些补贴。
一旦发送人获得退款:
X( U* o' W! u( V; D$ u
gas的Ether已经给到矿工$ L% l; M7 D- I, x4 g* v
交易使用的gas被添加到区块gas计数器(它跟踪区块中所有交易使用的总gas,并在验证区块时有用处)3 B3 ^' Z5 D4 ~2 C3 s
8 S* _: t. J7 W" S( B% x
在自毁集中的所有账户都将被删除(如果有的话)最后,我们留下新的状态和一组交易创建的日志。现在我们已经介绍了交易执行的基础知识,让我们来看创建合约的交易和消息调用之间的一些区别。
成为第一个吐槽的人