# 合约编程误区

## 继承覆盖关键变量

```javascript
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`.

{% hint style="warning" %}
检查合约继承链中的所有变量定义，避免覆盖关键变量。
{% endhint %}

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

```javascript
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) 可准确预测。

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

{% hint style="info" %}
检查所有随机数生成源头，避免可预测的随机数。
{% endhint %}

相关细节参考: [波场Solidity智能合约安全实践：合约内随机数的实现](https://zhuanlan.zhihu.com/p/116738596).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://andelf.gitbook.io/tron/smart-contract/contract-vulnerability.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
