Создание блокчейн проекта с использованием алгоритма «Стрибог»

как создать блокчейн проект

Блокчейн и все, что с ним связано, нынче у всех на слуху, и на сегодняшний день вряд ли можно найти издание, которое обошло эту тему своим вниманием. Мы тоже не оставались в стороне и в свое время подробно разобрались, что собой представляет блокчейн, зачем он нужен и что можно с ним делать. Сегодня мы попробуем рассмотреть данную тему с практической стороны и напишем простейший локальный блокчейн. Сразу оговорюсь, что до полноценного блокчейн-проекта ему далеко, однако с его помощью вполне можно получить общее представление о том, как работает эта технология изнутри.

Вас также может заинтересовать: Лучшие ICO-компании

Общая структура нашего блокчейна

Итак, наш блокчейн (как и положено) будет представлять собой цепочку из блоков, каждый из которых включает в себя следующее:

  • номер блока [index];
  • метка времени [timestamp];
  • содержание транзакции [transaction];
  • значение так называемого доказательства работы [proof] (о том, что это такое, чуть ниже);
  • значение хеш-суммы предыдущего блока [previous hash];
  • значение хеш-суммы текущего блока [hash].

В содержание транзакции мы включим отправителя денежных средств [sender], имя получателя этих средств [recipient] и количество переданных денежных средств [amount]. Для простоты в блок будем включать сведения только об одной транзакции.

Общая структура блока, таким образом, будет выглядеть вот так:

Помимо очередных текущих блоков, блокчейн должен включать в себя начальный (или первый) блок, с которого, собственно говоря, и начинается вся цепочка блоков. Этот блок называется genesis-блоком, и он, в отличие от текущих блоков, содержит в себе только номер (который всегда равен нулю), метку времени, какое-либо рандомное значение вместо хеш-суммы предыдущего блока (поскольку genesis-блок первый и предыдущего блока у него просто-напросто нет) и собственное значение хеш-суммы:

В целом наш блокчейн будет выглядеть следующим образом.

Создание блокчейн проекта
Общая схема нашего блокчейна

Функция подсчета хеш-суммы

Поскольку для подсчета хешей мы собрались использовать алгоритм «Стрибог», нам необходима соответствующая функция. Ее мы напишем, используя код из указанной статьи. Качаем его отсюда и подключаем в наш проект нужные файлы следующей строчкой:

Саму функцию объявим так:

Далее объявляем структуру для хранения результатов подсчета хешей и выделяем для нее память:

Поскольку в теле блока значения хеш-сумм представлены в виде строк, то функция должна получить на вход содержимое блока в виде строки. Для этого напишем следующее:

Далее считаем хеш:

Поскольку выход функции тоже должен быть в виде строки, а рассчитанное значение хеша представлено в виде байтового массива, нам необходимо сделать соответствующее преобразование. Сделаем это следующим образом (HASH_SIZE — длина хеш-суммы, 512 или 256 бит, выберем 256):

Функция по расчету хешей у нас готова, можно писать дальше.

Файл block.h

В этом файле опишем класс CBlock, в который войдет все, что нам нужно для создания блока (как очередного, так и genesis-блока). Однако прежде чем описывать сам класс, определим структуру, которая будет описывать транзакцию. Как мы уже решили, транзакция будет включать в себя три поля — отправитель, получатель и сумма транзакции:

Теперь можно приступить к описанию нашего класса CBlock. В него входит public-секция, включающая два конструктора (тот, который без параметров, служит для инициализации genesis-блока, а тот, который с параметрами, — для инициализации очередных блоков); метод, создающий genesis-блок; метод, с помощью которого будет майниться очередной блок; метод, записывающий значение хеша предыдущего блока в нужное место текущего блока; метод получения значения хеша блока из соответствующего поля и private-секция со всеми необходимыми полями (номер блока, имя блока, метка времени и так далее) и одним методом подсчета хеш-суммы:

Теперь можно написать реализацию всех указанных методов. Все это мы поместим в файл block.cpp.

Файл block.cpp

В начале не забудем написать

Конструктор для инициализации genesis-блока

Как было сказано выше, конструктор без параметров нужен для инициализации genesis-блока. Поле, содержащее метку времени, инициализируется значением текущего времени, поле с именем блока — строкой «Genesis block», все остальное по нулям:

Конструктор для инициализации очередного блока

Здесь мы инициализируем все поля нужными значениями (очередной номер блока, имя блока, например «Current block», значения полей транзакции и так далее):

Создаем genesis-блок

Основное, что нужно сделать, — это сгенерировать рандомное значение хеша для записи его в место, предназначенное для хеша предыдущего блока.

Майним очередной блок

Основная цель майнинга — сделать так, чтобы формирование очередного блока было некоторым образом затратным (в общем случае требовало времени и значительных вычислительных ресурсов). Для этого реализуем алгоритм доказательства работы (Proof of work) по аналогии с большинством известных криптовалют. Суть этого алгоритма заключается в переборе подсчитанных хеш-сумм блока, пока не выполнится определенное условие. Для того чтобы значения хеш-суммы блока при каждой итерации подсчета были разными, нужно каждую итерацию каким-то образом менять что-либо в содержимом блока. Для этого мы в описании класса определили поле proof, значение которого каждую итерацию будем увеличивать на единицу. Условием, по которому будем прекращать итерационный подсчет хеш-сумм, будет наличие в начале получившейся в результате очередной итерации хеш-суммы определенного количества нулей. В общем случае чем большим количеством нулей в начале хеша мы зададимся, тем большее количество итераций необходимо проделать, чтобы получился искомый хеш. Количество нулей в начале хеша определяется уровнем сложности diff.

создание блокчейна stribog
Общая схема доказательства работы (Proof of work)

Исходя из всего этого, метод, реализующий майнинг блока, напишем следующим образом:

Считаем хеш очередного блока

В предыдущем методе использовался метод calc_hash(), с помощью которого и осуществляется подсчет хеш-суммы блока. Тут все просто — содержимое блока засовываем в одну строку и с помощью функции get_hash_stribog(), которую мы описали в самом начале, получаем искомое значение хеша от получившейся строки:

Записываем в блок значение хеша предыдущего блока

Здесь все просто, обычный сеттер:

Читаем значение хеша блока из поля hash

Здесь также все очень просто:

Итак, класс CBlok, из которого в дальнейшем мы будем делать блоки, мы описали и реализовали, теперь нужно эти блоки складывать в цепочку. Для этого напишем класс CBlockchain.

Файл blockchain.h

В начале подключим описание класса CBlock:

В public-секцию класса запишем:

  • конструктор с входным параметром in_diff, задающим сложность майнинга блоков;
  • метод, добавляющий в блокчейн genesis-блок;
  • метод, добавляющий в блокчейн очередной блок.

В private-секцию определим:

  • поле, в котором будем хранить значение сложности майнинга;
  • поле, в котором будем хранить цепочку наших блоков, представляющее динамический массив типа vector (чтобы это сделать, не забудь подключить соответствующую библиотеку vector.h);
  • метод возвращающий предыдущий блок из цепочки, для того чтобы вытащить из него хеш-сумму.class CBlockchain {
    public:
    CBlockchain(uint32_t in_diff);
    void add_genesis_block(CBlock new_block);
    void add_block(CBlock new_block);private:
    uint32_t diff; // Сложность майнинга
    std::vector chain; // Цепочка блоков
    CBlock get_last_block() const;
    };

Класс CBlockchain описан, можно писать его реализацию.

Вам может быть интересно: Как запустить свое ICO

Файл blockchain.cpp

В первой строчке подключим только что написанный blockchain.h:

Инициализируем блокчейн

Конструктор класса включает одну строку, в которой очищается массив для хранения блоков.

Добавляем genesis-блок

В метод для добавления genesis-блока запишем функцию его создания из класса CBlock, после чего созданный блок помещаем в начало массива для хранения блоков:

Добавляем очередной блок

В этом методе получаем хеш предыдущего блока, майним очередной блок (с учетом поля diff) и помещаем смайненный блок в массив:

Здесь используется метод get_last_block(), возвращающий предыдущий блок, чтобы из него можно было прочитать значение его хеш-суммы. Написать его особых сложностей не представляет:

Запустив получившийся блокчейн у себя на компьютере, я попробовал смайнить три блока с разными уровнями сложности майнинга. Для сложности, равной шести, три блока майнились немного меньше часа. Для семерки один блок майнился около полутора часов, дальше экспериментировать у меня терпения не хватило.

создание собственного блокчейна
Результаты майнинга трех блоков (с уровнем сложности, равным шести, три блока майнились пятьдесят минут)

Диспетчер задач при этом показывал, что основные усилия процессора направлены исключительно на решение задачи Proof of work.

создание блокчейн проекта
Диспетчер задач сигнализирует, что на данный момент самая затратная задача — майнинг блоков

Рекомендуем к прочтению: Создание биткойн-майнера на Java

Заключение

Конечно, мы упростили и не учли очень многое: и распределенность самого блокчейна, и процедуры достижения консенсуса, и возможность включения большего количества транзакций в один блок, и подтверждение целостности этих транзакций с помощью деревьев Меркла, да и много чего еще… Но во-первых, в одну статью это все никак не уместить, а во-вторых, цель статьи все-таки немного другая — положить начало в не совсем легком, но весьма интересном деле освоения этого перспективного направления. Дальше качай White Paper Bitcoin (в том числе и на русском), исходники Bitcoin и Ethereum, читай, вникай, разбирайся.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий