🤢
Tron
  • Mastering TRON
  • Introduction
    • TRON 引言
    • TRON 基础
    • 节点客户端
    • 钱包
    • 交易(内置合约类型)
    • API
    • 开发者资源
  • Internals
    • 超级代表和投票
    • 产块和维护周期
    • 提案和链升级
  • Smart Contract
    • 什么是智能合约
    • Solidity 基础
    • Solidity 进阶
    • Solidity ABI
    • Use Solidity Like a Professional
    • 合约编程误区
    • Tooling
    • TVM
  • TRON by Example
    • Generate Address Offline
    • Transfer TRX
    • Transfer TRC20
    • Parse Event Logs
    • Estimate Energy Usage
    • Call Justswap
    • Query TRC20 Balance
  • Next Generation TRON
    • Current Tech that Benifits Blockchain
由 GitBook 提供支持
在本页
  • 继承覆盖关键变量
  • 使用可预测变量获取随机数

这有帮助吗?

  1. Smart Contract

合约编程误区

介绍常见的合约编程错误带来的风险。

继承覆盖关键变量

pragma solidity >=0.4.22 <0.6.0;

contract owned {
    address public owner;

    constructor() public {
        owner = msg.sender;
    }

    modifier onlyOwner {
        require(msg.sender == owner, "owner calls only!");
        _;
    }
}

contract XXX_POS is owned {
    address private owner;

    function distributeDividends(uint256 amount)
        public
        onlyOwner
        returns (bool)
    {
        require(address(this).balance >= amount, "!invalid withdraw amount");
        owner.transfer(amount);
        return true;
    }
}

如上合约代码,关键功能性函数已忽略。

看似 onlyOwner modifier 工作正常,且整个合约没有修改 owner 的入口,那么按照逻辑,只有合约作者可以通过调用 distributeDividends 获得收益。

然而实际执行中,合约的余额并没有发送给 owner, 而是被发到了 T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb 这样一个地址。通过调用 owner() 检查,并没有发现 owner 被修改。

问题出在 address private owner; 一句,该私有变量申明通过合约继承链,屏蔽掉了父合约 owned 中的真正的 owner 变量。所以在 owner.transfer() 中使用的地址是一个未初始化的 address 类型,值为 "410000000000000000000000000000000000000000", 用 base58check 编码后正好是 T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb.

检查合约继承链中的所有变量定义,避免覆盖关键变量。

使用可预测变量获取随机数

pragma solidity >=0.4.22 <0.6.0;

contract RandGuess {
    function genRandom() internal view returns (uint256) {
        return uint256(keccak256(abi.encodePacked(block.difficulty, now)));
    }

    function guess(uint8 value) public payable {
        require(msg.value == 1 trx);
        if (value == uint8(genRandom())) {
            msg.sender.transfer(2 trx);
        }
    }
}

如上合约代码,是一个简单的猜数字游戏。

uint256(keccak256(abi.encodePacked(block.difficulty, now))) 多见于以太坊合约的随机数生成,然而, 对于 TRON 来说,block.difficulty 恒为 0, 且 now(即 block.timestamp) 可准确预测。

最终结果是,攻击者可以提前计算随机数值,选择在合适的时间点发送交易,达到控制随机数的目的。

检查所有随机数生成源头,避免可预测的随机数。

上一页Use Solidity Like a Professional下一页Tooling

最后更新于4年前

这有帮助吗?

相关细节参考: .

波场Solidity智能合约安全实践:合约内随机数的实现