Криптовалюта набирає популярності, а майнінг ETH з алгоритму PoW (Proof of Work) вже давно перейшов на алгоритм Proof of Stake. Проте цікаво розуміти, як саме відбувається процес майнингу, так як інколи може знадобитись згенерувати необхідний хеш. У 2017 приходилось мати справу з монетою XRB де PoW потрібен був для переводу токенів, а у 2021-му – цей алгоритм використовується у P2E ігрі Alien Worlds для збору TLM.
Власне щоб писати код для генерації PoW токенів, потрібно в першу чергу розуміти як це працює. Тому напевне підходити до цього питання було б правильно тоді, коли зрозуміла концепція блокчейн. Але якщо потрібних знаннь немає – також не біда – розберемось.
Значить давайте уявимо, що у нас є якісь дані, які для зручності запису буду зберігати його в форматі json.
{"data":"Якесь повідомлення"}
У будь-який час я можу з цих даних отримати хеш sha256.
Результат буде мати приблизно такий вигляд: 362264c2d3d08e6a6508d314a77d430deed27ae391bf9e4b73f2cf37d18936e5
.
Власне це ключове поняття – на вхід у нас є дані, на виході – у нас sha256 хеш.
Є ще таке поняття як складність PoW. Простими словами результатом повинен бути хеш, у якого зліва буде необхідна кількість нулів. Виглядати це може так: 00057100260fc007b281fc7711787731da505d8762849baa36322fed9bfd297
. Але, проблема в тому, що з одних одинакових даних завжди буде получатись одинаковий хеш. Тому, потрібно ввести ще таке поняття як блок.
Блок це точно такий json з даними, який буде містити в собі інші додаткові поля. В криптовалюті там буде свій номер, унікальне значення nonce, хеш попереднього блока, а в якості даних там буде список транзакцій. Проте для демонстрації принципу, я обмежусь одним полем nonce з унікальним значенням і полем data з даними.
{"nonce":166495,"data":"Якесь повідомлення"}
Тепер, якщо у мене стоїть задача згенерувати хеш у якого зліва буде чотири нулі 0000, мій алгоритм дій повинен бути таким – устанавлюю nonce в значення 0. Генерую sha256. Перевіряю хеш – якщо те що получилось містить зліва чотири нулі 0000 – значить я знайшов шукане значення. В іншому випадку – збільшую nonce на 1 і знову генерую хеш. Так продовжується до того часу, поки не буде знайдене значення яке задовільняє умову.
Результат: 00000e7efdfda197cfff0f35ac404e5a4778c10b12ccb4974e4cdad0196046a5
– це і буде шукане значення.
Реалізація алгоритму PoW в C# для програми ZennoPoster буде мати такий вигляд:
long nonce = 0; string data = "Якесь повідомлення"; string sha256 = string.Empty; do { string json = Global.ZennoLab.Json.JsonConvert.SerializeObject(new{ nonce, data }); var sb = new StringBuilder(); using (var hash = System.Security.Cryptography.SHA256Managed.Create()) { var enc = Encoding.UTF8; foreach (var b in hash.ComputeHash(enc.GetBytes(json))){ sb.Append(b.ToString("x2")); } } sha256 = sb.ToString(); if(sha256.StartsWith("0000")) project.SendInfoToLog(json, true); else nonce++; } while(!sha256.StartsWith("0000")); return sha256;
Звичайно, що це спрощений варіант, адже тут перевіряється тільки умова на 0000, а у реальних умовах може бути набагато більше, наприклад у мережі Bitcoin зараз повинно бути приблизно 19 нулів зліва (подивився у блокчейні останній блок – 0000000000000000000 ).
Також я вище писав про те, що дані у мене находяться у json. Проте в залежності від умов, які поставили розробники дані можуть бути і у xml, і у base64, і у вигляді звичайного масиву байт. Тому, у реалізацію в кожному конкретному випадку потрібно вносити поправки.
З іншої сторони – приблизне бачення того, як саме відбувається майнинг (а власне пошук потрібного хеша з накладеними на нього обмеженнями методом підбору nonce і є майнингом або Proof of Work) я думаю мені получилось показати. Навіть код получився робочим, який можна запустити в програмі ZennoPoster, попробувати поміняти дані, поміняти кількість нулів в хеші (щоб зрозуміти наскільки довше шукається хеш при зміні умови). Щоб не вимірювати час вручну – можна скористатись способом вимірювання часу виконання блоків кода в проєкті ZennoPoster, про це писав у цій публікації