solidity return data和revert/require的reason string的获得
前言:
在使用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 Terms Draft - 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 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 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 oftruffle-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.
solidity return data和revert/require的reason string的获得的更多相关文章
- org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.String
org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.Strin ...
- hibernate报错Unknown integral data type for ids : java.lang.String
package com.model; // Generated 2016-10-27 14:02:17 by Hibernate Tools 4.3.1.Final /** * CmDept gene ...
- Python入门篇-递归函数Recursion
Python入门篇-递归函数(recursion) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.递归概述 (1)函数直接或者间接调用自身就是递归: (2)递归需要有边界,递归 ...
- Python 练习题总结(待续)
1.编写一个函数,接受一个参数n,n为正整数,左右两种打印方 式.要求数字必须对齐 正三角 倒三角 实现思路: 思路1.一行一行打印,前面追加空格,每一个空格的宽度等于数字字符串的宽度 #正三角打印d ...
- 【原创分享·微信支付】 C# MVC 微信支付教程系列之扫码支付
微信支付教程系列之扫码支付 今天,我们来一起探讨一下这个微信扫码支付.何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添 ...
- FileUtil(from logparser)
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; ...
- PHP如何自动识别第三方Restful API的内容,自动渲染成 json、xml、html、serialize、csv、php等数据
如题,PHP如何自动识别第三方Restful API的内容,自动渲染成 json.xml.html.serialize.csv.php等数据? 其实这也不难,因为Rest API也是基于http协议的 ...
- ASP.NET使用Memcached
一.安装Memcached及Memcached配置和状态查询 要想使用Memcached做缓存首先需要安装Memcached服务,安装方法如下: memcached.exe下载 保存至相应路径 打开c ...
- ASP.NET MVC EF 中使用异步控制器
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精 为什么使用异步操作/线程池 ASP.NET MVC ...
随机推荐
- XML部分
XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? 两种形式:DTD以及schema: 本质区别:schema本身是xml的,可以被XML解析器解析(这也是从DTD上发展sc ...
- DotNetCore学习-2.程序启动
新创建的ASP.NET Core程序中包含两个文件,分别是Program.Startup.其中,Program中Main方法是整个应用程序的入口,该方法如下: var host = WebHost.C ...
- 菜鸟入门【ASP.NET Core】12:JWT 设计解析及定制
前言 上一节我们讲述的书如何使用jwt token,而且上一节的token是要加Authorization:bearer XXXXXXXXXXXX才能访问. 这一节我们来研究如何自定义类似jwt的to ...
- (整理)Sublime Text 3 安装、破解、安装Package Control、汉化、添加到右键菜单、代码格式化、禁止更新
Sublime Text 3好用,但是每次安装到最后用着顺手,得在网上找半天安装.破解.安装Package Control.汉化.添加到右键菜单.代码格式化等等的教程,今天有空给自己整理一下吧. 一. ...
- 【c#】6.0与7.0新特性介绍记录
c#发展史 引用地址:https://www.cnblogs.com/ShaYeBlog/p/3661424.html 6.0新特性 1.字符串拼接优化 语法格式:$”string {参数}” 解释: ...
- 【协议】5、gossip 协议
Gossip是一种去中心化.容错并保证最终一致性的协议. Background:分布式环境 Gossip是为了解决分布式遇到的问题而设计的.由于服务和数据分布在不同的机器上,节点之间的每次交互都伴随着 ...
- lfs(systemd版本)学习笔记-第2页
我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! lfs(systemd)学习笔记-第1页 的地址:https://www.cnblogs.com/renren-study-no ...
- 终端复用软件 tmux
Tmux是一个优秀的终端复用软件,类似GNU Screen,但来自于OpenBSD,采用BSD授权. Tmux 所使用的快捷键前缀默认是组合键 Ctrl-b(同时按下 Ctrl 键和 b 键). 技巧 ...
- 正则与python的re模块
一.正则表达式的语法 正则表达式使用反斜杠字符('\')来表示特殊的形式或者来允许使用特殊的字符而不要启用它们特殊的含义.这与字符串字面值中相同目的的相同字符的用法冲突:例如,要匹配一个反斜线字面值, ...
- css制作表格
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...