为什么我们无法通过智能合约向以太坊地址0x1发送以太币

6
使用以下Solidity代码,我尝试通过智能合约向以太坊钱包地址0x1发送以太币,但失败了。但是,当我直接从我的钱包向地址0x1发送以太币时,它成功了。
pragma solidity ^0.4.24;

contract Transfer {

    constructor () public payable {
        // Deploy contract with 1000 wei for testing purpose
        require(msg.value == 1000);
    }

    function done() public {
        address(0).transfer(1); // Transaction success
    }

    function fail() public {
        address(1).transfer(1); // Transaction failed
    }

    function send(address account) public {
        account.transfer(1); // Transaction success (except 0x1)
    }

}

为什么我们不能通过合约向地址0x1发送以太币? 参考:
  1. 直接从我的钱包发送以太币成功 https://ropsten.etherscan.io/tx/0x1fdc3a9d03e23b0838c23b00ff99739b775bf4dd7b5b7f2fa38043056f731cdc

  2. done()函数执行成功 https://ropsten.etherscan.io/tx/0xd319c40fcf50bd8188ae039ce9d41830ab795e0f92d611b16efde0bfa1ee82cd

  3. fail()函数执行失败 https://ropsten.etherscan.io/tx/0x0c98eafa0e608cfa66777f1c77267ce9bdf81c6476bdefe2a7615158d17b59ad


更新:

在研究以太坊预编译合约后,我编写了以下solidity代码通过智能合约向地址0x1发送以太币并成功。

pragma solidity ^0.4.24;

contract Learning {

    constructor () public payable {
        // Deploy contract with 1000 wei for testing purpose
        require(msg.value == 1000);
    }

    function test() public returns (bool) {
        // Set minimum gas limit as 700 to send ether to 0x1
        transfer(0x0000000000000000000000000000000000000001, 1, 700);
        return true;
    }

    function transfer(address _account, uint _wei, uint _gas) private {
        require(_account.call.value(_wei).gas(_gas)());
    }
}

为了测试,只需部署合约并使用1000 wei执行test()函数。它可以正常工作 :)

1个回答

6
你不小心发现了以太坊的一个较少为人知的“特性”。该链实际上有一些预编译合约(黄皮书附录E),其中之一位于0x0000000000000000000000000000000000000001(即ecrecover合约)。
由于ecrecover合约的回退执行将需要比transfer方法转发的2300 gas更多的gas,因此你的fail()函数会因gas不足而失败。
0x0地址不是一个特殊的合约,因此常规的转账调用可以正常工作,就像与任何其他地址一样。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接