Попробуем описать в чем заключалась проблема и почему стали недоступны около $300 млн.
Что такое multi-sig кошельки
Multi-sig(nature) кошельки созданы для решения проблемы повышения защиты приватного ключа, так как для совершения транзакции необходимы 1 и более приватных ключей (в общем виде M из N ключей). Пример для случая 2 из 3 ключей: один ключ хранится локально, один в облаке, и еще 1 резервный (в укромном месте). Для совершения транзакции нужны 2 ключа. Чуть подробнее можно почитать здесь
Пользователь GitHub devops199, экспериентируя с публичными методами общедоступных смарт-контрактов вызвал метод
kill
смарт-контракта (библиотека Parity Wallet). Issue #6995 на GitHub.В результате этого 584 кошелька на общую сумму около 1 миллиона ETH ($300 миллионов по текущему курсу) стали «заморожены», то есть пропала возможность перевести с них деньги.
Картинка с комментариями devops199
Технически говоря, сперва он вызвал метод инициализации контракта initWallet
function initWallet(address[] _owners, uint _required, uint _daylimit) only_uninitialized {
initDaylimit(_daylimit);
initMultiowned(_owners, _required);
}
Модификатор
only_uninitialized
описан так // throw unless the contract is not yet initialized.
modifier only_uninitialized { if (m_numOwners > 0) throw; _; }
Однако при размещении контракта список владельцев не был инициализован, и переменная
m_numOwners
была равна 0. Историю всех операций с контрактом можно посмотреть здесьВ результате вызов
initWallet
позволил devops199
стать владельцем контракта (при вызове initWallet по адресу смарт-контракта библиотеки, она превратилась в обычный кошелек с владельцем msg.sender
, то есть devops199
). Далее можно просто выполнить
kill
для удаления, что и было сделано: // kills the contract sending everything to `_to`.
function kill(address _to) onlymanyowners(sha3(msg.data)) external {
suicide(_to);
}
Операция
suicide
в EVM используется для уничтожения контракта и переводит весь оставшийся баланс на указанный адрес. При этом suicide
эффективнее операции send
и стоит отрицательное значение газа так как освобождает место от данных контракта в блокчейне.Так как вся логика работы multi-sig кошелька была зависима от контракта, все владельцы, создавшие кошелек после 20/07/2017 (а это фактически все их пользователи, так как до 20 июля была другая уязвимость) потеряли доступ к возможности делать переводы своих средств кошельков Parity Wallet. Исправить ошибку можно лишь очередным форком Ethereum-a, но этого конечно не будет.
Полагаю, что проблему можно было бы легко избежать, если бы Parity убрала функцию
kill
при публикации смарт-контракта библиотеки. Она полезна лишь на момент тестирования, но никак не в целевой системе. Таким вот образом закончилась история кошельков Parity Wallet и $300 млн, которые больше нельзя истратить.
Не забывайте удалять код для тестирования, перед передачей в production!