[Из песочницы] Как я писал свою криптовалюту с нуля на PHP
3 года назад у меня появилась мысль создать свою криптовалюту. От биткоина решил взять идею с нодами и блокчеином. В голове вертелось что-то вроде раздачи валюты всем жителям земли. Но как их идентифицировать, как сделать, чтобы они не потратили всё сразу, как решать, кто будет генерировать следующий блок?
Я решил сделать привязку каждой ноды к человеку. Каждый, кто хочет стать майнером, должен заснять на видео своё лицо и сделать фото. При проверке сранивается фото и видео, чтобы убедиться, что лицо одно и то же. Видео нужно только потому, что подделать его практически невозможно, в отличие от фото.На фото нужно нанести точки в определенные части лица, чтобы при поиске по БД сравнивать пропорции.Проверяют это всё майнеры, которые ранее уже прошли такую проверку. В итоге нужно набрать 10 положительных голосов и менее 10 отрицательных в течение суток.Всё это происходит путем рассылки транзакций и блоков между нодами, никаких центральных серверов нет. Все фото/видео находятся в паблике.Если подкупить 10 майнеров, чтобы они проголосовали за Вас, то это не будет гарантией, что Вы станете майнером, т.к. остается шанс поймать 10 минусов.
Также предусмотрен запасной вариант, когда клоны уже проникли в DC-сеть. В этом случае на них кто-то должен отправить транзакцию с жалобой (ParseData→abuses ()). Тогда админ, т.е. я, получает право отправить транзакцию, которая переведет данного майнера в ряды простых пользователей.Всего админу доступно 11 типов транзакций, все они обрабатываются методами из ParseData: admin_1block — Обработка самого первого блока.admin_add_currency — Добавление новой валюты. Сейчас там не все нац валюты, а только основные.admin_answer — Ответ на баг-репорт.admin_ban_miners — Перевод майнеров из майнеров в юзеры, если на него была жалоба. При этом всё, что успело найманиться остается в распоряжении пользователя.admin_message — Короткое сообщение, которое показывается в интерфейсе.admin_blog — На будущее, вдруг нужно будет сообщить что-то, что не влезет в короткое сообщение.admin_new_version — Заливка новой версии.admin_new_version_alert — Выдает алерт в интерфейсе, что нужно обновиться.admin_spots — Всё для поиска клонов — наборы точек, совместимость версий точек, из каких точек составляем отрезки, допустимые расхождения.admin_unban_miners — Перевод разжалованного майнера обратно в майнеры.admin_variables — Переменные, в БД таблица variables. Потом планирую сделать константами.
Я сразу перечислил все возможности админа, чтобы ни у кого не возникало вопроса —, а может ли админ заблокировать аккаунт с деньгами? Нет, не может, максимум, что разрешено админу, — это понижение привилегий у аккаунта без затрагивания находящихся на аккаунте средств (admin_ban_miners).
Обозначения Само слово miner (в переводе шахтер) наверное не очень подходит для обозначения пользователя с повышенными привилегиями. Но исторически сложилось, что у меня везде используется miner.Порядок генерации блоков Все ноды делятся на уровни в зависимости от текущего хэша заголовка (node_id, block_id, prev_head_hash).Нод, который находится на 0-м уровне, определяется методом testblock→get_block_generator_miner_id ()Если, например, сейчас на 0-м уровне нод ID 12689, то на 1-м уровне будут ноды 12690–12691, на 2-м — 12692–126995 и т.д. Если нод на 0-м уровне не смог сгенерировать блок, то в работу включаются ноды 1-го уровня, если и они не смогли, то 2-го и т.д. Т.е. злоумышленник не сможет сделать так, чтобы блок генерировали именно его ноды.Генерация монет Теперь у нас есть ноды, за каждой из которых закреплен один живой человек. Можно было бы просто раздать по X монет каждому майнеру. Но мне почему-то эта идея сразу не понравилась, как потом выяснилось, не зря. Вот пример того, что могло бы произойти — habrahabr.ru/post/217111/ и далее — coinmarketcap.com/aur_90.html.Еще у меня из головы не выходила мысль о том, что если Dcoin станет популярен, то с ним могут начать бороться власти путем введения санкций против бирж. Нужен был механизм, который позволял бы существовать Dcoin без бирж, банков и прочих посредников.Да, кстати, Dcoin — это сокращенно от Democratic Coin, оно же — DC.Решение оказалось довольно простым. Нужно совместить раздачу монет с функцией обмена Dcoin на наличные. Для этого мне понадобилось скопировать основные валюты в Dcoin. Я просто прибавил букву D к 3-х буквенному коду валюты. Получилось DUSD, DEUR, DRUB и т.д. Если майнер хочет купить, например, 1000 DUSD, то он отправляет в DC-сеть транзакцию, в которой указано, что он хочет купить 1000 DUSD за 1000 USD. Но желающих продать DUSD может не быть. Майнер должен быть готов ждать неопределенный срок, пока найдется продавец DUSD.
Теперь, у нас есть, например, 100к записей в нашей распределенной БД о том, что майнеры готовы купить DUSD на 100 млн. $. Осталось создать DUSD. Все, наверное, подумали о премайне. Но я не верю, что кто-то захочет заплатить мне $ за какие-то там DUSD, поэтому сразу нет. Да и вместо премайна было бы логичнее просто раздать монеты.
Я решил начислять на счет майнера DUSD за то, что майнер ждет, пока кто-то захочет продать ему DUSD.Начисляются DUSD по следующей формуле: nDUSD = bDUSD*((1+K)^T)-bDUSDгде nDUSD — новосозданные DUSD, bDUSD — сумма DUSD, которую майнер готов купить, K — коэффициент, про который напишу ниже, T — время в секундах.Т.е. чем больше DUSD готов купить майнер и чем дольше он ждет, пока ему их кто-то продаст, тем больше новых DUSD создается и начисляется ему на счет.В исходниках эта формула находится в методе ParseData→calc_profit (). calc_profit включает еще несколько параметров, но если начну описывать и их, то будет слишком занудно и длинно. Но если кому-то интересно, то напишу.
Коэффициент К Это очень важный коэффициент, т.к. от него зависит эмиссия. Я долго думал, каким его сделать, к каким параметрам привязать. Ведь он не должен поддаваться накрутке. Самым демократичным вариантом оказался тот, где этот коэффициент определяют сами майнеры данной валюты путем голосования. Для удобства, в интерфейсной части коэффициент К отображается как %/год. Допустимые значения от 0 до 1000%/год. В исходниках ParseData→votes_complex (). Майнер может голосовать только за те валюты, которые были добавлены у него более чем $variables['min_hold_time_promise_amount'] секунд назад. Для защиты от атак клонов, чтобы они не смогли дестабилизировать сеть своими голосами.Пересчет голосов и обновление коэффициентов делается каждые $variables['new_pct_period'] секунд. Сейчас там 2 недели.Теперь у нас в распределенной БД есть не только обещания майнеров купить 100 млн. DUSD, но и их голоса за скорость эмиссии, т.е. за коэффициент К. И через какое-то время на счетах майнеров начнут появляться первые DUSD.
Получается, что обычный майнер должен просто указать, что он готов отдать 1000$ за 1000 DUSD, и если по результатам голосования будет выбрано, например, 900%/год, то через месяц у него будет +200 DUSD, а через год +9000 DUSD, которые эквивалентны 9000$.Но я не рекомендую заигрываться с верхними пределами коэффициента. Про последствия будет написано ниже.
WOC По аналогии с ru.wikipedia.org/wiki/Wocu я сделал WOC. Она начисляется каждому майнеру, её нельзя обменять на наличные у другого майнера. Её можно переводить с кошелька на кошелек. По идее, WOC должна заменить доллар на пьедестале мировой валюты.Биржи Если они будут — хорошо, но если их запретят — то не страшно. В крупных городах, я думаю, предпочтение майнеров будет отдаваться встроенному механизму обмена, ведь он переводит валюту Dcoin сразу в наличные деньги.Географические и национальные ограничения Возможно большинство майнеров будет против того, чтобы майнинг их национальной валюты происходил где-то за пределами их страны или валютного союза, либо захотят, чтобы майнеры находились только в крупных городах. По-этому при добавлении какой-либо валюты майнеру нужно будет записать видео, в котором он будет говорить на своем национальном языке, что-то вроде: «Я обещаю отдать 100 норвежских крон за 100 DNOK». Далее нужно будет указать страну и отметить точку на карте. И запрос должны будут утвердить 10 майнеров, у которых майнится Норвежская крона. Возможно майнеры DNOK введут правило, по которому новые майнеры DNOK должны будут снять видео на фоне какого-нибудь известного памятника в крупном городе Норвегии.Инфляция Я не знаю, как поведут себя майнеры и за какой коэффициент они будут голосовать. Но не исключен такой сценарий, когда, например, DUSD будет создано больше, чем нужно рынку. Если DUSD будет торговаться на биржах, то курс упадет ниже 1:1, т.е. за 1 DUSD будут давать, например, 0.9 USD. В этом случае майнеры должны проявить сознательность и уменьшить общую массу DUSD. Путем того же голосования. Например, >50% проголосуют за уменьшение на 10% и в БД вместо 100 млн. DUSD у всех станет 90 млн. DUSD (ParseData→reduction ()), что, скорее всего, вернет курс на 1:1.Также майнеры могут проголосовать за изменение максимальной обещанной суммы и за количество валют, которые могут майниться вместе (ParseData→votes_complex ()).Простые пользователи Кроме майнеров есть еще простые пользователи. Для них не нужно ни фото, ни видео, они полностью анонимны. Они могут только принимать и отправлять монеты Dcoin. Держать свою ноду пользователю не нужно. Он может просто отправлять свои транзакции на любую ноду в DC-Сети.Майнеры могут проголосовать за то, чтобы монеты простых пользователей росли на их кошельках. Например, на 30%/год. Т.е. простой пользователь может купить на бирже какое-то кол-во DUSD, например 10к, и через год у него будет 13к DUSD. Я не знаю, нужна ли такая фича, если не нужна, то майнеры могут просто держать % для пользователей равным нулю, и ничего расти не будет.Новые пользователи С этим тоже пришлось помучиться. Ведь если дать возможность слать транзакции с регистрацией новых пользователей всем подряд, то кто-то возьмет да сгенерирует 1 млрд транзакций и захламит всю DC-сеть. Вначале сделал с инвайтами, но выяснилась проблема — транзакцию с регистрацией, в которой указан инвайт, можно перехватить и использовать инвайт самому. Поэтому транзакцию с регистрацией нового пользователя может отправлять только майнер и не более $variables['limit_new_user'] за $variables['limit_new_user_period'] секунд. Сейчас там 2 за месяц.Защита от хищения праймари ключа К аккаунту можно прикрепить до 3-х праймари ключей. Это значит, что для принятия DC-сетью любой Вашей транзакции будет требоваться 3 подписи. Один ключ Вы можете хранить у себя, два других, например, на каких-нибудь сторонних сервисах, которые будут подписывать Ваши транзакции только если Вы введете смс-код.Пара слов о процессе разработки То, что уйдет 3 года, я не представлял даже в самом страшном сне. Я думал управиться за несколько месяцев. По этой же причине писал на том языке, который знал на более-менее приемлемом уровне. Если бы вернуться в прошлое на 3 года, то, наверное, использовал бы C++.Первые 2 с половиной года работал по вечерам и выходным, что жутко раздражало, но полгода назад избавился от работы, которая мешала, и стал уделять всё время Dcoin. Последние 3 месяца по 10–16 часов в сутки искал и исправлял баги. Думал, максимум месяц — и багов не будет, а нет — 3 ушло.Очень много тонкостей работы Dcoin я не описал, т.к. иначе получится слишком длинная статья, которую будет сложно читать. В Dcoin 41 тип транзакций, методы, которые их обрабатывают, находятся в классе ParseData. Пишите вопросы, всё поясню.Комментарии в исходниках сожержат множество ошибок и опечаток, потом обязательно подчищу. Код написан, скорее всего, не очень грамотно, но главное, что всё работает.Установка При установке требуется приватный ключ. Его можно взять либо тут, либо у какого-нибудь майнера. Проверить на занятость можно тут.Установка простая и занимает около 2–3 минут. Чтобы акканут не занял кто-то другой, нужно сразу сменить ключ.Можно использовать пока только на 32-х битных ОС. Нужно переписать пару функций, в частности pow, и будет совместимо и с 64-х битными.На тестах использовал простые ВПС с 512 ОЗУ и 700Mhz CPU, на первое время таких мощностей будет вполне достаточно.Нужен apache или nginx, PHP >5.2.4, Mysql >5.0.Если будете ставить на win, то лучше используйте nginx, я тестировал с winginx.