Почему мы не можем отправить эфир по адресу эфира 0x1 по умным контрактам
С помощью приведенного ниже кода солидности я попытался отправить эфир на адрес кошелька Ethereum 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 через контракты?
ССЫЛКА:
Отправка эфира прямо из моего кошелька - это успех https://ropsten.etherscan.io/tx/0x1fdc3a9d03e23b0838c23b00ff99739b775bf4dd7b5b7f2fa38043056f731cdc
Функция done() успешна https://ropsten.etherscan.io/tx/0xd319c40fcf50bd8188ae039ce9d41830ab795e0f92d611b16efde0bfa1ee82cd
Функция fail() не выполнена https://ropsten.etherscan.io/tx/0x0c98eafa0e608cfa66777f1c77267ce9bdf81c6476bdefe2a7615158d17b59ad
2 ответа
Вы случайно наткнулись на одну из менее известных "особенностей" эфириума. Цепочка фактически имеет несколько предварительно скомпилированных контрактов (Приложение E в желтой бумаге), один из которых живет по адресу 0x0000000000000000000000000000000000000001
(ecrecover
контракт).
Ваш fail()
функция выходит из строя из-за того, что ecrecover
Откат выполнения контракта потребует больше, чем 2300 gas
направлено transfer
метод.
0x0
адрес не является специальным договором, поэтому обычный перевод звонка работает просто отлично, как и с любым другим адресом.
Изучив предварительно скомпилированные контракты ethereum, я написал нижеприведенный код надежности для отправки эфира по адресу 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()
функция. Работает:)