Пинем блокчейн. От теории до практики.

in Team Ukraine4 years ago

Здравствуйте!

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

blockchain.jpeg

                          И так, приступим к теории.

Блокчейн - это непрерывная цепочка блоков (односвязный список),
имеющая лишь две операции: чтение и добавление, исключая при этом
функции редактирования и удаления за счёт элементов криптографии и
компьютерных сетей. Необходимость такого способа хранения информации
обусловлена в ситуациях, когда участники протокола не доверяют посредникам
и друг-другу (обмен без участия арбитра, транзакция средств без участия
банка).
Реализовывать блокчейн можно разными способами, даже если сфера
применения заранее известна. Так например, если разрабатываемая программа
на основе блокчейна является платёжной системой, то получение баланса
пользователя уже можно реализовать двумя способами: детерминированным и
недетерминированным*, не говоря уже о том, из чего будет состоять блок,
каковы ограничения блока, какие награды за майнинг и тд. Такое состояние дел
несёт более негативный характер, так как безопасность итогового продукта не
будет определяться общепринятыми стандартами, которые прошли открытый и
долговременный анализ. Чтобы бороться с этим фактором принято
придерживаться стандартов де-факто, подобия биткоина «Bitcoin» (который
выступает в качестве классической платёжной системы) и эфириума
«Ethereum» (в качестве платформы контрактов).
*Детерминированность можно рассматривать как математическую
функцию, результат которой зависит только от принятых аргументов и не от,
чего более. Её также называют концепцией «без состояний», отличной
аналогией могут служить функциональные языки программирования (Haskell,
LISP и тд.). Так например, чтобы получить баланс пользователя,
необходимо будет перебрать всё множество блоков, которое относится к
принятию / отправлению монет. Тем самым, создастся вся последовательность
операций человека и полная закономерность его действий от начала и до конца.
Недетерминированность можно рассматривать как концепцию «с
состояниями», и аналогией для этого могут служить императивные языки
3программирования (C, Go и тд.). Если необходимо перенести это свойство на
блокчейн, то можно сделать так, чтобы состояние баланса пользователя
сохранялось в отдельном блоке, а не в цепочке блоков. Таким образом, чтение
баланса пользователя будет происходить с конца цепочки и прекратится в тот
момент, когда найдётся нужный блок.

                           Подробнее о блоках.

Каждый отдельный блок можно ассоциировать с атомом физического мира,
который является
относительно неделимым, но состоит при этом из протонов, нейтронов,
электронов, а если заглянуть глубже то и до кварков можно дойти. Такая же
ситуация характерна для блока, он состоит из списка транзакций, текущего и
предыдущего хеша, сложности вычисления, метки времени, подписи майнера и
может содержать ещё больше информации (как например состояние баланса
для недетерминированной концепции). И этот раздел предназначен в первую
очередь для анализа внутренностей блока.
Стоит начать рассмотрение блока с самой минимальной его версии, где
он способен оставаться и функционировать как объект в блокчейне. Так для
блока достаточно всего одного поля - хеша предыдущего блока. Эта урезанная
версия проста для понимания, но и даёт при этом начало теоретической базы.
Так например, представим, что у нас существует некий блок B 0 , который
представляет начало цепочки, по терминологии он является генезис-блоком.
Суть его в том, что он не имеет предыдущего блока и является единственным
прародителем всех последующих. Можно представить блок B 0 в следующем
виде:
B 0 = <случайная строка>
Случайная строка в генезис-блоке заменяет хеш блока и она в теории
может быть любой, даже не случайной, так как это не влияет на безопасность.
Все последующие блоки будут генерироваться исходя из следующей формулы:
B i = hash(B i-1 ),
где hash - криптографическая хеш-функция*
Таким образом, получается цепочка хешей, которую лишь с оговорками
можно назвать блоком. Чтобы придать блоку «смысла», нужно поместить в
блок данные (D) для хранения, но таким образом, чтобы эти данные
зафиксировались в результате хеша. Теперь блок усложнился и вместо одного
значения (хеша), он стал хранить два (данные и хеш), тем самым став
массивом:
B 0 = [^NULL^, <случайная строка>]
B i = [D, hash(D || B i-1 {2})]
В данном примере были введены запись «||», что означает конкатенацию
строк и запись «B i-1 {2}», что означает взять из массива B i-1 второй элемент
(индексация для массива будет начинаться с единицы).
Эта запись уже более похожа на блокчейн, потому что хранит хоть какие-
то значения, предполагаемо полезные пользователю. Но может возникнуть
логичный вопрос: для чего это всё было сделано? И ответ - для безопасности
(хоть на данном этапе ещё есть масса проблем). Суть в том, что теперь
невозможно изменить значение B i {1} (или B i-1 {2}) не затрагивая B i {2}, иначе
изменение будет обнаружено, потому что значение блока не будет
соответствовать его хешу.
Ситуация для злоумышленника будет плачевной в тот момент, когда ему
необходимо будет изменить значение блока в середине или начале цепочки, так
как ему придётся изменять все последующие хеши, которые идут после
изменяемого блока. Но проблемы в этой схеме всё же остаются.
Что если в блокчейне хранятся переводы денежных средств? Будет очень
обидно, если злоумышленнику удастся изменить ваше значение, хранимое в
блоке, на значение куда больших размеров, либо сгенерирует новый блок, в
котором укажет вас как отправителя.
Чтобы решить данный недостаток, необходимо ознакомиться с таким
термином как цифровая подпись.
Цифровая подпись помогает идентифицировать создателя блока, тем
самым исключая моменты, когда кто-либо может выдать себя за другого
человека. Сама концепция цифровой подписи несёт ещё два термина - адрес
(публичный ключ) и кошелёк (приватный ключ).
Подпись должна применяться на хеш блока, а не на его значение по двум
основаниям. Во-первых, хеш всегда имеет фиксированную длину,
соответственно и скорость подписания не будет варьироваться. Во-вторых,
подпись будет затрагивать также информацию о хеше предыдущего блока, что
полностью свяжет подпись с предыдущими блоками.
Блок усложнился до трёх элементов (значение, хеш, подпись):
B 0 = [^NULL'^ ^случайная строка^, ^NULL^]
B i = [D, hash(D || B i-1 {2}), sign(B i {2})]
Теперь, если злоумышленник захочет изменить значение B i {1}, ему
необходимо будет изменить и значение B i {2}, но если он изменит значение
B i {2} он не сможет никак изменить значение B i {3} так, чтобы этот блок
продолжал идентифицироваться как до изменения. Или иными словами,
посредник будет способен изменить блок, но только при условии того, что он
поставит свою подпись на блок и точно также изменит все последующие блоки.
Таким образом, если злоумышленник будет проводить подобные махинации в
платёжной системе, то банкротом он станет быстро.
Но что если злоумышленник до такой степени отчаялся, что готов
потратить все свои деньги лишь бы стало плохо другим? Даже если ваш блок
будет находиться в начале цепочки, а цепочка в миллион блоков, современному
компьютеру будет под силу изменить значение в цепочке и далее сгенерировать
все последующие хеши с подписями злоумышленника, тем самым стерев все
настоящие блоки.
В данном случае, на помощь приходит proof-of-work
*. Это
ещё большее усложнение блока, которое добавляет такой термин как сложность
вычисления. Сложность эта основана на математически трудной задаче,
подобия нахождения нужного хеша. Обычный компьютер может тратить на
такие задачи по несколько часов, дней, а то и месяцев и лет, не говоря уже о
возможности человека найти собственноручно решение. Чтобы регулировать
сложность, была придумана задача вычисления не всего хеша, а лишь его
части. Допустим, перебирается число и оно хешируется, нужно найти такое
хешируемое значение, чтобы оно начиналось на четыре нулевых байта. Если
такой хеш находится, значит задача решена. Но здесь определённо существует
минус, если хоть один человек найдёт хешируемое число, которое заведомо
будет начинаться с большого количества нулей, то придётся изменить способ
вычисления трудной задачи, например перейти на единицы, потом на двойки,
тройки, четвёрки и тд. Это явно неудобно, соответственно был придуман
усовершенствованный способ этой задачи, что если хешировать не просто
инкрементируемое число, а хешировать конкатенацию инкрементируемого
числа с текущим хешем блока? Будет получаться всегда случайный результат и
нельзя будет использовать полученное инкрементируемое число повторно на
другом блоке. Поиск нужного хеша ещё называется майнингом.
Теперь блок будет выглядеть следующим образом:
B 0 = [^NULL>^ ^случайная строка^, ^NULL^, ^NULL^]
B i = [D, hash(D || B i-1 {2}), sign(B i {2}), pow(B i {2})], где pow возвращает
число x = B i {4}, при котором hash(x || B i {2}) = «0000...».
Следует отметить, что функция pow сосредоточена именно на хеш. Тоесть, блок не содержит никакой информации о том, кто майнил. Представим такую ситуацию, что вы сами не майните блок, а перекладываете эту задачу на
группу других людей, мощность компьютеров которых в разы превышает вашу
ЭВМ и за это вы платите некий процент от перечисленных средств. Далее один
человек из этой группы наконец-то находит нужное число и заносит его в блок.
Но в этой группе есть злоумышленник, он копирует число x и пересылает его
вам. Теперь вам поступило два ответа о найденном хеше, кому доверять?
Можно сказать, кто первый принёс, тот и получит награду, но можно поступить
другим, более правильным способом. Пусть сам майнер будет создавать блок, а
вы ему будете отправлять лишь транзакцию (а именно три первых поля блока),
далее майнер будет вносить свой хеш и подпись в блок, и на свой хеш будет
производить операцию pow.
Блок ещё больше усложняется:
B 0 = [^NULL^, ^NULL^, ^случайная строка^, ^NULL^, ^NULL^,
^NULL^]
B i = [[D, hash(D), sign(B i {1}{2})], M, hash(M || B i {1}{2}|| B i-1 {3}),
sign M (B i {3}), pow(B i {3})]
Когда майнер найдёт нужное число x = pow(B i {3}), никто более не
сможет скопировать это число и подставить под свой результат, так как
полученное значение не будет подходить под хеш другого блока, где будет
указан другой майнер. Но и при этом, необходимая транзакция попадает в
блокчейн, со значением, хешем значения и подписью хеша. То-есть, всё как
нужно.
Но и на данном этапе существует лазейка. Можно заменить без
последствий sign(B i {1}{2}) и никто этого не заметит. Вопрос конечно может
стоят иначе, ради каких целей существующую подпись стороннего человека
захочется изменять на свою подпись, при этом подстраиваясь под его хеш? Но
увы всякое бывает и потому это также следует считать уязвимостью. В
исправлении данной уязвимости может помочь раскрытие внутренностей
волшебного значения D.
И опять блок начинает усложняться:
B 0 = [^NULL^, ^NULL^, ^случайная строка^, ^NULL^, ^NULL^,
^NULL^]
B i = [[[S, R, V], hash(B i {1}{1}), sign S (B i {1}{2})], M, hash(M || B i {1}{2} || B i-
1 {3}),
sign M (B i {3}), pow(B i {3})]
В данном случае, S - sender (отправитель), R - receiver (получатель), V -
value (само значение или количество денег). Также изменился вид
sign(B i {1}{2}) на sign S (B i {1}{2}), указывая на то, чья это подпись. Теперь
подпись нельзя заменить, не затрагивая хеша. Изменить создателя подписи
тоже нельзя, потому что необходимо будет менять хеш-значение, что
неминуемо ведёт опять к замене подписи. Подпись майнера также
проблематично изменить, потому что его имя указано в хеше. Доказательство
работы украсть также не получится, потому что оно привязано к хешу. Кажется
будто вот она, идеальная защита! Но увы нет, ещё остались уязвимости.
Помните, что в блокчейне нельзя доверять никому? Собственно это
справедливо и для майнеров. Но каким образом майнер способен навредить?
Ведь была сделана подпись на хеш, а хеш указывает на отправителя,
получателя и значение, то-есть ничего из этого нельзя изменить, а если и
изменишь то всё полностью, что аналогично простому игнорированию
добавления транзакции в блок. Это всё верно, но есть одна деталь, которая
очень надоедливая - транзакция ни к чему не прикреплена. Соответственно,
майнер или кто-либо другой сможет скопировать полностью транзакцию и
продублировать её заново, при этом она также будет валидна, потому что все
хеши и подписи правильные (ведь они и вправду настоящие). Чтобы избавиться
от этой уязвимости, можно просто указать в транзакции хеш предыдущего
блока.
Блок ещё немного усложнился:
B 0 = [^NULL^, ^NULL^, ^случайная строка^, ^NULL^, ^NULL^,
^NULL^]
B i = [[[S, R, V], hash(B i {1}{1} || B i-1 {3}), sign S (B i {1}{2})], M, hash(M ||
B i {1}{2} || B i-1 {3}), sign M (B i {3}), pow(B i {3})]
Теперь даже если майнер захочет продублировать транзакцию, она будет
находиться под новым блоком, а хеш предыдущего блока уже не будет
совпадать с хешем, который находится в транзакции. А если майнер
попытается оставить изменённые значения, даже несмотря на несоответствие,
то другие майнеры будут просто отвергать его блок как невалидный.
И вот теперь у нас блоки выстраиваются в цепочку, все они защищены от
подмены, изменения, дублирования и при чём от всех пользователей. Но что
если, существует несколько майнеров и у каждого из майнеров разная цепочка
блоков? Как они будут согласовывать общий блокчейн? И возможно ли это?
Ответом будет конечно же да, иначе не существовали бы биткоины, да
эфириумы. Вопрос скорее лежит в сложности такого изменения. Основной
способ решения таких конфликтов сводится к общей сложности самой цепочки,
которая была составлена из множества операций pow. Если одна цепочка
превышает другую по сложности, то она и становится лидирующей. Если в
цепочках сложность является статичной величиной, тогда цепочки измеряются
в количестве блоков, и так цепочка, размер которой больше, будет являться
лидирующей и узел с меньшей цепочкой должен уступить и принять большую.
Такие противоречащие ситуации называются soft fork, когда блокчейн
разделяется на несколько ветвей, но при этом ещё существует возможность
выбрать только одну «правильную» цепь. Если злоумышленник захочет
подменить весь блокчейн, то ему придётся сгенерировать самостоятельно
больше блоков, чем имеется в атакуемой цепочке, соответственно, если
цепочка уже является огромной, то потенциал такой атаки стремится к
нулю.****
И помимо soft fork’ов существуют ещё так называемые hard fork’и. Hard
fork’и, в отличие от soft fork’ов, сами по себе не появляются. Они используются
тогда, когда необходимым является изменение или улучшение приложения, или
же создание нового блокчейна на основе уже имеющегося. Это приводит к
тому, что новая ветка никак не будет «срастаться» со старой, тем самым
становясь несовместимой.
Когда идёт рассуждение о транзакциях в основе которых лежат деньги,
автоматически и логически возникает вопрос, а от куда возникают корни этих
денег в цифровом мире блокчейна? Надеюсь вы ещё не забыли, что существует
такой генезис-блок. Ну так вот, кто создаёт генезис-блок, тот и является
человеком с деньгами, он способен ими манипулировать или иными словами
совершать первоначальные транзакции. Но, помимо всего прочего, в блокчейне
также существует хранилище, которое является неким блокчейн-
пользователем, но не имеющим приватного ключа. Это можно рассматривать
как исключение из правил, которое формирует новое правило только для него в
контексте майнеров. Суть хранилища сводится к тому, чтобы оно выплачивает
из своей «казны» деньги за выполненную работу майнерам. При этом,
хранилище может быть как самовосстанавливающимся, так и
невосстанавливающимся.
Если мы говорим о невосстанавливающихся хранилищах:
1- Майнер замайнил блок
2- Хранилище платит деньги майнеру
3- Майнеру перечисляется процент с транзакций
Если мы говорим о самовосстанавливающихся хранилищах:
1- Майнер замайнил блок
2- В хранилище перечисляется процент с транзакций
3- Хранилище платит деньги майнеру
Таким образом, зная всё это, необходимо изменить генезис-блок:
B 0 = [[[S, M, V], ^NULL^, ^NULL^], ^NULL^, hash(B 0 {1}{1}), ^NULL^,
^NULL^, ^NULL^],
где S - хранилище, M - майнер генезис-блока, V - награда за генезис-блок.
Как только генезис-блок сгенерировался, начинает действовать хранилище, у
которого определённый и ограниченный запас ресурсов.
Кажется, словно уже обо всём сказано, но существует ещё ряд тонкостей
в блокчейне.
Во-первых, если разным майнерам посылается одновременно транзакция,
то у майнеров возникает конкуренция или гонка по майнингу. Шансов
выиграть больше у того, кто обладает большими мощностями, но вопрос в
другом, как координируются майнеры? Ведь в теории майнеры могут майнить
одни и те же значения, тем самым расходуя понапрасну время и энергию. Для
такого случая, создаются пул-сервера, к которым подключается группа
майнеров заинтересованных в решении одной задачи и распределении ресурсов
между собой. Пул-сервера координируют действие каждого отдельного
майнера, таким образом, чтобы они не пересекались в переборе одинаковых
значений.
Во-вторых, транзакций в блоке может быть несколько (и так чаще всего
бывает). В таком случае возникает ещё одна уязвимость, а именно
дублирование транзакции в одном блоке. Чтобы избежать этого, нужно
вставлять в каждую транзакцию случайное число (r) и хешировать его вместе
со всей другой информацией.
В-третьих, можно применить временные метки (Time), которые будут
свидетельствовать о времени создания блока, для его последующего
отслеживания в истории и определения текущей мощности блокчейна со
стороны майнеров*****. Всё это возможно лишь при условии грамотной
синхронизации с сервером, представляющим время.
В итоге, последняя версия блока будет выглядеть следующим образом:
B 0 = [[[[^NULL^, S, M, V], ^NULL^, ^NULL^]], ^NULL^, ^NULL^,
hash(B 0 {1}{1}{1}), ^NULL^, ^NULL^, ^NULL^]
B i = [[[[r, S, R, V], hash(B i {1}{1}{1} || B i-1 {4}), sign S (B i {1}{1}{2})], [...], ...
], M, Time, hash(M || Time || (B i {1}{1}{2} || B i {1}{...}{2}) || B i-1 {4}), sign M (B i {4}),
pow(B i {4})]
*Криптографическая хеш-функция - это односторонняя функция, которая
принимает строку произвольной длины и возвращает строку фиксированной
длины. Свойство односторонности говорит, что легко получить y от x [y = f(x)],
но сложно получить x от y [x = f -1(y)]. В качестве криптографических хеш-
функций рекомендуется использовать хеш-функции семейства SHA-2 (sha224,
sha256, sha384, sha512) или SHA-3 (keccak). Хеш-фукнции «в сыром виде» имеют
недостатки, подобия удлинения сообщения и
коллизий. От второго избавиться проблематично, по причине существования
атаки дней рождения, тем самым принято выбирать хеш-функции большего
порядка. От первого же недостатка избавиться можно, как пример, применяя
алгоритм HMAC на функцию. Но в блокчейне такая атака будет бесполезной,
так как она требует редактирования уже имеющихся данных и хеша данных,
что влечёт за собой необходимость редактирования подписи, по причине
дальнейшего несоответствия между хешем и подписью.
**Цифровая подпись - элемент асимметричной криптографии. В таких
алгоритмах шифрования как RSA является результатом функции
13расшифрования, а проверка подписи осуществляется при помощи функции
шифрования. Замысел в том, что функция расшифрования известна лишь
создателю закрытого ключа, соответственно только он способен при помощи
этого свойства подтверждать свои действия.
***PoW (Proof-of-work) - доказательство работы, осуществляемое при
помощи решения сложной математической задачи (например, нахождение
нужного хеша). Помимо PoW существуют и другие способы доказательства,
как например PoS (Proof-of-stake), PoA (Proof-of-authority), PoB (Proof-of-burn) и
тд.
****Стоит сказать, что если майнеры соберутся в одну коалицию и их
суммарная мощность будет больше 50% мощности всех майнеров, то возможна
атака, при которой будет возникать достаточно продолжительный soft fork. То-
есть, накапливание блоков в разных цепочках будет происходить
одновременно, тем самым разделяя общий блокчейн на два лагеря. Из этого
явления могут выступать спекулятивные возможности отмены транзакций за
счёт выбора майнерами нужной цепочки.
*****Вычислить текущую мощность майнеров можно при помощи меток
времени. Если раньше на майнинг уходило в среднем 10 минут, а сейчас 5, то
можно утверждать, что мощность майнинга увеличилась вдвое. При этом,
тенденция к понижению необходимого времени сказывается неблагоприятным
образом, так как будут возникать более частые случаи появления soft fork’ов.
Из-за этого в блокчейнах предустанавливают функцию, которая регулирует
текущую сложность блокчейна, подстраиваясь под константное время
(например 10 минут).

                             Перейдем к сети.

Чем больше вы изучаете сеть блокчейна, тем меньше она вам кажется

полностью децентрализованной. В этой сети существуют сервера указывающие
точное время, пул-сервера отвечающие за координацию действий узлов, а
помимо всего прочего и сами узлы представляют из себя распределённый
сервер, так как пользователи, которые осуществляют транзакции, являются
клиентами.
Сутью данного раздела является выявление особенностей блокчейна со
стороны сети и построение связей между её участниками. Так для начала стоит
сказать, что существует два основных вида сети - многоранговые и
одноранговые. Многоранговые (клиент-серверные) сети предполагают
существование двух объектов - клиента и сервера, где клиент способен
производить запрос, а сервер выдавать ответ. Одноранговые же (peer-to-peer)
сети предполагают равноправие участников в действиях, или иными словами,
пользователь в данной сети является одновременно и клиентом, и сервером
(если исходить из терминологии многоранговых сетей). Таких пользователей
именуют узлами.
Но помимо двух вышеперечисленных типов сетей существует некий
гибрид, который так и называется - гибридная сеть. Её основная суть заключена
в том, что существуют, как и в многоранговой сети, два основных объекта -
клиент и сервер. Но особенность такой сети заключается в том, что в качестве
сервера выступает одноранговая сеть, или иными словами сеть узлов. И это
определение гибридной сети всё же может вызывать вопросы. Например, что
если, какой-нибудь человек поднимет сайт, хранение данных которого будет
распределено между его серверами, тогда такая сеть будет называться
гибридной? И можно ли будет назвать сеть гибридной, если существует только
один узел?
Не ответив на эти вопросы, вряд-ли можно продолжать рассуждение о
данном теме. Соответственно, необходимо найти в многоранговых и гибридных
сетях принципиальное различие, и оно существует. Узлы в гибридных сетях, в
отличие от серверов в многоранговых, не доверяют друг-другу, но и при этом
выполняют общую работу. Из этого следует, что узлы не подчиняются какому-
то конкретному человеку, либо узкому кругу лиц и тем самым несут
децентрализованный характер. Но и из этого следует то правило, что если
существует только один узел или узлы находятся в руках одной группы лиц,
тогда такая сеть теряет свойства гибридной и переходит в фазу многоранговой.
В итоге, существуют следующие связи среди участников блокчейна:
1- Клиент -> [многоранговая] -> Узел
2- Узел -> [одноранговая] -> Узел
3- Узел -> [многоранговая] -> Пул-сервер
4- Узел -> [многоранговая] -> Сервер времени
1- Клиенты посылают узлам запросы на счёт получения баланса, блоков или
занесения транзакции в блок.
2- Узел связывается с другими узлами для хранения общей цепочки. Узел
может посылать другому узлу запросы о добавлении нового блока в
блокчейн.
3- Узел запрашивает у пул-сервера необходимый диапазон майнинга.
4- Узел запрашивает у сервера времени текущее состояние времени.
Хоть количество многоранговых связей и преобладает, тем не менее,
важность действий приходится на одноранговую связь. Основной вопрос здесь
скорее лежит в том, ухудшается ли отказоустойчивость блокчейн сети, в
моменты появления многоранговой связи?
Возьмём для начала пример пул-сервера и представим злоумышленника
пытающегося его отключить от сети методом DDoS атак. Сервер отключается,
к нему доступ прекращён для некоторых узлов. В итоге, эта группа узлов может
пойти по двум сценариям, либо подключиться к другому пул-серверу, либо
генерировать блоки по отдельности, исходя из случайного числа. В данном
случае, сеть продолжает функционировать при любом обстоятельстве, хоть и с
возможными оговорками по поводу падения производительности.
Теперь же возьмём сервер времени. Отличие данного сервера от пул-
сервера заключается в том, что его можно использовать лишь единожды перед
запуском узла. Иными словами, запросить у сервера точное время, установить
это время на локальной машине и запустить узел. Таким образом, атаки на
сервер будут приносить вред лишь появлению новых узлов, в то время как уже
функционирующие узлы будут продолжать работу. При этом стоит учитывать,
что серверов времени всегда несколько и произвести успешную DDoS атаку
представляется сложной задачей. И даже если все серверы времени были
отключены от сети, в это время продолжает функционировать сам блокчейн, в
узлах которых хранится текущее время. Соответственно, формирующийся узел
может запросить время не напрямую, у серверов времени, а косвенно, через уже
работающий узел в блокчейне.
Если подытожить всё вышесказанное, то отказоустойчивость блокчейна
будет зависеть полностью от одноранговой архитектуры, при этом отключение
от серверов может привести лишь к падению производительности некоторой
группы майнеров, но никак не к понижению уровня отказоустойчивости.
Хорошо, если блокчейн сеть является по своей сути децентрализованной,
тогда возникает логичный вопрос: каким образом клиенты (и сами узлы) будут
подключаться к другим узлам? От куда они возьмут первоначальный список
необходимых адресов? Это на самом деле очень частый вопрос в контексте
децентрализованных сетей, так как каждая такая сеть решает подобные
проблемы разными способами. Чаще всего, решением является использование
сторонних каналов связи. Допустим, создаётся некий сервер, на котором будет
располагаться список действующих узлов. Выведение из строя такого сервера
не разрушит саму сеть, но перекроет доступ к информации о ней и её
увеличению (что является проблемой лишь при начальном формировании
блокчейна). Расширение списка будет происходить самими же узлами (то-есть
они будут вносить свой адрес на сервер), так как заинтересованы в прибыли от
майнинга. И чем чаще, на различных серверах адрес майнера будет попадаться,
тем чаще к нему будут обращаться клиенты, за помощью в майнинге (и сами
майнеры, для добавления новых блоков).
Если в блокчейне учитывать добавление адресов, то количество связей в
сети увеличится на две строки:
1-Клиент -> [многоранговая] -> Сервер адресов
2-Узел -> [многоранговая] -> Сервер адресов
Также стоит учитывать, что сам майнер способен выдавать список всех
других майнеров, к которым он подключен, тем самым в большинстве случаев
даже не нужно посещать сервера. Но может появиться один вопрос: из-за
конкуренции майнеров в нахождении нужного хеша, не будет ли майнер
пытаться выдавать урезанный список адресов, чтобы увеличить свои шансы на
майнинг? Может и будет, но суть здесь в другом, если он не успеет замайнить
блок и блокчейн обновится за счёт другого майнера, то блок, который майнил
«майнер-мошенник» окажется невалидным. В итоге, ему придётся либо создать
свою цепь блоков, игнорируя при этом весь другой блокчейн (что достаточно
рискованно, так как это будет аналогично hard fork’у, с последующим
привлечением майнеров на свой блокчейн), либо согласится с другими
майнерами и принять тот факт, что транзакции от клиентов, которые
посылались ему, оказались просроченными. Из этого случая клиенты поймут,
что если транзакции не попали в новый блок, то скорее всего майнер выдал не
весь список действующих узлов. Таким образом, клиентам лучше
подключаться сразу к нескольким узлам и получать от них адреса других
майнеров, отсеивая повторяющиеся.
И есть ещё третий способ, благодаря которому можно получить список
узлов. Авторы программы блокчейн-клиента (либо блокчейн-узла) могут по-
умолчанию внести в программу (либо в конфигурационный файл) список
доверенных узлов, которые показали себя как действующие на протяжении
долгого времени. И по мере обновления программы будет также обновляться
этот список.
Со стороны сохранения мощности и доступности блокчейн-сети следует
применять сразу все три способа нахождения адресов. Так например, если
популярность данного блокчейна увеличилась на несколько порядков, то в
теории первый способ нахождения адресов (при помощи сервера) может не
использоваться, но тогда будет возникать уязвимость, когда доверенные узлы
(третьего способа нахождения майнеров) скооперируются и не будут выдавать
адреса всех других узлов, тем самым понижая мощность блокчейн-сети. Это
скажется на более успешном пополнении баланса «майнеров-мошенников»,
при этом другие майнеры даже не получат шанса формировать новый блок,
исходя из транзакций. При этом, если убрать третий способ, то будет всегда
возникать необходимость обращения к серверу на инициирующем этапе
запуска приложения. Если убрать первый и второй способы, то шансы
занесения транзакции в новый блок будут пониженными (при условии того, что
существует несколько клиентов с разным списком адресов). Если убрать второй
способ, то возможность получать список новых адресов будет возложена
только на сервер. Ну а если убрать первый и третий способы, то такая
блокчейн-сеть будет терять лёгкость использования, из-за необходимости
ручной настройки соединения.

Ну в целом теорию изложил. В следующем посте перейдём непосредственно к её реализации.


Posted Using Aeneas.Blog

Sort:  

Congratulations @mhuggu5hss! You have completed the following achievement on the Hive blockchain and have been rewarded with new badge(s) :

You received more than 10 upvotes. Your next target is to reach 50 upvotes.

You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @hivebuzz:

Feedback from the January 1st Hive Power Up Day
 4 years ago  

Вітаємо вас на HIVE 😉

Долучайтесь до нашої спільноти Team Ukraine, публікуйте у ній свої дописи та використовуйте при публікації ваших постів одним із тегів #ua для отримання підтримки від учасників нашої спільноти.

Більше інформації за посиланням