前言

以太坊是新兴的区块链技术平台,其目标是成为“永不停机的世界计算机”,人们在其上可以部署各种应用供全世界使用。以太币是以太坊公链这台虚拟世界计算机器运行的“燃油”(以太坊英文名Ethereum词根eum含有燃油的意思),其理念是以太坊平台运行需要消耗资源,比如各节点的CPU、存储、带宽等资源,而这些资源消耗由以太坊平台给以计量和计价,并通过挖矿时对矿工的奖励给予补偿,这种奖励同时也是以太币去中心化的发行机制。

一、以太坊转账手续费的特点

对资源消耗的计量和计价,在以太坊中有专有的名词,叫某笔交易的gasUsed和gasPrice。前者体现了这笔交易消耗了以太坊这台虚拟世界计算机的资源的量(比如多少CPU时间之类),后者体现了这笔交易消耗的资源的量的单位价格(比如每单位CPU时间值多少以太币)。用开车打个比方,比如你出去旅行一趟,过程消耗燃油20升,当前油价每升6元,相当于你这次旅行的燃油成本是(20升 * 6元每升 = 120元)。同样地,一笔以太坊交易的手续费,其计算公式就是:

交易手续费Fee(单位:以太) = 过程油耗gasUsed * 当前油价gasPrice

以太坊交易的手续费,有三个特点,值得注意:

  1. 手续费和转账金额无关。不像银行,转钱越多手续费越高。
  2. 手续费给谁事先是不知道的。不像银行,手续费肯定是给银行的。
  3. 费用不会固定。由于油价gasPrice的实时变化,经常是相隔几分钟的交易,其消耗的手续费都是不同的。

例如给4位同事转以太币,每个同事2个以太币,实际情况取截图说明。如下交易都是相隔较短时间内相继完成的。

  1. 交易编号:0x1ed1dbbe611cbaf6447aab61165b4d5ff49c061cad7665d6a23ec8df346412d1 (给A同事,价格10 Gwei每单位油耗)

  1. 交易编号:0x0b6e798951aa7786b6484df6e2924489af338c9dbb8c30bd64c9954e56ea55c0 (给B同事,价格7 Gwei每单位油耗)

  1. 交易编号:0x7df8116e1825c944f260e71ab8f0e00da6e45859afa7a196ebe7258656f31d60 (给C同事,价格12 Gwei每单位油耗)

  1. 交易编号:0xa9787e69f484329723dbb46b0c446f1756301c28e70929fda5f358958ebbee50 (给D同事,价格9 Gwei每单位油耗)

如上记录的发给4位同事的交易记录表明同样类型的交易但金额不同;每次油耗都一样,但是油价却不一样。看来,以太坊交易的gasPrice就像现实生活的油价,也会起起落落,取决于计算资源和交易量之间的供求关系。

  • 手续费具体的计算和扣收过程

一笔交易,手续费计算有3次,最后进行扣收。

  1. 第一次检查是交易pending的时候,这时候的手续费计算是简单看其余额是否足够支付手续费,是单个交易的模拟检查,并没有将这笔交易纳入到整个区块的整体中计算

|--JsonRpcImpl.eth_sendTransaction(CallArguments args)

|---前端新发一笔交易请求到节点时的程序入口

|----EthereumImpl.submitTransaction(tx)

|-----节点接收到后,进行初步的数据非空检查后创建一个Transaction对象并提交

|------pendingState.addPendingTransaction(transaction)

|-------节点新建一个广播任务,将交易异步广播出去;并加入本地的待确认交易表

|--------PendingStateImpl.addPendingTransactionImpl(final Transaction tx)

|---------对该笔交易进行验证,各数据项格式是否符合要求,并起模拟环境验证

|----------PendingStateImpl.executeTx(tx)

|-----------该处执行交易沙盒验证,因为是单笔交易验证,会创建一个假区块

|-----------假区块中无其他交易,已发生油耗也设为0,这样只校验单笔是否超标

2)第二次检查是区块挖出前进行模拟计算,这时候就是一个区块的整体了,除了检查账户中是否有足够支付单笔交易手续费的余额,还看区块中所有交易的手续费加起来是否超过区块的手续费总额限制,检查开始有了整体观

3)第三次检查及最后的手续费扣收,是区块挖出后的实际执行,检查限制是同第二次,但这时候是实际扣缴了,而且就算合约交易在虚拟机中执行失败,手续费是照旧扣收的

如上第2、3小点流程基本一致,区别在于执行环境是否为真,调用关系如下:

|----BlockchainImpl.createNewBlock(parent, txs, uncles, time)

|-----第2点中,创建新区块时需要模拟校验该手续费情况,沙盒执行

|----BlockchainImpl.addPendingTransaction(transaction)

|-----第3点中,区块挖矿出来后最终执行交易,扣收手续费,真实环境执行

|--------BlockchainImpl.applyBlock(repo, block)

|---------传入执行环境和当前块,对区块中的交易进行验证

|----------for (Transaction tx : block.getTransactionsList())

|-----------对于区块中的每笔交易进行手续费的检查并执行

|-----------2、3小点区别在于前者是模拟执行环境,后者是真是执行环境

以太坊交易过程中有4个重要的函数,分别是:init()、execute()、go()、finalization()

(图全貌见附录)

对应的手续费有3个动作:

  • 事前:真正开始交易钱先检查手续费,这时候要计算一次手续费,看账户中余额是否够手续费
  • 事中:交易过程中对手续费的扣缴,因为以太坊交易分3类,普通转账,合约创建,合约执行,这3种口手续费的地方都不一样
  • 事后:最后一次计算,有手续费剩余的时候(leftover),这部分预交冻结的手续费要返回给发起者

注意,上述手续费检查的限制都是针对gas量,最终手续费的计算还要乘以gasPrice。

针对这部分的代码分析:

四个变量:

  1. currentBlock.getGasLimit() 动态的本区块所能消耗的gas量的限制
  2. gasUsedInTheBlock 简单累加计算得到的本区块已经消耗的gas量
  3. tx.getGasLimit() 复杂计算统计各个指令得到的本交易所能消耗的gas量
  4. basicTxCost 读取配置得基本交易gas量

两个判断关系:

1)如果:(tx.getGasLimit() + gasUsedInTheBlock) > currentBlock.getGasLimit()

则提示:Too much gas used in this block:

业务含义是本区块已经消耗的gas,加上本交易消耗的gas如果超过了整个区块的gasLimit,就报错

2)如果:txGasLimit.compareTo(BigInteger.valueOf(basicTxCost)) < 0

则提示:Not enough gas for transaction execution: Require: basicTxCost Got: txGasLimit

业务含义是如果这个交易消耗的gas,太大了就超出了区块的gasLimit,如果太小了就不符合最低交易手续费的要求

  • 手续费中油耗是如何计算的

以太坊不像比特币那样,手续费统一,因为以太坊设计成可以运行智能合约,而各个智能合约其消耗的资源显然是不一样的,所以不能收统一的手续费。故而,以太坊将各种基本操作分类,评估每个细节操作的耗费,汇总起来就是一个指令的油耗

如何计算见《以太坊黄皮书》中附录,费率表:

不同种类指令有不同的费用,目前最贵的合约创建,花费32000单位的油耗,最便宜的跳转指令只要花费1单位的油耗,最贵最便宜资源消耗量相差了32000倍!

最常用的交易指令就是普通的转账交易,按下表定义是21000个单位的油耗,之前的实际操作例子也显示确实是21000单位的油耗。

  • 手续费中油价的形成机制

以太坊的油价是每时每刻在变动的,如果你打开以太坊钱包的客户端,比如Mist,打开转账界面,在未输入金额等要素的时候,钱包就已经显示了本次手续费,并随着油价的变动,页面会刷新并发生变化。

那么油价的形成机制是怎么样的呢?有点类似于股票交易所的股票报价。

首先,油价由矿工节点生成。

其次,矿工是根据待确认交易池中的交易列表,按gasPrice进行排序,考虑历史区块的影响后,最终取一个中间值并发布生成的。由于新交易不断的涌入,各交易gasPrice报价可能不同,从而产生不断变化的gasPrice报价。

|--GasPriceTracker.onBlock

|---每当一个新区块加入区块链时,就用区块中的交易的gasPrice计算更新本类参数

|----GasPriceTracker.onTransaction

|-----该类有长度为512的价格池,每笔价格从后往前加入池,加满则循环覆盖

|------GasPriceTracker.getGasPrice

|-------另一个线程负责发布实时油价

具体如何综合价格池中价格发布一个油价,代码如下:

public long getGasPrice() {
      if (!filled) { //如果始终没有交易,则返回默认油价
          return defaultPrice;
      } else {
          if (lastVal == 0) { //若该标志为0,则重新计算油价,这标志是价格池满时设置的
            long[] longs = Arrays.copyOf(window, window.length);
            Arrays.sort(longs); //排序
            lastVal = longs[longs.length / 4];  // 取第25% percentile位置的油价
          }
          return lastVal;
      }
    }

有个专门统计以太坊油价的网站:http://ethgasstation.info/,图形化方式展示了油价变化。

  • 以太坊手续费发挥的经济调控作用

以太坊手续费不单纯是个技术问题,更是一个经济学问题。前面文章提到过,我们可以把以太坊当作一台超级计算机,而智能合约是这个计算机上运行的程序。因为这个计算机不是我们自己的,更像一台我们在网上租用的服务器,因此,我们想使用的话必须花费成本。

如果gas使用得越多,而gasPrice价格不变的话,使用以太坊搭建分布式应用的成本将会越来越高(上图等式cost越来越大)。而实际上,以太坊为了解决这个问题,特地将ether(ETH的单位)与gas进行解耦,保持gasPrice与ether的一种动态变化,使得ETH价格大幅上涨时,gasPrice价格下降(以ether计算的价格);ETH价格下跌时,gasPrice价格上升(以ether计算的价格)。这样才能使得使用以太坊的成本处于一个合理的、不会大幅波动的范围。

以太坊gasPrice的动态变化图:

之前以太币价格低,gasPrice相对比较高,随着以太币的升值,gasPrice价格下降,维持了以太坊运行成本保持稳定,发挥了市场的调节作用。

另外,比特币目前遇到扩容问题,因为刚开始设计时的考虑不足,比特币的手续费未能像以太坊那样进行起动态调节的机制,目前遇到交易拥堵的问题,交易体验远不如以太坊。因此比特币社区目前在讨论扩容问题。而以太坊就没有这个问题,以太坊的gasLimit可以动态调整,容纳交易的能力也可以动态扩展,如下是截稿时,最新10个区块的交易数量:

最新区块(第300多万个)的交易容纳量可以达到100级别,而比对刚开始的第13万个区块附近的交易容量和gasLimit如下:

gasLimit从3141592增长到4712394,交易容量相应增加,由此可见,以太坊自身可以动态调整容量,适应了交易量增加的需求

附件:以太坊交易整体过程:

  • 公链调用实验:为了弄清楚以太坊公链上部署合约和调用,实际上花多少钱,进行了如下真金白银的实验:

目前调用了5次,费用每次约10元人民币左右。

注:由于gasPrice等因素,每次调用花费不一样,综合同事们提供的调用费用,列举如下:

调用次数

手续费(Ether)

1

0.0058

2

0.0052

3

0.0048

4

0.0049

5

0.0079

目前以太坊上的合约调用活动已经比较频繁,各种合约账户达75万个(也就是有75万种合约),区块链应用呈现落地的趋势。如下是调用存证系统时,同区块的其他调用合约的交易。

以太坊手续费详细分析相关推荐

  1. 3 v4 中心节点固定_死磕以太坊源码分析之p2p节点发现

    死磕以太坊源码分析之p2p节点发现 在阅读节点发现源码之前必须要理解kadmilia算法,可以参考:KAD算法详解. 节点发现概述 节点发现,使本地节点得知其他节点的信息,进而加入到p2p网络中. 以 ...

  2. 以太坊源码分析-交易

    以太坊源码分析-交易 机理 先说一点区块链转账的基本概念和流程 用户输入转账的地址和转入的地址和转出的金额 系统通过转出的地址的私钥对转账信息进行签名(用于证明这 笔交易确实有本人进行) 系统对交易信 ...

  3. php区块链以太坊,兄弟连区块链教程以太坊源码分析CMD深入分析(一)

    兄弟连区块链教程以太坊源码分析CMD深入分析. cmd包分析 cmd下面总共有13个子包,除了util包之外,每个子包都有一个主函数,每个主函数的init方法中都定义了该主函数支持的命令,如 geth ...

  4. kademlia java_死磕以太坊源码分析之Kademlia算法

    死磕以太坊源码分析之Kademlia算法 KAD 算法概述 Kademlia是一种点对点分布式哈希表(DHT),它在容易出错的环境中也具有可证明的一致性和性能.使用一种基于异或指标的拓扑结构来路由查询 ...

  5. Merkle Patricia Tree (MPT) 以太坊merkle技术分析

    转载自:https://blog.csdn.net/zslomo/article/details/53434883 一 传统merkle树缺陷 我的这篇博客merkle tree 分析 详细解释了me ...

  6. 《迅雷链精品课》第七课:以太坊数据存储分析

    上一节课我们学习了比特币的区块链数据存储,接着前一篇的内容,我们继续了解以太坊的相关内容.业界一直把以太坊认为是区块链发展进程中2.0的代表,因为它在比特币的基础上增加了图灵完备的智能合约,扩展了区块 ...

  7. 以太坊RLP机制分析

    目录 1 RLP 定义 2 RLP 编码规则 3 RLP 编码实例 4 RLP 分析 1 RLP 定义 RLP,即 Recursive Length Prefix, 递归长度前缀编码,是以太坊数据序列 ...

  8. 以太坊源码分析之随心笔记

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 以太坊索引 table.go 定期随机选取一些节点找他们要他们的节点,放到本地,也就是一个随机找节点的table 里头的 ...

  9. go-ethereum-code-analysis 以太坊源码分析

    分析go-ethereum的过程,我希望从依赖比较少的底层技术组件开始,慢慢深入到核心逻辑. 目录 go-ethereum代码阅读环境搭建 以太坊黄皮书 符号索引 rlp源码解析 trie源码分析 e ...

最新文章

  1. android c聊天功能,Android实现简单C/S聊天室应用
  2. ZeroMq实现跨线程通信
  3. 万字干货|逻辑回归最详尽解释
  4. c++ builder 读取指定单个名称节点的值
  5. GridView绑定数据源 绑定DataReader /DataSet /DataTable
  6. CentOS 5.2 安装Apache服务器后无法访问解决方法
  7. 【Hbase】eclipse下远程调试Hbase
  8. .net MVC Model
  9. 309. zui佳买卖股票时机含冷冻期(JavaScript)
  10. mysql_real_connect段错误,mysql的多线程安全问题:在mysql_real_connect时出现段错误。...
  11. 我的地盘我做主—玩转Python函数和变量
  12. 机器人读懂人心的九大模型
  13. 计算机改硬盘格式,预装win10改win7硬盘格式怎么改_win10改win7分区格式如何转换...
  14. roundcube db.inc.php,开源电子邮件系统(Roundcube Webmail)
  15. 直播系统 java_直播系统软件定制开发
  16. 计算机中 加减运算 的 实现原理
  17. Weak Pointer
  18. 感应加热电源-谐振移相-感性移相
  19. python朋友圈自动点赞_基于airtest的朋友圈自动点赞
  20. 各个国家 不同字符集的unicode 编码范围

热门文章

  1. 数字电视标准ATSC,DVB的比较
  2. Android -- XML属性
  3. linux 有线链接树莓派,linux-通过公共互联网连接到树莓派
  4. GitLab更换IP地址报错解决
  5. JSD-2204-创建Spring项目-Day19
  6. PCB各种表面工艺差异说明
  7. ThinkPad T480 Win10系统键盘失灵
  8. 关于PADS 9.5导入CAD图(dxf文件)的说明
  9. 使用DiskGenius扩展C盘大小,遇见“您选择的分区不支持无损调整容量”
  10. 计算机网络面试题总结之一