一起学智能合约之九错误和异常处理

一起学智能合约之九错误和异常处理

记得在群里和小伙伴们讨论的时候儿,有人说他的智能合约执行没成功,但钱没了。这个有点可怕,但是如果你从源码角度看,这种可能性是不可能的。
下面分析一下出现了错误和异常会是什么情况?
一、 错误
在Solidity中,出现错误很常见,比如条件不满足、目标不对,这时候儿,就会返回一个错误,返回错误,只要是非异常的错误,都可以保证合约的正常执行,只是达不到目的。当然,gas也就耗光了。
这里面有一种错误一定要高度引起重视,就是逻辑错误,最简单的例子就是在fallback中执行一些代码,导致重大损失。
这个在前面的相关的分析中写过例子,这里就不再列举了。
二、异常
在Solidity中,异常可以自动抛出,也可以用thrown手动抛出。招聘异常后,交易会回滚,意味着一切回到原样。
这里回到原样有三种方式:
1、 require(expression),表达式为非抛出的异常,未使用的gas退回。(函数入参)
2、 assert(expression),抛出异常后不退回gas,全部消耗。(内部状态验证)
3、 revert(),抛出异常返回错误,未使用gas退回。
其实assert是被编译成0xfe,而require被编译成0xfd(revert)。
不过,和其它语言不一样的是,在Solidity中想捕捉异常是异想天开的,也就是说,异常出来,自动向上传导,直到挂掉。下面看一个例子:
pragma solidity ^0.4.0;

contract Sharer {
function sendHalf(address addr) payable returns (uint balance) {
if (!addr.send(msg.value / 2))
throw; // also reverts the transfer to Sharer
return this.balance;
}
}
当前,Solidity在下述场景中自动产生运行时异常。
1、如果越界,或是负的序号值访问数组。
2、如果访问一个定长的bytesN,序号越界,或是负的序号值。
3、如果你通过消息调用一个函数,但在调用的过程中,并没有正确结束(gas不足,没有匹配到对应的函数,或他自己出现异常)。底层操作如call,send,delegatecall或callcode除外,它们不会抛出异常,但它们会通过返回false来表示失败。
4、如果在使用new创建一个新合约时,但合约的初化化由于类似3中的原因没有正常完成。
5、被除数为0。
6、对一个二进制移动一个负的值。
7、使用枚举时,将过大值,负值转为枚举类型。
8、使用外部函数调用时,被调用的对象并不包含代码。
9、如果你的public的函数在没有payable关键字时,却尝试在接收ether(包括构造函数,和回退函数)。
10、合约通过一个public的getter函数(public getter funciton)接收ether。
11、调用一个未初始化的内部函数。
12、.transfer()执行失败
13、assert返回false

当一个用户通过下述方式触发一个异常:
1、 调用throw。
2、 调用require,但参数值为false。
当发生上述异常时,会执行0xfd(回退)指令,而当运行时assert时,前面讲过,会执行0xfe(无效)指令,耗尽gas。此时EVM会撤消所有的状态的改变。相当于进行了一个原子操作。
三、总结
错误和异常都会导致智能合约达不到最初的目的,甚至达到恶劣的效果。因为严格的控制错误和异常情况下帐户的安全是首要之首要。千万引起重视。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值