Это перевод поста пользователя webtricks. Спасибо ему за информацию!Возможно, вы читали множество теоретических постов о том, как работают криптовалюты, как работает блокчейн, и о некоторых других похожих темах, таких как Proof of Work, sha256. и т.д. Но такие теоретические посты могут дать вам только общее представление о работе, а многие вещи все еще остаются для вас загадкой. Итак, цель темы - дать вам информацию из первых рук о том, как работает Blockchain с использованием программного кода.
Прежде чем начну, я хотел бы прояснить несколько вещей:
Во-первых, эта тема только для обучения. Код ниже не готов к работе и имеет несколько уязвимостей. Если вы планируете использовать его для работы, обязательно сначала свяжитесь со мной, и я сообщу вам необходимые дополнения, которые вы должны сделать, чтобы его подготовить.
Во-вторых, в этом руководстве будет использоваться среда Javascript / Node.JS, поэтому если у вас есть общее представление о том, как работает Javascript, то это руководство для вас. Если нет, то даже тогда вы сможете узнать много полезной информации. Если вы где-то "застряли", просто пишите мне в личку или здесь, и я решу все возникающие сложности.
Давайте начнем:
Часть 1: Блок
Часть 1(a):Конструктор
Ok! Таким образом, блок, как мы все знаем, является фундаментальной единицей блокчейна. Серия взаимосвязанных блоков образует блокчейн. Позвольте привести пример: предположим, 10 детей играют в парке. Каждый из них держит руку другого ребенка, таким образом формируя структуру человеческой цепи, дети на обоих крайних концах будут держать руку одного другого ребенка, в то время как остальные 8 будут держать руки двух детей, по одному с каждой стороны. Блокчейн работает по той же концепции. Первый блок цепочки (известный как генезис блок) будет держать руку только второго блока, в то время как самый последний блок будет держать руку только предпоследнего блока. Все остальные блоки будут держать в руках блоки предыдущих и следующих за ними.
Небольшое наглядное представление того, что я только что сказал:
(
Я плохой художник, я знаю. )
Ok! Итак, теперь ясно одно: каждый блок должен держать руку другого блока для формирования цепочки. Чтобы гарантировать, что блокчейн использует концепцию хэша и предыдущего хэша (мне нравится называть это последним хэшем). Каждый блок имеет уникальный хеш, который генерируется с помощью алгоритма SHA256 (подробнее об этом позже). Этот хэш действует как рука каждого блока. Второй блок сохранит хэш блока генезиса, третий блок сохранит хэш второго блока и так далее ... Это подводит нас к базовой схеме блокчейна,каждый блок должен иметь хэш, lastHash (хэш предыдущего блока), данные (что уникального хранится в блоке), отметка времени (время создания блока) и номер (постараюсь объяснить это на примере с PoW). Прежде чем начинать с работу с кодом, пожалуйста, убедитесь, что у вас все готово:
(i) Установите Node.js на вашу систему
(ii) скачать любой редактор кода (я бы предложил код Visual Studio)
(iii) создать новый файл с любым именем, но с расширением .js, например: app.js или index.js
(iv) открыть файл в коде Visual Studio
Вот первый фрагмент кода:
class Block {
constructor(timestamp, lastHash, hash, data, nonce) {
this.timestamp = timestamp;
this.lastHash = lastHash;
this.hash = hash;
this.data = data;
this.nonce = nonce;
}
}
Ура! Вот код для части: 1 (а). Теперь позвольте мне объяснить, что мы только что сделали. Начиная со слова «class». Сlass на самом деле скелет. Мы создали скелет с названием «Block». Как у каждого человека есть скелет, но разные мышцы и органы. Точно так же каждый блок в цепочке будет иметь этот скелет блока. Отметка времени, lastHash, hash, data и nonce являются костями. Каждый блок должен иметь эти кости, чтобы сформировать скелет. В дальнейшем слово «constructor» относится к функции, которая будет принимать кости в качестве входных данных и создавать из них скелет. Таким образом, мы фактически вводим значение timestamp, lastHash, hash, data и nonce в функцию конструктора, которая, в свою очередь, устанавливает значение timestamp, lastHash, hash, data и nonce экземпляра Block, эквивалентное этому.
Отлично. Давайте перейдем к Части: 1 (б).
Часть 1(b): Genesis блок
Вот код для части: 1 (б), этот код будет следовать после функции конструктора:
static createGenesis() {
return new this("17/01/2020", "dummy-last-hash", "dummy-hash", "data in genesis block", 0)
}
Превосходно! Итак, позвольте мне рассказать вам, что мы только что сделали: мы создали статическую функцию в классе Block, которая создаст для нас генезис блок. Вы можете заметить, что мы создали жестко запрограммированное значение для этого блока (все, что внутри '' ''- это строковое или жестко запрограммированное значение, а не код). Мы делаем это так, потому что у блока genesis не может быть lastHash. Для него можно создать хеш, что делает рискованным хранение любых данных в genesis блоке , поэтому лучше, если мы определим свойства блока genesis самостоятельно и не используем его для хранения данных.
Двигаясь дальше, позвольте мне описать, что делает приведенный выше код. Начиная со слова «static». Мы можем создать два типа функций в классе, обычные функции и статические функции. Нормальные функции могут использоваться с каждым экземпляром класса (например, каждый блок, созданный с помощью класса Block, может использовать обычную функцию), но невозможно использовать статическую функцию с каждым экземпляром. В нашей цепочке нам нужен только один генезис блок, поэтому было бы неправильно, если бы мы создали для этого нормальную функцию. Следовательно, статическая функция гарантирует, что функция createGenesis () может быть вызвана только один раз в блокчейне.
Вы можете заметить «return» в коде выше. Return на самом деле означает возврат (умный, да
). Это гарантирует, что всякий раз, когда эта функция вызывается, функция возвращает значение генезис блока. «New» относится к экземпляру класса Block. Всякий раз, когда мы создаем экземпляр любого класса, мы должны использовать новое ключевое слово. «this» относится к конструктору класса Block. Если мы используем конструктор внутри класса, тогда мы должны ссылаться на него с помощью «this».
Достаточно, давайте двигаться дальше и создадим самую важную функцию, т. Е. CreateBlock.
Часть 1(c): Создать Block function и Proof of Work
Код после функции createGenesis ():
static createBlock(previousBlock, data) {
let hash, timestamp, nonce=0;
const lastHash = previousBlock.hash;
do {
timestamp = Date.now();
nonce++;
hash = hashGenerator(timestamp, lastHash, data, nonce);
} while (hash.substr(0,4) !== ‘0’.repeat(4));
return new this(timestamp, lastHash, hash, data, nonce);
}
Хорошо! Теперь пришло время понять, что мы написали выше. Функция принимает два входа: предыдущий блок, который является блоком, предшествующим тому, который мы создаем, и данные, т.е. фактические данные, которые мы хотим сохранить в блоке. Затем мы разрешаем начальное значение hash = none, timestamp = nothing и nonce = 0. В Javascript «let» и «const» - это два способа определения переменных. Мы ссылаемся на переменные, которые не меняют свое значение с помощью «const», а переменные, которые меняют свое значение на «let». Затем мы извлекли значение lastHash из предыдущего блока, равное хэшу предыдущего блока.
Затем следует концепция Proof of Work. Мы попытались достичь этого с помощью цикла do / while. Часть «while» цикла do / while принимает условие, и цикл продолжает выполнять в части «do» до тех пор, пока не выполнится условие в условии while. Итак, условие, которое мы упомянули в операторе while: hash.substr (0, 4)! == ‘0’.repeat (4). Теперь давайте нарушим это утверждение. hash.substr (0,4) означает первые 4 символа хеша, начиная с 0, то есть первый символ, затем второй, третий и четвертый. «0» .repeat (4) означает четыре нуля или «0000». Таким образом, мы на самом деле заявляем, что продолжаем выполнять цикл, поскольку первые четыре символа хэша не равны 0. Как только первые 4 символа хэша станут равны 0, цикл прервется, и результирующее значение станет хешем блока. Это не совсем то, как Proof of Work работает, но основная идея та же самая. Мы находим хеш с четырьмя нулями в начале, как 0000vddvd5vd4dv5dvdXXXXXXXXXX. Если вы хотите повысить сложность системы Proof of Work, увеличьте количество нулей до 5 и более, и блоки будут добываться медленнее. Если вы хотите уменьшить сложность, уменьшите количество нулей до 3 или ниже, и блоки будут добываться быстрее.
Теперь перейдем к коду внутри оператора "do". Во-первых, это временная метка, которую мы взяли равной Data.now (), которая является функцией javascript для генерации текущей даты. Следующим является одноразовый номер. Одноразовый номер - это число, которое увеличивается на 1 в каждом цикле, так что значение хеш-функции продолжает изменяться. Если одноразовый номер остается неизменным, то невозможно создать новый хэш в каждом цикле. Последней вещью в коде является hashGenerator, который принимает значения меток времени, lastHash, data и nonce и генерирует хеш, объединяя все 4 значения в одну строку с использованием алгоритма sha256. Мы напишем функцию hashGenerator в следующей части. Давайте приступим.
Часть 1(d): SHA256
Давайте сначала напишем код, он будет идти вверху файла перед классом Block:
const crypto = require(‘crypto’);
const hashGenerator = (...inputs) => {
const hash = crypto.createHash(‘sha256’);
hash.update(inputs.map(item => JSON.stringify(item)).join(‘’));
return hash.digest(‘hex’);
}
Прекрасно! Пришло время объяснений. Crypto - это встроенная библиотека Node.js. Итак, мы просто вызвали её в наш файл, запросив её. Далее идет функция hashGenerator. Во-первых, мы берем входные данные, то есть, если вы помните из части: 1 (c), это отметка времени, lastHash, data и nonce. Затем вы должны заметить три точки перед входами. Эти точки не ошибки, эти точки преобразуют все 4 входа в массив следующим образом: [timestamp, lastHash, data, nonce]. Бинго! Теперь давайте войдем в функцию hashGenerator. В первой строке мы определили значение хеша, равное функции createHash («sha256») криптотеки. Затем мы вводим каждый элемент массива входных данных через метод обновления. Сначала мы сопоставляем массив входов, что означает циклический просмотр элемента массива, преобразование каждого элемента в строку с помощью метода JSON.stringify и последующее объединение всего в одну строку. Наконец, мы возвращаем значение функции digest методом, но сначала преобразуем сгенерированное значение из второй строки в шестнадцатеричное.
Если вам трудно понять функцию hashGenerator, тогда не беспокойтесь, это потому, что мы использовали собственный синтаксис крипто-библиотеки, который отличается от общих синтаксисов Javascript.
Это подводит нас к концу первой части нашего руководства из двух частей по созданию Blockchain. Мы успешно создали класс Block. Далее мы создадим класс Blockchain и добавим блоки в наш blockchain.