Контракт DAO подвергся атаке 17 июня 2016 года, когда злоумышленник похитил эфиры на сумму около 50 миллионов долларов США , используя уязвимость рекурсивного вызова в коде контракта DAO.
Злоумышленник слил украденные эфиры в несколько дочерних DAO, а группа Робин Гуда слила оставшиеся средства в другие дочерние DAO.
Блокчейн Ethereum был подвергнут хард- форку в блоке № 1 920 000 20 июля 2016 года для передачи эфиров из контракта DAO и его дочерних DAO в контракт WithdrawDAO .
В то время как большинство клиентов узлов Ethereum используют блокчейн с хардфорком (ETH), меньшинство клиентов узлов Ethereum использует классический блокчейн без хардфорка (ETC).
Клиенты узлов Ethereum могут быть настроены на использование блокчейна с хард-форком или блокчейна без хард-форка. Некоторые узлы были настроены для ретрансляции транзакций из разветвленной цепочки блоков в неразветвленную цепочку блоков и наоборот. Транзакции, выполненные в блокчейне ETH, с высокой вероятностью будут воспроизведены в блокчейне ETC, а транзакции в блокчейне ETC с высокой вероятностью будут воспроизведены в блокчейне ETH.
Несколько сплит-контрактов были развернуты по одному и тому же адресу контракта как в блокчейнах с хард-форком, так и в блокчейнах без хард-форка.
Как вы используете эти сплит-контракты для условной отправки эфиров на другие учетные записи либо в цепочке ETH с хард-форком, либо в цепочке ETC Classic без хард-форка?
Обновление от 02 июня 2017 г.
Из ПРЕДУПРЕЖДЕНИЯ: НЕ используйте SafeConditionalHFTransfer! Или используйте его правильно :
SafeConditionalHFTransfer сэкономил много эфиров, неправильно перемещенных по неправильной цепочке после хардфорка DAO . На данный момент через SafeConditionalHFTransfer по адресу 0x1e143b2588705dfea63a17f2032ca123df995ce0 прошло 20549 txns + 16022 internalTxns . Автор связался со мной сегодня утром по поводу 67 317,257581981046981598 ETH ~ 14 892 596,89 долларов США (@ $ 221,23 / ETH), отправленных неправильно в контракт.
При использовании этого контракта вы должны вызывать функции
classicTransfer(...)
илиtransfer(...)
для направления вашего ETH или ETC в предполагаемую цепочку. Если вы отправляете ETH (или ETC) НАПРЯМУЮ на адрес контракта, ваш ETH (или ETC) не будет перенаправлен на адрес назначения в цепочке назначения, а вместо этого останется в этом контракте НАВСЕГДА.Поскольку последние клиенты в цепочках ETH и ETC имеют встроенную защиту от воспроизведения EIP155 , вам НЕ нужно больше ее использовать
SafeConditionalHFTransfer
. Просто убедитесь, что вы используете последний клиент с EIP155!Вот основные клиенты и версии, реализующие EIP155:
geth
Go Ethereum — EIP155 с Let There Be Light (v1.5.0) 16 ноября 2016 года. Последний релиз Hat Trick (v1.6.5) .- Parity — EIP155, начиная с Civility (v1.4) 07 ноября 2016 г. Последний выпуск с https://parity.io/parity.html или https://github.com/paritytech/parity/releases
- MyEtherWallet (не забудьте использовать правильный URL-адрес https://www.myetherwallet.com/ ) имеет защиту от повторного использования EIP155.
Это предупреждение также было размещено в верхней части ответа на вопрос « Как условно отправить эфиры на другую учетную запись после хард-форка, чтобы защитить себя от повторных атак» .
Обновление от 26 ноября 2016 г. — см. ответ @eth на вопрос выше, так как в версии geth
1.5.3 реализована защита от повторных атак.
geth
для передачи эфиров в классическую сеть с хард-форком ИЛИ без хард-форка через SafeConditionalHFTransfer
контракт.geth
для передачи эфиров в классическую сеть с хард-форком и без хард-форка через ReplaySafeSplitV2
контракт.SafeConditionalHFTransfer
контракт.ReplaySafeSplitV2
контракт. Любая учетная запись может быть вашей исходной учетной записью, чтобы средства отправлялись обратно на вашу учетную запись в одной из цепочек.ВОПРОСЫ
Если вы хотите отправить предварительно хардфорк ETC на учетную запись Exchange ETC
support-hard-fork
или oppose-hard-fork
клиент узла Ethereum.classicTransfer
метод geth
или « Перевод только в классической цепочке без жесткого форка» в кошельке Ethereum .SafeConditionalHFTransfer
контракту, возвращающему ваш ETH.Ethereum Wallet и Mist Beta 0.8.2 теперь имеют функцию предотвращения повторного воспроизведения:
Предотвращение повторного воспроизведения
Мы добавили расширенную функцию для предотвращения повторного воспроизведения ваших транзакций в других цепочках, таких как ethereum classic. Это позволяет вам либо вообще предотвратить этот перевод на Classic, либо использовать эту транзакцию для отправки той же суммы на другой контракт, например, на вновь созданную учетную запись или на биржу. Если вы хотите полностью разделить все свои транзакции, мы рекомендуем вам создать две новые учетные записи, одну для собственно Ethereum, а другую для Classic, а затем перевести на них все свои средства (помните, что для перемещения токенов вам нужен эфир), убедившись, что каждая аккаунт имеет 0 эфиров в другой цепочке — если сделать это один раз, любая будущая транзакция не будет воспроизведена. Чтобы использовать это, используйте кнопку «Дополнительные параметры» на странице отправки.
Эта функция также поддерживает разделение токенов, но она очень экспериментальная и работает не со всеми токенами. Поскольку все это делается с помощью контракта, сначала вам нужно разрешить этому контракту перемещать токены от вашего имени, нажав «Подтвердить передачу токена».
Как всегда, эти функции являются экспериментальными и должны быть сначала протестированы на небольших количествах . Хотя большинство транзакций воспроизводятся в обеих цепочках, некоторые могут не воспроизводиться по нескольким причинам. Кроме того, на некоторых биржах возникают проблемы с получением эфира с адреса контракта — если это ваш случай, свяжитесь с биржей.
Мы также удалили весь код форка из приложения Mist, поэтому, если вы хотите использовать его, Ether Classic вам придется либо загрузить Classic Mist непосредственно из их репозитория, либо использовать свой собственный узел в качестве серверной части для вашего кошелька (как Ethereum Wallet, так и Ethereum Wallet). и Mist может подключиться к любому узлу), как и в случае с частной сетью.
Контракт защиты от воспроизведения можно найти по адресу 0x1ca4a86bba124426507d1ef67ad271cc5a02820a .
geth
и SafeConditionalHFTransfer
контрактУбедитесь, что вы используете версию geth 1.4.10 или более позднюю. И запустите свои команды geth с параметром --support-dao-fork, чтобы вы находились на хард-форке блокчейна. Для передачи с помощью функций transfer(...)
или :classicTransfer(...)
user@Kumquat:~$ geth console
// Allow chain to sync
var fromAccount = "{from account}";
var toAccount = "{to account}";
var amount = web3.toWei(1.123, "ether");
personal.unlockAccount(fromAccount, "{password}")
var safeConditionalHFTransferAddress = "0x1e143b2588705dfea63a17f2032ca123df995ce0";
var safeConditionalHFTransferABI = [{"constant":false,"inputs":[{"name":"to","type":"address"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"}],"name":"classicTransfer","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"}];
var safeConditionalHFTransfer = eth.contract(safeConditionalHFTransferABI).at(safeConditionalHFTransferAddress);
// WARNING - Run the next statement to transfer ETH on the hard-forked chain
// This will only cost some gas on the non-hard-forked ETC Classic chain
// Test with a small amount first
var transfer = safeConditionalHFTransfer.transfer(toAccount, {from: fromAccount, value: amount});
console.log(transfer);
// WARNING - Run the next statement to transfer ETC on the non-hard-forked Classic chain
// This will only cost some gas on the hard-forked ETH chain
// Test with a small amount first
var classicTransfer = safeConditionalHFTransfer.classicTransfer(toAccount, {from: fromAccount, value: amount});
console.log(classicTransfer);
geth
и ReplaySafeSplitV2
контрактУбедитесь, что вы используете версию geth 1.4.10 или более позднюю. И запустите свои команды geth с параметром --support-dao-fork, чтобы вы находились на хард-форке блокчейна. Для передачи с помощью split(...)
функции:
user@Kumquat:~$ geth console
// Allow chain to sync
var fromAccount = "{from account}";
var toAccountFork = "{to account on forked chain}";
var toAccountNoFork = "{to account on non-forked chain}";
var amount = web3.toWei(1.123, "ether");
personal.unlockAccount(fromAccount, "{password}")
var replaySafeSplitV2Address = "0xaBbb6bEbFA05aA13e908EaA492Bd7a8343760477";
var replaySafeSplitV2ABI = [{"constant":false,"inputs":[{"name":"targetFork","type":"address"},{"name":"targetNoFork","type":"address"}],"name":"split","outputs":[{"name":"","type":"bool"}],"type":"function"}];
var replaySafeSplitV2 = eth.contract(replaySafeSplitV2ABI).at(replaySafeSplitV2Address);
var transfer = replaySafeSplitV2.split(toAccountFork, toAccountNoFork, {from: fromAccount, value: amount});
console.log(transfer);
SafeConditionalHFTransfer
контрактаОбратите внимание, что приведенный ReplaySafeSplitV2
ниже контракт имеет больше встроенных функций безопасности.
Убедитесь, что вы загрузили Ethereum Wallet 0.8.1 или более позднюю версию.
При первом запуске Ethereum Wallet 0.8.1 выберите «Да» на вопрос «Хотите ли вы активировать цепочку, в которой средства, связанные с эксплойтом, восстанавливаются в контракт, где они могут быть сняты держателями токенов The DAO?» . Теперь вы сделали выбор в пользу использования хард-форка Ethereum.
В Ethereum Wallet выберите страницу КОНТРАКТЫ в верхнем меню. Нажмите ПОСМОТРЕТЬ КОНТРАКТ.
SafeConditionalHFTransfer
0x1e143b2588705dfea63a17f2032ca123df995ce0
[{"constant":false,"inputs":[{"name":"to","type":"address"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"}],"name":"classicTransfer","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"}]
Это переведет ваш ETH на целевой счет в сети с жестким форком и будет стоить вам только газа в классической цепочке без жесткого форка.
Выберите страницу КОНТРАКТЫ в верхнем меню. Нажмите на БЕЗОПАСНЫЙ HFTRANSFER. В правой части страницы в разделе ЗАПИСАТЬ КОНТРАКТ выберите функцию Transfer
. Введите адрес назначения в цепочке хард-форка в поле « Кому — адрес » . В разделе «Выполнить из » выберите свою учетную запись. Введите количество ETH в поле « Отправить ETHER » . Нажмите кнопку ВЫПОЛНИТЬ, введите свой пароль и подтвердите. Вот изображение экрана:
Это переведет ваш ETH на целевой счет в классической цепочке без хард-форка и будет стоить вам только газа в цепочке с хард-форком.
Выберите страницу КОНТРАКТЫ в верхнем меню. Нажмите на БЕЗОПАСНЫЙ HFTRANSFER. В правой части страницы в разделе ЗАПИСАТЬ КОНТРАКТ выберите функцию Classic Transfer
. Введите адрес назначения в цепочке без хард-форка в поле Кому - адрес . В разделе «Выполнить из » выберите свою учетную запись. Введите количество ETH (ETC) в поле « Отправить ETHER» . Нажмите кнопку ВЫПОЛНИТЬ, введите свой пароль и подтвердите. Вот изображение экрана:
ReplaySafeSplitV2
контрактаОБНОВЛЕНИЕ 22:27, 4 сентября 2016 г. Это новая более безопасная версия, ReplaySafeSplit
как обсуждалось @chevdor на thedao.slack.com/messages/general в более безопасной версии смарт-контракта ReplaySafeSplit . Эта новая версия проверяет, что указанные вами адреса не являются 0x0000...0000 перед отправкой ваших эфиров на адреса. Этот раздел был обновлен новыми деталями контракта.
Убедитесь, что вы загрузили Ethereum Wallet 0.8.1 или более позднюю версию.
При первом запуске Ethereum Wallet 0.8.1 выберите «Да» на вопрос «Хотите ли вы активировать цепочку, в которой средства, связанные с эксплойтом, восстанавливаются в контракт, где они могут быть сняты держателями токенов The DAO?» . Теперь вы сделали выбор в пользу использования хард-форка Ethereum.
В Ethereum Wallet выберите страницу КОНТРАКТЫ в верхнем меню. Нажмите ПОСМОТРЕТЬ КОНТРАКТ.
ReplaySafeSplitV2
0x8201...
0xaBbb6bEbFA05aA13e908EaA492Bd7a8343760477
[{"constant":false,"inputs":[{"name":"targetFork","type":"address"},{"name":"targetNoFork","type":"address"}],"name":"split","outputs":[{"name":"","type":"bool"}],"type":"function"}]
Это переведет ваш ETH на две учетные записи, первая будет учетной записью назначения в цепочке с хард-форком, а вторая — учетной записью назначения в классической цепочке без хард-форка.
Выберите страницу КОНТРАКТЫ в верхнем меню. Нажмите REPLAYSAFESPLITV2. В правой части страницы в разделе ЗАПИСАТЬ КОНТРАКТ выберите функцию Split
. Введите адрес назначения в цепочке хард-форка в поле « Целевой форк — адрес » . Введите адрес назначения в сети Classic без хард-форка в поле « Цель без форка — адрес ». В разделе «Выполнить из » выберите свою учетную запись. Введите количество эфиров в поле « Отправить ETHER » . Нажмите кнопку ВЫПОЛНИТЬ, введите свой пароль и подтвердите.
Вот изображение экрана:
SafeConditionalHFTransfer
ДоговорОбратите внимание, что приведенный ReplaySafeSplitV2
ниже контракт имеет больше встроенных функций безопасности.
Ниже приведен исходный код контракта SafeConditionalHFTransfer (предложен 26 июля 2016 г. @shoraibit
). Этот контракт не зависит от контракта WithdrawDAO, имеющего баланс более 1 000 000 эфиров в будущем.
contract ClassicCheck {
function isClassic() constant returns (bool isClassic);
}
contract SafeConditionalHFTransfer {
bool classic;
function SafeConditionalHFTransfer() {
classic = ClassicCheck(0x882fb4240f9a11e197923d0507de9a983ed69239).isClassic();
}
function classicTransfer(address to) {
if (!classic)
msg.sender.send(msg.value);
else
to.send(msg.value);
}
function transfer(address to) {
if (classic)
msg.sender.send(msg.value);
else
to.send(msg.value);
}
}
Этот контракт зависит от контракта ClassicCheck :
contract ClassicCheck {
bool public classic;
function ClassicCheck() {
if (address(0xbf4ed7b27f1d666546e30d74d50d173d20bca754).balance > 1000000 ether)
classic = false;
else
classic = true;
}
function isClassic() constant returns (bool isClassic) {
return classic;
}
}
Когда SafeConditionalHFTransfer
контракт был развернут, он использовал ClassicCheck
контракт, чтобы определить, был ли код развернут в хард-форк или не хард-форк. И эта проверка была сделана, когда баланс WithdrawDAO превышал 1 000 000 . SafeConditionalHFTransfer
всегда должен работать , так как ему больше не нужно проверять баланс баланса WithdrawDAO.
ReplaySafeSplitV2
ДоговорОБНОВЛЕНИЕ 22:27, 4 сентября 2016 г. Это новая более безопасная версия, ReplaySafeSplit
как обсуждалось @chevdor на thedao.slack.com/messages/general в более безопасной версии смарт-контракта ReplaySafeSplit . В этой новой версии есть проверки того, что адреса, которые вы указываете, не 0x0000...0000
перед отправкой ваших эфиров на адреса.
Ниже приведен исходный код контракта ReplaySafeSplitV2 :
contract RequiringFunds {
modifier NeedEth () {
if (msg.value <= 0 ) throw;
_
}
}
contract AmIOnTheFork {
function forked() constant returns(bool);
}
contract ReplaySafeSplit is RequiringFunds {
// address private constant oracleAddress = 0x8128B12cABc6043d94BD3C4d9B9455077Eb18807; // testnet
address private constant oracleAddress = 0x2bd2326c993dfaef84f696526064ff22eba5b362; // mainnet
// Fork oracle to use
AmIOnTheFork amIOnTheFork = AmIOnTheFork(oracleAddress);
// Splits the funds into 2 addresses
function split(address targetFork, address targetNoFork) NeedEth returns(bool) {
// The 2 checks are to ensure that users provide BOTH addresses
// and prevent funds to be sent to 0x0 on one fork or the other.
if (targetFork == 0) throw;
if (targetNoFork == 0) throw;
if (amIOnTheFork.forked() // if we are on the fork
&& targetFork.send(msg.value)) { // send the ETH to the targetFork address
return true;
} else if (!amIOnTheFork.forked() // if we are NOT on the fork
&& targetNoFork.send(msg.value)) { // send the ETH to the targetNoFork address
return true;
}
throw; // don't accept value transfer, otherwise it would be trapped.
}
// Reject value transfers.
function() {
throw;
}
}
Ниже приведен код виртуальной машины из классического блокчейна без жесткого форка, который соответствует проверенному коду виртуальной машины + исходному коду в цепочке с жестким форком.
user@PussyWillow:~$ geth -exec 'eth.getCode("0xaBbb6bEbFA05aA13e908EaA492Bd7a8343760477")' attach
"0x6060604052361561001f5760e060020a60003504630f2c93298114610028575b6100005b610002565b6100406004356024356000348190116100e157610002565b60408051918252519081900360200190f35b80547f16c72721000000000000000000000000000000000000000000000000000000006060908152600160a060020a0391909116906316c727219060649060209060048187876161da5a03f11561000257505060405151905080156100d25750604051600160a060020a038416908290349082818181858883f193505050505b1561010f575060015b92915050565b82600160a060020a0316600014156100f857610002565b81600160a060020a03166000141561005257610002565b600060009054906101000a9004600160a060020a0316600160a060020a03166316c727216040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151159050801561018c5750604051600160a060020a038316908290349082818181858883f193505050505b15610023575060016100db56"
Этот контракт зависит от контракта AmIOnTheFork :
contract AmIOnTheFork {
bool public forked = false;
address constant darkDAO = 0x304a554a310c7e546dfe434669c62820b7d83490;
// Check the fork condition during creation of the contract.
// This function should be called between block 1920000 and 1921200.
// Approximately between 2016-07-20 12:00:00 UTC and 2016-07-20 17:00:00 UTC.
// After that the status will be locked in.
function update() {
if (block.number >= 1920000 && block.number <= 1921200) {
forked = darkDAO.balance < 3600000 ether;
}
}
function() {
throw;
}
}
--oppose-dao-fork
Это работает!var classicTransfer = hfConditionalTransfer
ошибочно, потому что он все еще использует, hfConditionalTransfer
а не безопасную версию.ReplaySafeSplit
выполняются действия в двух блокчейнах? Я не понимаю эту часть. Я ожидал, что вам придется запускать что-то дважды, по одному разу из кошелька, указывающего на один из двух блокчейнов.@mowliv
, транзакции из сети HF в настоящее время ретранслируются в сеть без HF, и наоборот. Я обновил ответ выше.Если вы используете новый клиент, такой как Geth 1.5.3, он реализует защиту от атак повторного воспроизведения EIP 155 , чтобы ваши транзакции ETH были защищены от повторной атаки на ETC.
Используя Geth 1.5.3 (или более позднюю версию), вы должны создать другую учетную запись и переместить все свои ETH на новый адрес. Не забудьте сделать резервную копию этой новой учетной записи (и не удаляйте старую учетную запись, поскольку в ней есть ваш ETC).
Дополнительный шаг тем временем, так как Geth 1.5.3 очень новый: после вышеизложенного в цепочке ETC переместите все ETC на другой адрес. Это поможет убедиться, что вы действительно защищены от повторных атак.
эт
q9f
Ксавьер Комбель
эт
forked
, получает автоматически сгенерированный метод доступа в Solidity.Ксавьер Комбель
эт
msg
иtx
переменные). Не стесняйтесь задавать вопросы и добро пожаловать на сайт!