前言:

在使用solidity写智能合约的时候,会使用到revert和require来进行断言,比如:

require(tokenOwner[tokenId] == 0x0,'this is not the first create');

在上面的断言中,只有当你满足了tokenOwner[tokenId] == 0x0这个 条件,你才能继续往下执行,否则就会报错“this is not the first create”。

然后当我们使用remix这个编译器的时候,是能够在出错的时候得到reason string这个错误信息的,如下:

Transact to  token.create errored:VM error:revert.
revert The transaction has been reverted to the initial state.
Reason provided by the contract: “this is not the first create”. Debug the transaction to get more information.

在remix-ide中当transaction出错,即require断言没通过时,在terminal处会返回这样的信息,但是如果你在geth私有链中运行的时候,你只能知道你的transaction失败了,但是这个时候我们更多的是希望知道是哪里出错了,而不是仅仅得到交易失败的结果。

目的:

就是查找如何能够在使用geth搭建的私有链及web3js来实现revert/require的reason string的获得。

过程:

首先去查看了remix-ide的源码,然后发现这个返回的错误信息是通过读取获得的
网址:https://github.com/ethereum/remix/blob/73849adc6bf0eb5f1b8198842cfb9a8f417264b9/remix-lib/src/execution/txExecution.js

然后在GitHub中的EIP758(https://github.com/ethereum/EIPs/blob/master/EIPS/eip-758.md)可以看见这的确是一个没有实现的功能,就是在remix中能够返回require和revert中的信息,但是geth是会把这个信息直接扔掉的。除此之外,从EIP758也知道,如果你智能合约中的函数有返回值(return data),那么也是会被抛弃的。

⚠️但是EIP758一直讲的都是return data的问题,但是很多地方谈reason string的时候又把他们合在一起,可能两者的实现是一起的吧!!!!!
这个好像就是大家也都发现的问题,就是geth是会把内部得到的返回值(或者require和revert中的信息reason string)信息直接扔掉的,但是后面EIP758提出了解决了这个问题的方案:
This EIP proposes that callers should be able to subscribe to (or poll for) completed transactions. The Ethereum node sends the return data to the caller when the transactions are sealed.
目前如果当你的函数是通过eth_sendTransaction or eth_sendRawTransaction RPC request来执行的,那么外部访问者是没有方法获得return data的。

解决方法是在web3js中的函数eth_subscribe中添加查看交易的return data的功能,详细情况自己看。

后面在GitHub中的确有看见别人问和我一样的问题:https://github.com/ethereum/go-ethereum/issues/15721,是2017/11/21号的时候问的,那时候是说还没有办法:
Directly - not yet, pending ethereum/solidity#1686.
You should be able to step it through a debugger, like the one in Remix.
您应该能够通过调试器进行调试,比如Remix中的调试器。其实就是使用remix,但我就是想知道能不能用geth。

参考:https://github.com/ethereum/go-ethereum/pull/16424

https://github.com/ethereum/EIPs/issues/963

这里有详细解释了要如何实现EIP758这个提案:
This functions in two different ways,:
one via the JSON-RPC command eth_subscribe. If the client has a full-duplex connection (ipc or ws), it can issue an eth_subscribe command with params= [“returnData”].For any transactions submitted by the same client after that, the tx hash is saved internally while the transaction is pending, and the appropriate client is notified when it completes.
就是如果你的连接方式是ipc or ws,那你就可以使用命令eth_subscribe,参数指定是“returnData”,即返回信息。然后当交易pending的时候,tx hash并不会给你,而是会保存在内部,直到成功写上区块的时候才会通知你信息
the client has only a half-duplex connection (http), then eth_subscribe is not allowed since there are no callbacks. Instead, eth_newReturnDataFilter is sent, the return data of subsequent transactions are stored up in a queue internally, and returned to the client when eth_getFilterChanges is called with the same subscription id.
如果你使用的是http的话,就不能使用命令eth_subscribe,要变成使用eth_newReturnDataFilter,并且返回数据会以队列的形式保存在内部,知道你调用命令eth_getFilterChanges才会返回给你,不像上面那个直接给你

My proposal is to add a from field in the params of eth_newReturnDataFilter, so that they only listen to transactions sent from a specific address, or a list of addresses--not everyone's transactions. (I've also mentioned an alternative of adding a subID param to eth_sendTransaction and eth_sendRawTransaction, which would also solve the problem.)
就是eth_newReturnDataFilter会监听所有的返回数据,可以通过设置{from:…}来限制只监听哪个from的返回数据,或者在发送数据时(即使用eth_sendTransaction和eth_sendRawTransaction)添加subID参数??

Another improvement I plan to add soon is an optional bool param noEmpty, which can suppress notifications for transactions where there is no return data. For noEmpty=false, the client will still be notified when the requested transactions complete, but the return data field will be []
noEmpty=true,就是在当没有返回数据时就可以不用返回东西,否则仍会返回一个[]空数组

因为EIP758的status是Draft,说明该建议在ethereum还没有真正实现,还在实现中,我们只好等待了!!!!!!

EIP Status TermsDraft - an EIP that is undergoing rapid iteration and changes
Last Call - an EIP that is done with its initial iteration and ready for review by a wide audience
Accepted - a core EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author
Final (non-Core) - an EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author.
Final (Core) - an EIP that the Core Devs have decide to implement and release in a future hard fork or has already been released in a hard fork
Deferred - an EIP that is not being considered for immediate adoption. May be reconsidered in the future for a subsequent hard fork.

这个建议的依据是EIP 658:

https://github.com/ethereum/EIPs/blob/master/EIPS/eip-658.md

EIP 658是建议将return data写到 transaction receipts,但是这样会导致 return data is not charged for (as it is not stored on the blockchain), so adding it to transaction receipts could result in DoS and spam opportunities.
所以最后的解决方案是在transaction receipts加上一个状态status,通过eth.getTransactionReceipt()查看,status为0x0,则交易失败;status为0x1,则交易成功。该建议的status是final,说明已经实现。

但是后面有其他的惊喜:
https://github.com/trufflesuite/ganache-core/issues/116
https://github.com/trufflesuite/truffle/issues/976

在这里我们能够发现现在ganache-core和truffle的新版本v5.0(beta)已经实现了能够查看reason string的功能,但是我还没试过,大家可以自己去看看(但是我就是想使用geth的)

  • Remix gets the reason string because it runs ethereumjs-vm in the browser and can just grab the return data directly out of the vm. The clients' default behavior is to throw that data away rather than include it in the response, so we need changes at that layer to be able to do the same thing.

  • Ganache just merged a PR last week that attaches return data to the error message on eth_call. That change is queued for the next release. As soon as it becomes available we'll begin work on integrating this into the next version of truffle-contract.

通过查看ganache-core的代码来看它是如何实现这个操作的:

https://github.com/trufflesuite/ganache-core

感觉自己好像低估了ganache的功能,后面好好学学。

最终:

终于查明这个功能还没有实现,只能等待了
https://github.com/OpenZeppelin/openzeppelin-solidity/issues/917

web3.js is not the culprit. There is actually no way to retrieve the revert reason from a node. EIP 758 is a proposal to solve that, and there's Geth (ethereum/go-ethereum#16424) and Ganache (trufflesuite/ganache-core#116) issues to implement it.

即上面提到的:
https://github.com/ethereum/go-ethereum/pull/16424(ethereum/go-ethereum#16424)

https://github.com/trufflesuite/ganache-core/issues/116(trufflesuite/ganache-core#116)

I guess we'll have to wait and see how that plays out.

looks like truffle 5.0 will allow for this to be possible: see the relevant beta release notes.

https://github.com/trufflesuite/truffle/releases/tag/v5.0.0-beta.0#reason-strings(truffle的新版本)

truffle v5.0.0-beta.0 是如何解决这个问题的呢:

Revert with reason strings!!

Find out the reason. At the moment this feature is only supported by the ganache-cli client (>= 6.1.3). Parity and Geth are still working out their implementations.

Solidity中运行:

require(msg.sender == owner, 'not authorized');

再在Javascript中运行

try {await example.transferToSelf({from: nonOwner})
} catch (err) {assert(err.reason === 'not authorized');assert(err.message.includes('not authorized'); }

软件版本阶段说明

Alpha版: 此版本表示该软件在此阶段主要是以实现软件功能为主,通常只在软件开发者内部交流,一般而言,该版本软件的Bug较多,需要继续修改。Beta版: 该版本相对于α版已有了很大的改进,消除了严重的错误,但还是存在着一些缺陷,需要经过多次测试来进一步消除,此版本主要的修改对像是软件的UI。RC版: 该版本已经相当成熟了,基本上不存在导致错误的BUG,与即将发行的正式版相差无几。Release版: 该版本意味“最终版本”,在前面版本的一系列测试版之后,终归会有一个正式版本,是最终交付用户使用的一个版本。该版本有时也称为标准版。一般情况下,Release不会以单词形式出现在软件封面上,取而代之的是符号(R)。

所以该truffle的beta版还是测试版

其他:

(1)

一开始以为eth_subscribe已经实现了上面的功能,所以去查看并希望使用web3的1.0版本,在这里遇见了个问题:为了实现上面的函数eth_subscribe,来获得solidity中require里的断言失败信息:

新生成一个文件remix-revert,将之前运行智能合约的文件夹中的package.json复制粘贴过去,然后将里面的web3版本改为1.0.0,而不是还使用0.20.1,然后使用npm init来把package.json中的模块都安装下来。但是后面发现这样不能成功,老是报错,所以打算还是直接一个个安装吧。

npm init :生成package.json
安装时出现了这样的错误:
npm ERR! Unexpected end of JSON input while parsing near ‘...xpress/-/express-2.1.
解决方法是:
npm cache clean —-force

为什么要改web3
因为要试着使用web3.eth.subscribe(“pendingTransactions”)来获得solidity中require中的信息,但是这个是1.0版本才有的功能,0.20中报错

(2)
再后面我看见一个问题就是有人问他发现就是如果使用了reason string,它所使用的gas会变得很高,就是使用reason string是一件十分奢侈的事情:
https://github.com/ethereum/solidity/issues/4588

It will not be part of storage, but more likely be stored as a combination of push and mstore
原因可能就是在编译的过程中,需要将这些reason string压到内存当中,这个过程当然是会花费gas的。所以我的交易总是频繁地出现out of gas的原因很有可能就是使用了require的reason string的原因了,所以我的tx的gas才会这么高

https://github.com/ethereum/solidity/issues/4774

说明gas高的原因
Currently all strings are broken up into 32 byte items, PUSHd and MSTOREd.
The helper function CompilerUtils::storeStringData is doing this, however it has a fixed rule for only doing it for >128 characters.
It should be exposed to the optimiser (or user) to decide based on cost.

转载于:https://www.cnblogs.com/wanghui-garcia/p/9560217.html

solidity return data和revert/require的reason string的获得相关推荐

  1. 定义类MyProgram,包含两个属性:一个是private的整型属性data、一个是private的String类型属性str,重写toString,equals

    题目: 定义一个类MyProgram,包含两个属性:一个是private的整型属性data.一个是private的String类型属性str,封装这两个属性的四个方法setData( )和getDat ...

  2. Unknown integral data type for ids : java.lang.String; nested exception is org.hibernate.id.Identifi

    1.发生的异常内容: org.springframework.orm.hibernate5.HibernateSystemException: Unknown integral data type f ...

  3. 运行fis3 server start --type smarty启动时,报错The “data“ argument must be of type string or an instance of

    运行fis3 server start --type smarty启动时突然,报错The "data" argument must be of type string or an ...

  4. vue学习:vue中data和return data的区别

    在简单的vue实例中看到的Vue实例中data属性是如下方式展示的: let app= newVue({ el:"#app", data:{ msg:'' }, methods:{ ...

  5. 内置对象 API Math对象、Data对象、Array对象、String对象

    Javascript分三种对象:自定义对象.内置对象.浏览器对象 前两种对象是JS基础内容,属于ECMAScript:第三个浏览器对象属于我们JS独有的. 内置对象: 就是指JS语言自带的一些对象,这 ...

  6. php逆波兰表达式,PHP根据数字的字符表达式计算出结果(转换成逆波兰式再求解)[转]...

    这个简单的计算器采用的是逆波兰式来做的,仅支持加减乘除四种运算,纯粹个人练习记录一下,还望多多支持. 用法 require 'Calc.php'; $calc = new Calc('(1+9)/2' ...

  7. python递归函数的意思_Python 递归函数

    一.函数执行流程 示例.png 全局帧中生成 foo1.foo2.foo3.main 函数对象 main 函数调用 main 中查找内建函数 print 压栈,将常量字符串压栈,调用函数,弹出栈顶 m ...

  8. koa --- [MVC实现之五]Model层的实现

    说明 上一篇: MVC实现之四 这一篇主要介绍: 项目中用到的Sequelize库中的一些方法,参考使用Sequelize连接mysql 将Model层加入Mar类中 Service层 还是从业务出发 ...

  9. 微信公众平台开发4-长链接转短链接口调用实例(含源码)

    微信公众平台开发-access_token获取及应用(含源码) 作者: 孟祥磊-<微信公众平台开发实例教程> 将一条长链接转成短链接.开发者用于生成二维码的原链接(商品.支付二维码等)太长 ...

最新文章

  1. 习题8_6与习题9_2
  2. RESTful之异常处理 Exceptions
  3. MATLAB的基础-虽然基础,但全是细节,掌握了这些细节,才是MATLAB高手
  4. OnItemCommand属性使用方法
  5. sql语句lastupdate使用数据库库函数
  6. linux C 基于链表链的定时器
  7. 信息安全工程师笔记-云计算安全需求分析与安全保护工程
  8. 用Android Studio画UI界 --- 以Job/Task Schedule为例(英文版)
  9. 【python算法系列二】快速排序算法
  10. oracle 中的or,oracle语句查询 or和and
  11. 计算机二级刷题库刷的到原题吗,刷题能过计算机二级吗?
  12. 手绘图形识别方法(算法)
  13. A Deep Q-Network for the Beer Game: A Reinforcement Learning Algorithm to Solve Inventory Optimizati
  14. GitChat · 前端 | React 生态系统:从小白到大神
  15. adaboost.M1与adaboost.M2差别比较
  16. python按关键字爬取必应高清图片
  17. Android Studio 在library中引用本地arr的办法
  18. PMP之项目风险管理---实施定量风险分析
  19. 金山词霸字典转换工具
  20. java access 密码_java 连接加密Access2007数据库时,不用输入用户名密码也能连上

热门文章

  1. P3007 [USACO11JAN]大陆议会The Continental Cowngress(2-SAT)
  2. 上deepweb难吗_发动机保养难?傲群除尘毛刷用上了吗
  3. Hbase安装及配置
  4. [Ext JS ] 7.25.1 Form或者面板自动定位到错误的输入框
  5. java swing 等待框_java – 让用户使用Swing等待
  6. cglib动态代理jar包_Java中的原生动态代理和CGLIB动态代理的原理,我不信你全知道!...
  7. matlab keras,基于预训练的 Keras 层组合网络
  8. POJ - 3461 (kmp)
  9. 计算机主机清理步骤,三个方法教你如何正确清理C盘空间
  10. JS为键盘中的Enter键添加onkeyDown()和onkeyUp()事件