Лучший способ понять блокчейн - это построить его.

В этой части 1 серии статей о блокчейне Javascript мы рассмотрим объект блока и объект цепочки блоков, а также обсудим их структуру и последствия.

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

Что вам нужно: последняя версия Node.js (я использую v8.7.0) и npm (диспетчер пакетов узлов) (я с использованием v5.6.0)

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

Где репо: код можно найти здесь.

Шаг 1: строительные блоки

Создайте папку с именем js-blockchain и создайте файл с именем main.js. В этом руководстве мы будем использовать один единственный файл, чтобы вы всегда могли обратиться к исходному коду, если у вас возникнут какие-либо проблемы.

Структура блокчейна

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

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

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

Блокировать объект

Сначала мы создадим Block класс, который будет содержать constructor функцию, calculateHash функцию и функцию mineBlock. Мы начинаем с функции constructor, которая создает экземпляры объектов Block и предоставляет им их свойства.

Блокировать входы

Каждый блочный объект принимает временную метку и данные блока. Отметка времени показывает, когда блок был создан. Это полезно, например, в биткойнах (BTC), поскольку BTC имеет такую ​​сложность, что среднее время добычи на блок составляет 10 минут. Таким образом, система может использовать эту временную метку, чтобы каждый месяц балансировать сложность майнинга. Данные блока содержат информацию, хранящуюся в цепочке. Во многих валютах, таких как BTC, именно здесь данные транзакции хранятся в виде деревьев Меркла.

Блокировать данные

Как видите, в дополнение к 3 полям ввода данных наш объект Block также содержит index, previousHash, hash и nonce. Индекс сообщает, где в цепочке расположен блок. Хеш предыдущего блока - это то, что поддерживает целостность цепочки. Хэш блока просто содержит собственный хэш блока, полученный из calculateHash функции. Одноразовый номер - это еще одна важная часть блока, которая имеет решающее значение для создания механизма майнинга для нашей цепочки блоков, который мы обсудим во второй части этой серии. А пока мы установим нашу переменную nonce в 0.

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

Библиотека Crypto-JS

Теперь мы добавим в наш блок функцию calculateHash. Для нашей хеш-функции мы возьмем крипто-js-библиотеку и воспользуемся их функцией SHA256 hash. Хеш-функция SHA256 была разработана NSA и представляет собой необратимую хеш-функцию. Это фактически используется в майнинге BTC в качестве алгоритма доказательства работы и при создании адресов BTC благодаря своей безопасности.

Чтобы установить библиотеку crypto-js, перейдите в свой терминал и войдите в папку js-blockchain, затем установите библиотеку с помощью npm со следующим кодом:

npm install --save crypto-js

После этого вы увидите следующий результат:

npm WARN saveError ENOENT: no such file or directory, open '/Users/spenserhuang/Desktop/js-blockchain/package.json'
npm WARN enoent ENOENT: no such file or directory, open '/Users/spenserhuang/Desktop/js-blockchain/package.json'
npm WARN js-blockchain No description
npm WARN js-blockchain No repository field.
npm WARN js-blockchain No README data
npm WARN js-blockchain No license field.
+ [email protected]
updated 1 package in 1.75s

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

Рассчитать хеш

Тем не менее, теперь, когда у вас установлена ​​библиотека, вы можете создать константу SHA256 и получить информацию напрямую с помощью оператора require. Мы будем использовать это для создания нашей функции calculateHash.

Мы создаем нашу собственную функцию с именем calculateHash, которую мы будем использовать для присвоения каждому блоку собственного хеша. Как вы можете видеть с помощью функции, хеш принимает каждую часть объекта блока, бросает ее в функцию SHA256 и преобразует ее в строку. В этом проекте мы конвертируем наш результат SHA256 в строку, поскольку строки легче обрабатывать и сопоставлять.

Функция calculateHash принимает КАЖДУЮ часть данных блока. В результате, если какой-либо отдельный фрагмент данных будет изменен, даже если это новая десятичная точка, хэш блока немедленно изменится. Это отличная возможность сделать блокчейн безопасным. Вот отличное руководство, чтобы узнать больше об этой функции блокчейна!

Шаг 2: построение блокчейна

Теперь, когда у нас создана индивидуальная блочная структура, нам нужно создать структуру, объект класса Blockchain, чтобы связать их вместе и построить базовую функциональность, которая поставляется вместе с обычными блокчейнами. Чтобы упростить задачу, наша цепочка блоков будет содержать только функцию constructor, функцию createGenesis, функцию latestBlock, функцию addBlock и функцию checkValid.

Блокчейн объект

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

Конструктор Функция

Во-первых, нам нужна функция constructor, чтобы создать экземпляр нашей цепочки блоков. Это будет простая функция, которая просто создает объект цепочки блоков со свойством achain в структуре списка. Вот почему наши Block объекты содержали индексы. Свойство index наших блоков используется для определения его позиции в нашем списке цепочек.

Создать функцию Genesis

Во-вторых, нашему блокчейну нужна createGenesis функция, которая создает самый первый блок нашей цепочки. Согласно соглашению о блокчейне, самый первый блок любой цепочки также известен как «блок Genesis», отсюда и название createGenesis. С помощью этого блока мы обычно вручную вводим его информацию. Поскольку это первый блок в цепочке, он имеет значение индекса 0. Для его полей timestamp и data мы можем просто ввести сегодняшнюю дату и «блок Genesis» или что угодно. Что касается поля previousHash, мы можем пока просто поставить «0», поскольку перед блоком Genesis нет хеша.

Получить последнюю функцию блока

В-третьих, нашей цепочке нужна latestBlock функция. Это используется для получения информации о самом последнем блоке. Эта функция будет использоваться для реализации нашей addBlock функции.

Добавить новую функцию блока

В-четвертых, чтобы постоянно расширять наш блок, нам нужна addBlock функция. Блокчейны обладают такой функциональностью, поскольку они должны становиться все длиннее и длиннее по мере того, как в них вводится больше информации. Таким образом, в случае, например, BTC, новый блок создается прибл. каждые 10 минут, и каждый из этих новых блоков будет содержать всю информацию о транзакции, которая произошла в течение этого 10-минутного временного интервала.

Реализовать функцию addBlock просто. Наша функция принимает в качестве входных данных объект Block, который уже имеет метку времени и данные. Затем наша функция addBlock будет использовать функцию latestBlock, чтобы присвоить нашему новому блоку поля index и previousHash. После этого мы даем нашему новому блоку собственный хеш, используя функцию calculateHash, которую мы написали ранее. Наконец, мы помещаем этот новый блок в нашу цепочку, и теперь в нашей цепочке блоков есть один новый блок.

Функция проверки действительности

Последняя функция, которую мы реализуем, - это функция checkValid. Это используется для проверки целостности цепочки блоков и определения того, было ли что-либо взломано.

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

Наш цикл состоит из двух частей: первая сопоставляет currentBlock.hash с currentBlock.calculateHash(), а другая сопоставляет currentBlock.previousHash с previousBlock.hash. Первый используется для проверки, была ли подделана информация или currentBlock без обновления currentBlock.hash Второе используется для проверки того, был ли подделан previousBlock.

У вас может возникнуть вопрос, можно ли поставить условие if для

if (currentBlock.previousHash !== previousBlock.calculateHash()) {
    return false;
}

Теоретически кажется, что это должно сработать. Однако previousBlock на самом деле является немного другим объектом, чем фактический объект блока из цепочки, хотя в основном он содержит всю ту же информацию, что и фактический блок. В результате они производят разные хеши. Например, во время моего тестового прогона фактический хеш блока равен 0c27196c36691e915fb2a2f83e63867ec5042abfda4832b02383a6ab40aa075c
, а хеш previousBlock - e6a312951e9e4ed6e4b2ef049246b282f71144599939ff6a5b97b0c53c941295
Вот насколько хеш-значения чувствительны.

Собираем все вместе

Теперь ваша общая программа должна выглядеть так:

Вы можете протестировать свой блокчейн, добавив в конце следующие строки

Затем перейдите к своему терминалу и запустите

node main.js

Теперь вы должны увидеть следующий результат:

{
    "chain": [
        {
            "index": 0,
            "timestamp": 0,
            "data": "01/01/2017",
            "previousHash": "Genesis block",
            "hash": "8163cbd8feafd38a96cd193f2b44940473c22b21ddbb7445bd99ee310dac28ae",
            "nonce": 0
        },
        {
            "index": 1,
            "timestamp": "12/25/2017",
            "data": {
                "amount": 5
            },
            "previousHash": "8163cbd8feafd38a96cd193f2b44940473c22b21ddbb7445bd99ee310dac28ae",
            "hash": "744ce201216f78bba5b87e371579898b97e473ac644d6a13ddda9cdbe05100f6",
            "nonce": 0
        },
        {
            "index": 2,
            "timestamp": "12/26/2017",
            "data": {
                "amount": 10
            },
            "previousHash": "744ce201216f78bba5b87e371579898b97e473ac644d6a13ddda9cdbe05100f6",
            "hash": "9e3cf69ee7a3f3f651b33500ea3f32ccf1a13590115c6739dda74920d54702c8",
            "nonce": 0
        }
    ]
}
Is blockchain valid? true

Подведение итогов

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

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

Удачного кодирования и изучения!