Предисловие
Да, Вы только вдумайтесь, централизованная криптовалюта на PHP, это не правильно. Но мои ограничения на идеи все же пробились, поэтому, как Вы уже догадались, решил написать об этом. В самой первой части, мы расскажем, что такое криптовалюта, обсудим первоначальные конспекты, и сделаем систему кошельков. А теперь, приступим.
Криптовалюта, что из себя представляет?
информация взята из Википедии
Криптовалю́та — разновидность цифровой валюты, учёт внутренних расчётных единиц которой обеспечивает децентрализованная платёжная система (нет внутреннего или внешнего администратора или какого-либо его аналога), работающая в полностью автоматическом режиме.
Сама по себе криптовалюта не имеет какой-либо особой материальной или электронной формы — это просто число, обозначающее количество данных расчётных единиц, которое записывается в соответствующей позиции информационного пакета протокола передачи данных и зачастую даже не подвергается шифрованию, как и вся иная информация о транзакциях между адресами системы.
Вкратце криптовалюта работает так:
- Пользователь сети, имея баланс, отправляет другому анонимному пользователю транзакцию.
- Транзакция поступает в сеть.
- Майнеры (или-же пользователи, занимающиеся созданием блоков) решают сгенерированную по специальному алгоритму задачу с условиями (допустим, на наличие предшествующих 10-30 нулей в хеше, или наоборот).
- Когда условие (или условия) соблюдаются в хэше, благодаря ему, майнер отправляет в сеть блок, оповещающий о создании нового блока и выполнении транзакции.
- Получатель получает средства, а майнер — сумму вознаграждения, в виде комиcсии, просчитываемого при подготовки задачи.
Имеет ли смысл писать централизованную криптовалюту, и к тому же на PHP?
Я считаю, не очень. Но, попробовать еще как стоит.
Учитываем конспекты перед разработкой
Мы будем использовать двойную систему проверки хешей используя Proof-of-Work. Имеет смысл делать проверку хешей на программном и сетевом прикладном уровне. Это связано с процессом оптимизации нагрузки на сервера. Поскольку, когда мы будем обращаться к серверу за проверкой хеша много раз, появится такая нагрузка. Поэтому, предлагаю поступить следующим методом:
- На программном майнере локально проверять хеш на удовлетворение условий.
- Когда на программном майнере условия совпадут с необходимыми, делаем проверку на прикладном сетевом уровне (на уровне сервера).
Это, по-моему лучшему мнению, оптимальный способ распределения нагрузки. Проще несколько раз проверить на компьютере локально, чем много раз спамить запросами на сервер.
Название — я придумал простое, и возможно, запоминаемое название — FlyCoin с трех-значным кодом валюты FLC.
База данных — я воспользуюсь простым и удобным вариантом, PDO.
Криптокошельки — будут генерироваться используя GUID и mt_rand, а в качестве seed, будет использоваться время POSIX.
А тебе лень делать функцию проверки хеша? — Да, поэтому я решил взять код из одного старого (с открытым исходным кодом) майнера такой (уже умершей) криптовалюты Entropy, моего друга, Никиты.
Погнали!
Начнем с того, чтобы сделать каркас нашей будущей системы. Начнем, пожалуй с разработки прикладного API для нашей криптовалюты. А каркас, выглядит пока так пусто.
<?php /* * The API for FlyCoin */ function checkHash ($hash, $exp) // Где $hash - там находится наш итоговый хэш, а $exp - сложность. Функция взята из Entropy Miner, и подверглась комментированию. { $sum = 0; // Контрольная сумма нашего хеша. $len = strlen ($hash); // Cмотрим длину хеша. for ($i = 0; $i < $len; ++$i) $sum += 2 * base_convert ($hash[$i], 16, 10); // Проводим простую операцию для просчета контрольной суммы return $sum % 10 == 0 && substr ($hash, -$exp) === str_repeat ('0', $exp); // Возвращаем true, если хэш не годен, и true - если хэш годен. } class Block { public $id; // ID блока public $prev_hash; // Предыдущий хэш блока public $from; // От кого public $to; // Кому public $ammount; // Сумма public $difficult; // Сложность просчета } class API { protected $db; public function __construct () { $dsn = "mysql:host=localhost;dbname=flc"; // DSN для связи $dbh = new PDO ($dsn, $username, $password); // Попытка подключиться к базе try { return true; // Соединение удалось. } catch (PDOException $exception) { return false; // Разрыв соединения. } } }
Вот такой он, каркас нашего чуда. Первым делом мы реализуем регистрацию и генерацию GUID к нашим кошелькам. Я сразу же создал незаполненное определение функции API, а также нашел функцию генерации GUID в Google. Не забываем про seed. Я как раз нашел функцию получения seed, для уникального получения GUID.
function make_seed () // Взято из онлайн документации по PHP { list ($usec, $sec) = explode (' ', microtime ()); return $sec + $usec * 1000000; } mt_srand (make_seed ());
Прекрасно. А функция для генерации GUID для кошелька выглядит соответственно вот так (а также сама заглушка):
public function register () // Пустая функция регистрации { } protected function genGUID4 () // Сила Google { return sprintf ('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand (0, 0xffff), mt_rand (0, 0xffff), mt_rand (0, 0xffff), mt_rand (0, 0x0fff) | 0x4000, mt_rand (0, 0x3fff) | 0x8000, mt_rand (0, 0xffff), mt_rand (0, 0xffff), mt_rand (0, 0xffff)); // Я даже сам не понял, как это работает. }
Поскольку мы делаем все анонимно, мы не будем хранить IP или E-Mail. Никакого подтверждения. Нам и так будет достаточно. За ~25 минут я написал функцию регистрации. От нас потребуется только один пароль. Функция API вернет нам кошелек.
public function register ($password) // Где $password - там наш пароль { if ($this->db) // Защита от дурака { $walletId = 'FLC@' . $this->genGUID4 (); // Генерируем наш новый адрес кошелька $hash = crc32 ($walletId) . $walletId . hash_hmac ('sha512', str_rot13 ($password), 'FLC'); // Сложные вычисления пароля для хэша. $hash = hash_hmac ('sha512', $hash, 'FLC2'); // Сам пароль в виде хэша. $newUser = $this->db->prepare (" INSERT INTO `wallets` (walletId, loginHash, balance) VALUES (:walletId, :hash, :startBalance) "); // Готовим запрос в базу. $newUser->bindParam (':walletId', $walletId, PDO::PARAM_STR); // Привязываем кошелек к запросу $newUser->bindParam (':hash', $hash, PDO::PARAM_STR); // Привязываем хэш к запросу $newUser->bindParam (':startBalance', 0, PDO::PARAM_INT); // Привязываем стартовый баланс (нету никакого стартового баланса, ставим твердую 0!) к балансу $newUser->execute (); // Исполняем запрос. return ['walletId' => $walletId]; // Даем наш номер кошелька (это логин) } else return false; // Не удалось зарегистрировать кошелек в системе. }
Здесь я кратко описал, что делает та или иная строка.
«Привет можешь помочь? Я хранил на твоем блокчейне мани, и вдруг я потерял пароль помоги пожалуйста и будешь хорошим» — смело отклоняйте данное предложение. Суть криптовалюты — это хранение вскопанных чисел в безопасности. Никто так не докажет, что он или она является владельцем счета. Таким образом, любой злоумышленник может даже украсть чужие средства даже без участия самой жертвы! Не важно, хоть и действительно является этот человек владельцем счета, лучше отказывать. Если потерял деньги — значит не правильно хранил данные от счета. Ради дополнительной безопасности, далее мы не будем реализовывать восстановление пароля.
Функция получения хэша, представленную здесь можно представить еще так:
Функция работает так:
На вход поступает пароль, проверяем, подключена ли база данных:
Просчитываем plain-text хэша. В первом череду мы получим следующее: 0087196442FLC@c1cbe61d-a19d-4c82-ba17-3a577df0aeb59ee77779db5a44ef3f60044fcb0e1170218e642cb9adc0789ddd08871ad95c7e1d3b1391c6c79774d319b5141bd3b13b717c3d389206ede659cb280949feac66 (много букв, не удивляйтесь).
Во втором череду, хэш станет сто-процентным HMAC: 5e43cbb404c81efeb35162e5bba0766f20b340fbabcc66fd5f7a6a1993a8ccd43fc6384ac53f939acca4378681e2bb17912eacf4c65b8b63acda9aa2d15f5646 (опять же, много букв, использую SHA-512 HMAC).
Записываем это все в БД.
В ответ пишем номер кошелька, через который можно авторизоваться.
Так выглядит замудренная система регистрации. На деле она выглядит ну очень простой. А в плане кода — куда сложнее.
Потратим еще время, и сделаем авторизацию. С авторизацией дело обстоит по-проще. Мы ищем аккаунт, и пытаемся авторизоваться, зная уже знакомые нам алгоритмы генерации хэша пароля. Затем сверяем, и в случае верности данных, даем клиенту важную строчку, в которой хранятся данные для коммуникации между сервером и майнером.
Спустя еще 15-25 минут была готова и функция авторизации. Лицезрейте этот код ниже:
public function login ($walletId, $password) // Авторизация { if ($this->db) // Защита от дурака { $hash = crc32 ($walletId) . $walletId . hash_hmac ('sha512', str_rot13 ($password), 'FLC'); // Сложные вычисления пароля для хэша. $hash = hash_hmac ('sha512', $hash, 'FLC2'); // Сам пароль в виде хэша. $newUser = $this->db->prepare (" SELECT * FROM `wallets` WHERE walletId = :walletId AND loginHash = :hash LIMIT 0, 1 "); // Готовим запрос в базу. $newUser->bindParam (':walletId', $walletId, PDO::PARAM_STR); // Привязываем кошелек к запросу $newUser->bindParam (':hash', $hash, PDO::PARAM_STR); // Привязываем хэш к запросу $newUser->execute (); // Исполняем запрос. $object = $newUser->fetch_object (); // Соблюдаем использование ООП, делаем в виде объекта if ($object AND hash_equals ($object->hash, $hash)) // Если есть пользователь, и хэши совпадают. { $loginString = new stdClass; // Создаем пустое хранилище stdClass $loginString->hash = $hash; // Консервируем в него хэш и номер счета. $loginString->wallet = $walletId; return ['token' => serialize ($loginString)]; // С этой строчкой делаем что угодно, но не распространяем. } else return false; // Пользователь не существует/неправильный пароль. } else return false; // Не удалось войти }
Этот код — почти что регистрация, но действует в обратном алгоритме. Работа с пользователями подошла к концу.
Постусловие
За время этого занимательного времени прочтения статьи, мы сделали следующее:
- Вкратце познакомились с криптовалютой, и как она должна строится правильно.
- Коротко ответили на вопрос «Имеет ли смысл делать централизованную криптовалюту, и к тому же на PHP?»
- Обсудили конспекты перед выполнением данной задачи
- Реализовали систему крипто-счетов.
А теперь, Вы можете почитать, что было за жалюзями:
Что мы сделаем в следующий раз:
- Сделаем майнинг.
- Рассмотрим, как устроены транзакции и блоки.
- Сделаем транзакции, и дадим смысл пока-что не использованному классу Block.
Спасибо за прочтение! Еще увидимся! Это моя первая статья — жду критики.
ссылка на оригинал статьи https://habr.com/ru/post/481392/
Добавить комментарий