Пишем блокчейн-блокнот на языке программирования C#
2026-02-21 22:29 Diff

#статьи

  • 17 авг 2022
  • 0

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

Иллюстрация: Merry Mary для Skillbox Media

Пишет о программировании, в свободное время создаёт игры. Мечтает открыть свою студию и выпускать ламповые RPG.

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

Разбираемся, что же такое блокчейн, и пишем приложение с его использованием.

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

Хеширование — это преобразование данных произвольной длины в битовую строку фиксированной длины. То есть мы можем взять любой текст, например книгу «451 градус по Фаренгейту», а потом зашифровать его с помощью специального алгоритма.

Каждый раз этот алгоритм будет преобразовывать текст в один и тот же хеш. Например, такой:

6de4c03655fdc3e982e3bfc4f055dae5064547e8b78ef951b80c94b657a5c684Вряд ли вы узнаете, что здесь зашифровано.

Но если будет пропущена хотя бы одна запятая или какая-нибудь буква поменяет регистр, то хеш полностью изменится.

efdc5e0108e3906fea8c93efb1d9616b7a26aa26549c5d47a1b6c3fda8199ac9И опять вы вряд ли узнаете, что здесь зашифровано.

Тут зашифрована та же строка, что и сверху, но в конце я убрал точку. Как видно, результат уже совсем не похож на исходный хеш.

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

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

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

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

Рассмотрим это на примере блокнота. Каждая запись в нём будет восприниматься как отдельный блок.

Допустим, есть вот такая первая запись:

Привет, это первая заметка!

Её хеш выглядит так:

7cb70ea12f13042dbfbbf492c20e943b2c62a1007a9921e36f5479f6aa748bc9

Вторая запись содержит в себе саму запись, а также хеш первой записи. То есть:

7cb70ea12f13042dbfbbf492c20e943b2c62a1007a9921e36f5479f6aa748bc9_разделитель_Привет, это вторая запись!

В таком виде заметка хешируется:

8af30f625141cd685dd3ad40f32b0046b562e4efd9746f8225f5a56543a0e50a

И этот хеш становится частью третьей записи.

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

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

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

Эта мера используется, например, в криптовалюте BitCoin. И если кто-то захочет её у вас украсть, ему придётся одновременно заменить блоки на всех компьютерах.

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

Есть и другие варианты:

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

Это далеко не весь список.

Не стоит думать, что такая система надёжна на 100%. Возможны ошибки в самом программном обеспечении, которые позволят воровать данные до того, как они будут захешированы.

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

Начнём с создания класса, который представляет собой блок. Назовём его Note.

В своей работе он будет использовать преобразование строки в байты и обратно, а также шифрование, поэтому нужно подключить соответствующие пространства имён:

using System.Text; using System.Security.Cryptography;

Теперь можно приступать к работе над самим классом:

///<Summary>Заметка для блокнота, который работает на блокчейне</Summary> class Note { public static string Splitter = "_splitter_"; private string text; private byte[] hash; public Note(string text) { this.text = text; this.hash = ComputeHash(text); } private byte[] ComputeHash(string text) { SHA256 sha = SHA256.Create(); //Создаём объект, который будет вычислять хеш byte[] textBytes = Encoding.Default.GetBytes(text); //Преобразуем текст заметки в байты return sha.ComputeHash(textBytes); //Возвращаем хеш } ///<Summary>Полный текст заметки</Summary> public string Text { get { return this.text; } } ///<Summary>Текст заметки без хеша прошлого блока</Summary> public string ClearText { get { return this.text.Remove(0, this.text.IndexOf(Note.Splitter) + Note.Splitter.Length); } } ///<Summary>Хеш прошлого блока</Summary> public string PreviousHash { get { return this.text.Remove(this.text.IndexOf(Note.Splitter)); } } ///<Summary>Хеш текущего блока в виде строки</Summary> public string HashString { get { //При каждом получении текущего хеша нужно считать его заново //Так мы будем уверены, что он актуален var hash = ComputeHash(this.text); return Encoding.Default.GetString(hash); } } ///<Summary>Хеш в виде байтов</Summary> public byte[] Hash { get { return this.hash; } } }

Остаётся только написать программу, которая будет использовать эти блоки. Первым делом нужно создать список блоков:

List<Note> notes = new List<Note>(); //Список блоков notes.Add(new Note "start" + Note.Splitter + "First note")); //Добавляем первую заметку

Потом — реализовать метод добавления новых блоков.

static void AddNote(string text, List<Note> notes) { notes.Add(new Note(notes[notes.Count - 1].HashString + Note.Splitter + text)); }

Когда пользователь вводит текст для новой заметки, он передаётся в метод AddNote().Там создаётся новый блок, который содержит текст вида

Хеш предыдущего блока_разделитель_текст заметки

Созданный блок тут же добавляется в список:

Скриншот: Skillbox Media

После того как будет создано несколько заметок, можно проверить список:

Скриншот: Skillbox Media

Здесь отображается только текст заметок, но, если посмотреть на полную информацию о них, можно увидеть, что они содержат в себе хеш прошлого блока:

Хеш выглядит немного иначе, потому что конвертируется сразу в строку, а не в шестнадцатеричное число
Скриншот: Skillbox Media

Просматривать всё это вручную, чтобы проверить достоверность данных, нет смысла, потому что блоков может быть очень много. Вместо этого напишем метод валидации:

///<summary>Проверка подлинности блоков</summary> static void ValidateNotes(List<Note> notes) { for(int i = 0; i < notes.Count; i++) { if(i == 0) //Не проверять первый блок { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("0 - Valid"); } else { Console.ForegroundColor = ConsoleColor.White; //Проверяем, соответствует ли хеш, записанный в текущий блок, хешу прошлого блока if(@notes[i].PreviousHash == @notes[i - 1].HashString) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(i + " - Valid"); } else { Console.WriteLine($"\n\n | {notes[i].PreviousHash} | {notes[i - 1].HashString} | \n\n"); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(i + " - Changed"); } } } Console.WriteLine("\n"); }

Теперь можно проверить, всё ли в порядке с заметками, которые мы сохранили:

Скриншот: Skillbox Media

Если же в каком-нибудь блоке изменится хоть один символ, это сразу станет ясно. Поэтому такой блокнот — идеальный вариант для хранения долговых расписок и другой подобной информации.

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

Если же вы хотите изучить тему глубже, советую почитать статью на Habr. Там же есть ссылка на учебник по защите информации.

Бесплатный курс по Python ➞
Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу