2019-01-09 02:00:00
热度: 29622
作者: 隔壁老王(Old Wang NExt Door)
前言
随着solidity 0.5.0 nightly build版本的稳步推进,正式版也将在不久的将来与开发者见面。作为一个大版本更新,新版引入了很多特性,也废弃了很多关键字,比如
.call()不仅可以获知远程调用执行成功与否,还将获得远程调用执行的返回值address地址类型细分成 address和 address payableuintY和 bytesX不能直接转换external可见性constructor关键字定义throw关键字弃用, 函数状态可变性修饰符必须用 view,不能混用 constant和 view下面我们将对这些改变一一予以介绍,最后给出一个示例代码,对比展示新旧版solidity代码写法的区别,供大家参考。
显式声明
函数可见性
public可见性。public: constructor构造函数必须声明为 public可见性,否则编译报错。external: 回退函数(fallback function), 接口(interface)的函数必须声明为 external可见性,否则编译报错。存储位置
storage, memeory, calldata),包括函数参数和返回值变量都必须显式声明。external 的函数参数需显式声明为 calldata.合约与地址
contract合约类型不再包括 address类型的成员函数,必须显式转换成 address地址类型才能使用 send(), transfer(), balance等与之相关的成员函数/变量成员.address地址类型细分为 address和 address payable,只有 address payable可以使用 transfer(), send()函数.address payable类型可以直接转换为 address类型, 反之不能.address x可以通过 address(uint160(x)),强制转换成 address payable类型.contract A不具有 payable的回退函数, 那么 address(A)是 address类型.contract A具有 payable的回退函数, 那么 address(A)是 address payable类型.msg.sender属于 address payable类型.转换与填充(padding)
uintY与 bytesX
bytesX是右填充(低比特位补0),而 uintY是左填充(高比特位补0),二者直接转换可能会导致不符合预期的结果,所以现在当 bytesX和 uintY长度大小不一致(即X*8 != Y)时,不能直接转换,必须先转换到相同长度,再转换到相同类型.bytesX类型, 必须先转换到与 bytesX相同长度的 uintY,再转换到 bytesX类型bytesX不相等,也不能直接转换成 byteX类型ABI
abi.encodePacked()abi.encode()会恰当地处理 bytes和 string类型的填充(padding),若不需要进行填充,请使用 abi.encodePacked()abi.decode()时,如果发现 calldata太短或超长,将直接抛出异常,而不是像之前自动填充(补0)和截断处理,从而有效地遏制了短地址攻击..call()族函数( .call(), .delegatecall(), .staticcall())和 哈希函数( keccak256(),sha256(), ripemd160())只接受一个参数 bytes,且不进行填充(padding)处理..call()空参数必须写成 .call("").call(sig,a,b,c)必须写成 .call(abi.encodeWithSignature(sig,a,b,c)),其他类推keccak256(a,b,c)必须写成 keccak256(abi.encodePacked(a,b,c)),其他类推.call()族函数之前只返回函数执行成功是否的 bool, 现在还返回函数执行的返回值,即 (bool,bytes memory). 所以之前 boolresult=.call(sig,a,b,c) 现在必须写成 (boolresult,bytes memory data)=.call(sig,a,b,c) .不允许的写法
在之前版本的solidity编译,以下不允许的写法只会导致 warnings报警,现在将直接 errors报错.
storage变量.constant常量. 如 uintconstant time=now;是不允许的.0X(X大写)做16进制前缀,只能用 0x.value=0xffether必须写成 value=0xff*1ether.value=255.0ether不能写成 value=255.ether.+. 例如 value=1ether不能写成 value=+1ether.msg.value用在非 payable函数里以及此函数的修饰符(modifier)里.废弃的关键字/函数
years时间单位已弃用,因为闰年计算容易导致各种问题.var已弃用,请用 uintY精确声明变量长度.constant函数修饰符已弃用,不能用作修饰函数状态可变性, 请使用 view关键字.throw关键字已弃用,请使用 revert(), require(), assert()抛出异常..callcode()已弃用,请使用 .delegatecall(). 但是注意,在内联汇编仍可使用.suicide()已弃用, 请使用 selfdestruct().sha3()已弃用,请使用 keccak256().构造函数
constructor关键字定义. 之前,并未强制要求,既可以用合约同名函数定义构造函数,也可以用 constructor关键字定义.其他
do...while循环里的 continue不再跳转到循环体内,而是跳转到 while处判断循环条件,若条件为假,就退出循环.这一修改更符合一般编程语言的设计风格.if(){...}, do{...}while();, for{...}块内声明的变量,不能用在块外.pure和 view函数在EVM内部采用 staticcall操作码实现(EVM版本>=拜占庭),而非之前的 call操作码,这使得状态不可更改(state changes disallowed)在虚拟机层面得到保证.示例代码
其中 // Error...注释掉的代码在solidity版本<0.5.0均可以编译通过,但是在>=0.5.0均得换成 // Right ...的代码才能编译通过.
pragma solidity >0.4.99 <0.6;contract A { function () external payable {}} contract B { function () external {}}interface ERC20 { // function transferFrom(address _from, address _to, uint256 _value) public; // Error, `interface` must declare with `external` function transfer(address _to, uint256 _value) external; // Right}contract F{ address payable to_pay; address to; address owner; // uint constant time = now; // Error, value should be compile time constant. string constant time = "johnwick.io"; // Right modifier onlyOwner { require (msg.sender == owner); _; } // function () { // Error, fallback function MUST be `external` function () external { // Right } // function F() { // Error, consturctor function should use `constructor` keyword // constructor() { // Error, `constructor` should be `public` constructor () public { // Right } function payable_or_not() public { bool result; /* `address payable` VS `address` */ // to_pay = new A(); // Error, `contract` should explicitly convert to `address` to_pay = address(new A()); // Right, fallback function of contract A is `payable` to = address(new A()); // Right to_pay.transfer(1); // Right, `transfer()` is member of `address payable` result = to_pay.send(1); // Right, `send()` is member of `address payable` to = address(new B()); // Right // to_pay = address(new B()); // Error, fallback function of contract B is not `payable`. // to.transfer(1 ether); // Error, `transfer()` is not member of `address` // result = to.send(1 ether); // Error, `send()` is not member of `address` bool success; bytes memory data; (success, data)= to.call.gas(0).value(1 ether)(""); // However, you can use `call("")` to send ether address john; john = to_pay; // Right, `address payable` can directly convert to `address` address payable wick; // wick = to; // Error, `address` can't directly convert to `address payable` wick = address(uint160(to)); // Right, `address` can forcibly convert to `address payable` wick.transfer(1 ether); // `wick` is `address payable` now } // struct dummy {} // Error, empty struct is not allowed. struct yummy {string food;} // Right // `external` function input parameter should explicitly declare `calldata` location. function transfer(address _to, uint _value, bytes calldata _data) pure external returns (bool success){ // return; // Error, empty return statements for functions with one or more return values are now disallowed. } // `public` function input parameter should explicitly declare `memory` location. function try_some(bytes memory _data) public view returns(bool) { if(to == to_pay) { // throw; // Error, `throw` is deprecated. revert(); // Right, you should use `assert(),require(),revert()` to raise an exception. } bytes32 _hash; // _hash = sha3(_data); // Error, `sha3()` is deprecated. _hash = keccak256(_data); // Right uint256 _time; // _time = 1 years; // Error, `years` is deprecated, due to the leap year problem. _time = 366 days; // Right // var secs = _time * 3600; // Error, `var` is deprecated. uint secs; secs = _time * 0x3600; // Right int256 _value; // _value = 0xff wei; // Error, hex number with unit is not allowed now. _value = 0xff*1 wei; // Right // _value = 0Xff*1 wei; // Error, hex number prefix `0X` is not allowed now. // _value = 1. ether; // Error, dot followed without numbers is not allowed now. _value = 1.0 ether; // Right // _value = +1; // Error _value = -1; // bytes storage not_initial_bytes; // Error, `storage` without initialization is not allowed now. // uint[0] zero_array; // Error, fixed-size array of zero length is not allowed now. bytes32 b32; bytes20 b20; bytes1 b1; uint256 u256; uint160 u160; // b32 = bytes32(u160); // Error, can't directly convert `uintX` to `bytesY` of different size. b32 = bytes32(uint256(u160)); // Right, convert to the same size, then convert to the same type. u160 = uint160(bytes20(b32)); // Right b32 = bytes32(u256); // Right, both are the same size, then convert to the same type. // b1 = 255; // Error b1 = bytes1(uint8(255+360)); // Right, decimal number like `uintX` should convert to the same size, then the same type. // b16 = 0xff; // Error, hex number and `bytesX` are different size. b20 = bytes20(uint160(0xff)); // Right, same size, then same type. b1 = 0xff; // Right, hex number and `bytesX` are the same size } function im_not_payable() public returns (uint256 _value){ // _value = msg.value; // Error, `msg.value` MUST be used in `payable` function. } function im_payable() public payable returns (uint256 _value){ _value = msg.value; // Right, `msg.value` CAN be used in `payable` function. } // function not_impletement() public onlyOwner; // Error, function without implementation can't use `modifier` function kill(address payable _to) public { // suicide(_to); // Error, `suicide` is deprecated. selfdestruct(_to); // Right } function scope_() view public { uint count = 0 ; for (uint i=1 ; i<100; i++){ count += i; } // i = now; // Error, not C99-Style scope uint i; i = now; // Right, but this is error in solidity < 0.5.0 due to variable redefinition. } event ShowCount(uint); function inf_loop() public { uint count = 0; do { if (count!=0) { continue; } count = 1; // <0.5.0, `continue` jump to this loop body, which results in infinite loop !!! }while((count++)<10); // >=0.5.0 `continue` jump to this condition check. emit ShowCount(count); }}
文章声明:本文为火星财经专栏作者作品,不代表火星财经观点,版权归作者所有,如需转载,请提前联系作者或注明出处。