Уважаемые пользователи Голос!
Сайт доступен в режиме «чтение» до сентября 2020 года. Операции с токенами Golos, Cyber можно проводить, используя альтернативные клиенты или через эксплорер Cyberway. Подробности здесь: https://golos.io/@goloscore/operacii-s-tokenami-golos-cyber-1594822432061
С уважением, команда “Голос”
GOLOS
RU
EN
UA
shwanoff
6 лет назад

Блокчейн (blockchain) на языке C#

Блокчейн (blockchain) – это технология распределенного хранения данных в одноранговой сети в виде непрерывной последовательности блоков взаимосвязанных с помощью алгоритма хеширования. Давайте подробнее познакомимся с этой технологией и рассмотрим пример ее реализации на языке программирования C#.

Что такое Блокчейн?

Как я уже писал выше блокчейн это распределенное хранилище данных. То есть, блокчейн можно представить себе как непрерывную последовательность зависящих друг от друга блоков, содержащих как полезную информацию, так и дополнительные служебные данные, которые гарантируют достоверность хранимой информации. Главной особенностью данной технологии является распределенность (децентрализация) – не существует единого центрального хранилища данных, каждый пользователь хранит у себя полную копию всей информации. Каждый экземпляр хранилища синхронизуется с другими по заданным системой правилам. Второй важной особенностью блокчейна является ее криптозащищенность. Под этим подразумевается использование специализированных алгоритмов хеширования данных, которые гарантируют их целостность и неизменность. Это особенно важно, если брать во внимание, что не существует эталона данных, каждый экземпляр является полноценным и равным другому. Поэтому очень важно защищать данные от внесения изменений. Давайте чуть подробнее рассмотрим принцип работы технологии блокчейн.

Как работает Блокчейн?

Вводимые данные «упаковываются» в специализированные блоки. В данном блоке содержится дополнительная служебная информация, которая необходима для обеспечения целостности и неизменности введенных данных, а также для работы самой цепочки блоков. Сама по себе цепочка блоков очень похожа по структуре на односвязный список. Подробнее данная структура данных описана в статье Связный список (Linked List) C#. Блок данных содержит следующие важные поля:

  • Data – поле, в котором сохранены сами полезные данные. Это может быть как простая строка, так и более сложные структуры.
  • CreatedOn – дата и время создания блока данных. Важно использовать универсальное UTC время, чтобы не возникало конфликтов из-за разных часовых поясов.
  • Hash – уникальный ключ, созданный на основе хранимых данных блока с помощью специализированной хеш-функции, которая подразумевает только одностороннее шифрование.
  • PreviousHash – указатель на предыдущий хеш-блока. Это необходимо для связывания блоков в единую цепочку.

Также возможно использование и дополнительных данных, в данном случае также использовались следующие поля:

  • User – данные о пользователе, создавшем блок
  • Algorithm – используемый алгоритм хеширования
  • Version – версия блока

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

Что такое хеширование?

Хеширование – это процесс преобразования входных данных произвольной длины в значение определенного формата, путем преобразования по заданному алгоритму. Основной особенность хеш-функции является возможность легкого преобразования входных данных в хеш, и невозможностью однозначного восстановления исходных данных из хеша.Рассмотрим пример самой элементарной хеш-функции, это суммирование всех цифр числа. Например, если на вход мы получим число 73, то хешем данного числа будет 7 + 3 = 10. Это очень простая операция, которая позволяет получить хеш. Но вот обратное преобразование однозначно выполнить невозможно, так как существуют многие числа, дающие такой же результат: 64, 37, 181, 11116 и так далее.Конечно же, это очень простой пример, и настоящие хеш функции намного сложнее, но принцип работы у них всех идентичен – получение ключа на основе входных данных, при условии, что даже минимальное изменение входных данных приведет к изменению ключа.

Реализация Блокчейн на языке C#

Обратите внимание, что в данной статье рассматривается прототип приложения, а не готовый к использованию продукт. Код далеко не идеален, и не весь изначально задуманный функционал реализован, но для знакомства с технологией блокчейн этого более чем достаточно. Изначально, данный проект реализовывался в рамках ежегодного соревнования среди разработчиков департамента CRM компании ООО «Норбит» (New Year Coding Challenge 2018).Вот краткая формулировка задачи: необходимо разработать защищенное хранилище информации на базе технологии блокчейн. Решение должно обеспечивать хранение информации без возможности модификации (кроме полного стирания всех данных). Решение должно позволять хранить произвольный набор данных в виде строки размером до 5 МБ. Кроме того, необходимо реализовать ролевую модель пользователей и возможность разделения хранимых данных по типу.Приложение разделено на несколько проектов.

  • BlockchainData — уровень данных. Я заранее предусмотрел возможность расширения возможных средств для сохранения данных. В данном случае используется единственная реализация сохранения в базу данных MS SQL с использованием EntityFramework.
  • Blockchain — уровень логики. Здесь реализованы все основные классы и логика работы приложения.
  • BlockchainService — WCF-служба, предоставляющая REST API интерфейс для клиентских приложений.
  • BlockchainExplorerDesktop — WinForms-приложение для просмотра данных хранимых в блокчейн.
  • BlockchainExplorerWeb — MVC ASP.NET приложение для просмотра данных хранимых в блокчейн.

Рассмотрим подробнее реализацию основной библиотеки классов Blockchain.dll.

Реализация цепочки блоков Chain

Итак, основным классом библиотеки является класс Chain.cs. Он взаимодействует с уровнем данных использую принципы инверсии управления и внедрения зависимостей. Подробнее про это можно прочитать в статье Инверсия управления и Внедрение зависимостей (IoС & DI). Таким же образом реализован подход к алгоритму хеширования. Chain содержит в себе список всех блоков в хранилище данных, а также подсписки для разделения блоков по типам (блоки данных, блоки с данными о пользователях, блоки с данными о IP адресах серверов). При создании экземпляра класса цепочки блоков выполняется обращение к глобальной сети для синхронизации с другими хостами. Также выполняется получение блоков из локального хранилища. На данный момент не реализовано корректного алгоритма слияния этих двух цепочек. Выбирается просто выбирается наиболее длинная цепь. Если не было получено ни локальной, ни глобальной цепочки, то выполняется создание новой цепочки состоящей из одного генезис-блока. Генезис блок — это единый начальный блок цепочки. Он всегда генерируется по одинаковым правилам у всех экземпляров блокчейн. После создания экземпляра цепочки выполняется ее полная проверка на корректность, чтобы удостовериться, что не было внесено никаких изменений.

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

Реализация блока цепочки Block

Класс блок реализует структуру блока данных. Он содержит в себе все необходимые поля, которые должны быть сохранены в хранилище данных. При создании блока выполняется хеширование входных данных, а также хеширование всего блока, что позволяет гарантировать неизменность хранимых данных и метаданных. При выполнении хешированию учитываются следующие поля: версия, время создания блока, хеш предыдущего блока, хеш хранимых данных, хеш пользователя. Результат сохраняется в поле Hash блока, что позволяет легко проверить его корректность.

Реализация класса хранимых данных Data

Класс данных необходим больше для удобства работы. Он позволяет сохранять строковые данные, получать хеш хранимых данных, а также разделять хранимые данные по тип (данные о пользователях, данные о серверах, простые хранимые текстовые данные). Для корректного сохранения контента выполняется сериализация и десериализация в json формат.Сериализация — это процесс преобразования объекта в поток байтов, десериализация — это обратный процесс, позволяющий сформировать из потока байтов готовый объект. Если сформулировать это более простым языком, мы выполняет сохранение всех значений объекта в специализированном тестовом формате json. Данная тема будет мной подробнее рассмотрена в одной из моих следующих статей.

Реализация класса пользователя User

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

Интерфейсы IHashable и IAlgorithm

Обратите внимание, что важной особенностью данной реализации является использование специального интерфейса IHashable, который должны реализовывать все классы, которые подвергаются хешированию (такие как Block, User, Data). Этот интерфейс реализует всего одно свойство и один метод. Свойство строковое Hash гарантирует, что у класса будет поле, в которое будет выполнено сохранение готового хеша объекта, а метод GetStringForHash возвращает строку, в которой хранятся все тестовые данные, важные для хеширования.Данный интерфейс используется в другом интерфейсе IAlgorithm. Данный интерфейс используется для того, чтобы предоставить возможность дальнейшего расширения возможностей приложения, путем легкого добавления дополнительных алгоритмов хеширования. Данный интерфейс определяет один перегруженный метод GetHash, которвый возвращает либо хеш стоки, либо хеш класса, реализующего интерфейс IHashable.В данный момент реализован один алгоритм хеширования Sha256 в соответствующем классе.Для корректности работы классов, реализующих данные интерфейсы используется проектирование по контракту. Это позволяет задать предусловия и постусловия для всех классов, которые реализуют данные интерфейсы. Благодаря этому гарантируется минимальная проверка параметров у всех наследников. Подробнее данную тему можно изучить в статье Программирование по контракту (Code Contracts) в C#

Заключение

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

Сразу поделюсь некоторой дополнительной информацией. В качестве эксперимента, при демонстрации проекта на конкурсе я использовал Azure. Вещь очень удобная, приложения публикуются без каких-либо проблем, базы данных создаются и отлично работают, службы тоже. Но я столкнулся с двумя проблемами. Первое, разница в часовых поясах. Серверное время у службы было австралийским, из-за этого были большие проблемы при хешировании, так как время менялось. Проблему еще сильнее усугубил EntityFramework, который некорректно сохранял время в UTC. Пришлось немного поплясать с бубном. Второе, Azure очень дорогой. За 1 месяц у меня ушло около трех тысяч рублей, на базу данных, службу и веб-приложение. Кстати, конкурс я успешно выиграл. Надеюсь, эта статья была достаточно полезной и интересной, не смотря на большой объем. По любым вопросам можете писать в комментариях. С удовольствием отвечу на ваши вопросы.
Источник: Блокчейн (blockchain) C#

1
0.000 GOLOS
На Golos с April 2018
Комментарии (0)
Сортировать по:
Сначала старые