智能合约编写注意事项

简介: 智能合约编写注意事项

今天区块链技术圈被美链(BEC)智能合约的漏洞导致代币价值几乎归零的事件刷遍朋友圈。这篇文章就带大家了解一些智能合约编写的注意事项。

Overflow 与 Underflow

Solidity 可以处理 256 位数字, 最高为 2256 - 1, 所以对 (2 256 - 1) 加 1 会导致归 0。同理, 对 unsigned 类型 0 做减 1 运算会得到 (2**256 - 1)

测试代码如下:

  1. pragma solidity 0.4.18;
  2. contract OverflowUnderflow{
  3.    uintpublic zero =0;
  4.    uintpublic max =2**256-1;
  5.    // zero will end up at  2 ** 256 - 1
  6.    function underflow()public{
  7.        zero -=1;
  8.    }
  9.    function overflow()public{
  10.        max +=1;
  11.    }
  12. }

尽管他们同样危险, 但是在智能合约中, underflow 造成的影响更大.

比如, 账号 A 持有 X tokens, 如果他发起一笔 X + 1 tokens 的交易, 如果代码不进行校验, 则账号 A 的余额可能发生 underflow 导致余额变多.

可以引入 SafeMath Library 解决:

  1. pragma solidity 0.4.18;
  2. library SafeMath{
  3.    function mul(uint256 a, uint256 b)internal pure returns (uint256){
  4.        if(a==0){
  5.            return0;
  6.        }
  7.        uint c = a * b;
  8.        assert(c / a == b);
  9.        return c;
  10.    }
  11.    function div(uint256 a, uint256 b)internal pure returns (uint256){
  12.        uint256 c = a / b;
  13.        return c;
  14.    }
  15.    functionsub(uint256 a, uint256 b)internal pure returns (uint256){
  16.        assert(b <= a);
  17.        return a - b;
  18.    }
  19.    function add(uint256 a, uint256 b)internal pure returns (uint256){
  20.        uint256 c = a + b;
  21.        assert(c >= a);
  22.        return c;
  23.    }
  24. }
  25. contract OverflowUnderflow{
  26.    usingSafeMathforuint;
  27.    uintpublic zero =0;
  28.    uintpublic max =2**256-1;
  29.    function underflow()public{
  30.        zero = zero.sub(1);
  31.    }
  32.    function overflow()public{
  33.        max = max.add(1);
  34.    }
  35. }

Visibility 与 Delegatecall

  • Public functions 可以被任意地址调用
  • External functions 只能从合约外部调用
  • Private functions 只能从合约内部调用
  • Internal functions 允许从合约及其子合约调用

External functions 消耗的 gas 比 public 少, 因为其使用 calldata 而 Public 需要复制所有参数到 memory。

Delegatecall

Delegatecall is identical to a message call apart from the fact that the code at the target address is executed in the context of the calling contract and msg.sender and msg.value do not change their values. This means that a contract can dynamically load code from a different address at runtime. Storage, current address and balance still refer to the calling contract, only the code is taken from the called address.

这个特性可以用于构建 Library 和模块化代码. 但是与此同时, 这也有可能造成别人对你的代码进行操作。

下例中, 攻击者调用 pwn 方法获得了合约的拥有权。

  1. pragma solidity 0.4.18;
  2. contract Delegate{
  3.    address public owner;
  4.    functionDelegate(address _owner)public{
  5.        owner = _owner;
  6.    }
  7.    function pwn()public{
  8.        owner = msg.sender;
  9.    }
  10. }
  11. contract Deletagion{
  12.    address public owner;
  13.    Delegatedelegate;
  14.    functionDelegation(address _delegateAddreses)public{
  15.        delegate=Delegate(_delegateAddreses);
  16.        owner = msg.sender;
  17.    }
  18.    // an attacker can call Delegate.pwn() in the context of Delegation, this means that pwn() will modify the state of **Delegation** and not Delegate, the result is that the attacker takes unauthorized ownership of the contract.
  19.    function()public{
  20.        if(delegate.delegatecall(msg.data)){
  21.            this;
  22.        }
  23.    }
  24. }

Reentrancy(TheDAO hack)

Solidity 中 call 函数被调用时, 如果带有 value 参数, 则会转发所有他所收到的 gas。

在一下代码片段中, call函数在sender的余额实际减少前被调用。这里有一个漏洞曾导致TheDAO攻击。

  1. function withdraw(uint _amount)public{
  2.  if(balances[msg.sender]>= _amount){
  3.    if(msg.sender.call.value(_amount)()){
  4.      _amount;
  5.    }
  6.    balances[msg.sender]-= amount;
  7.  }
  8. }

引自Reddit的解释:

  1. In simple words, its like the bank teller doesnt change your balance until she has given you all the money you requested.Can I withdraw $500?Wait, before that , can I withdraw $500?”

  2. And so on.The smart contracts as designed only check you have $500 at beginning once,and allow themselves to be interrupted

目录
相关文章
|
3月前
|
区块链
【智能合约】新版Remix编写实现第一个HelloWorld
【智能合约】新版Remix编写实现第一个HelloWorld
73 2
api一键自动合约跟单模式 | 程序化交易系统开发讲解【附样板源码实例分析】
“量化交易”有着两层含义:一是从狭义上来讲,是指量化交易的内容,将交易条件转变成为程序,自动下单;二是从广义上来讲,是指系统交易方法,就是一个整合的交易系统。
|
8月前
关于调试的应用场景及如何编写优秀代码
关于调试的应用场景及如何编写优秀代码
65 0
|
机器学习/深度学习 人工智能 自然语言处理
秒合约开发原理丨秒合约系统开发(详细规则)丨秒合约源码案例部署
秒合约开发原理丨秒合约系统开发(详细规则)丨秒合约源码案例部署
|
前端开发 JavaScript 区块链
链上DApp开发智能合约代码编写示例
链上DApp开发源码demo是指链上DApp的完整源代码示例。这些示例通常包括前端、后端和智能合约等多个部分,展示如何使用各种编程语言和工具构建基于区块链的应用程序。
|
Rust 区块链 数据安全/隐私保护
佛萨奇2.0智能合约系统丨佛萨奇2.0智能合约系统开发(功能版)丨佛萨奇2.0智能合约现成源码案例开发
隐私计算网关调用系统合约把执行结果与签名传到链上。系统合约会从链上获取Enclave远程证明,从中提取出签名公钥,并对执行结果的签名进行验证,并从执行结果中提取隐私合约、链上数据部分,与区块链上的信息进行比对。如果这些验证都通过了,则系统合约执行成功,隐私合约的执行结果会被打包到区块中等待共识出块。
|
Go 区块链 数据安全/隐私保护
佛萨奇2.0系统智能合约程序编写逻辑方案
FORGE循环仪中使用的矩阵大小为3×1和2×2。3×1矩阵本质上很简单,只需要填充三个位置即可。2×2矩阵从第一层的两个位置开始,然后扩展到第二层的四个位置。职位通过直接和间接招募Forsage会员来填补。一旦矩阵中的所有位置都被填满,就激活循环佣金。从矩阵出来的位置也将输入相同大小的新矩阵。
佛萨奇2.0系统智能合约程序编写逻辑方案
|
区块链 Python
佛萨奇2.0智能合约开发逻辑demo
This article is compiled and released by **WeChaT: kaifa873**, which is only for reference of project development requirements! **telegram @ sleu88**
64 0
|
存储 Web App开发 区块链
关于派链模式系统开发的原理分析(Solidity编写)
关于派链模式系统开发的原理分析(Solidity编写)
152 0
|
Java 区块链
【智能合约】Solidity 进阶编程 | 注意一下合约中的细节
目录 1. 内置的全局变量 2. 错误处理 3. 访问函数 4. 创建合约 5. 合约继承 6. 修饰器modifier 最后
259 0
【智能合约】Solidity 进阶编程 | 注意一下合约中的细节