如何避免在合约业务逻辑中做出基于时间的决策?

How to Avoid making time-based decisions in contract business logic?

我写了一个省钱的智能合约,用户存入 ETH 并定义他们希望在合约中保留该 ETH 的时间,例如:用户 X 存入 2ETH 一年,他们只能在之后提取 ETH那个时期。 但是 solidity linter 一直告诉我,我不应该依赖 block.timestamp 来做决定。 这是我用来将每个地址映射到余额和结束时间的 Saving 结构:

struct Saving {
    uint256 balance;
    uint256 endTime;
}

这是我的函数修饰符,我要求取款时间大于我在存款时存储的结束时间:

modifier onlyValidTimeWithdraw() {
    require(
        block.timestamp > balances[msg.sender].endTime,
        "You cannot withdraw yet"
    );
    _;
}

这是我通过 linter 得到的消息。

经过一些研究后,我发现我的合约中不应该有时间依赖条件,因为矿工可以操纵时间戳,但我没有找到任何替代方案。

矿工可以在大约 10 个范围内操纵区块时间戳。几秒,足以影响到秒级精度的业务逻辑。

function betLottery() external {
    // the block.timestamp can be affected by a miner
    // and they can submit their own winning transaction
    if (block.timestamp % 2 == 0) {
        win();
    }
}

但是由于您的逻辑依赖于更长的周期,所以我会忽略或取消警告。

或者如果它适合您的用例,您可以根据块号进行验证,大多数 linter 都允许这样做。

struct Saving {
    uint256 balance;
    uint256 endBlock;
}
require(
    block.number > balances[msg.sender].endBlock,
    "You cannot withdraw yet"
);