Pull to refresh
0

Алгоритм формирования блокчейна

Reading time3 min
Views17K


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

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

В Dcoin ноды не могут бесконтрольно размножаться, т.к. каждый майнер — это живой человек, который доказал другим майнерам, что он человек и у него нет клонов. Слово «майнер» тут, скорее всего, не очень вписывается, но так уж сложилось, что я его использую именно в таком ключе.

Каждый раз после создания нового блока происходит распределение майнеров по уровням.

Предположим, что на 0-м уровне оказался майнер с ID 1056. Тогда распределение по уровням будет выглядеть так:
0: 1056
1: 1057, 1058
2: 1059, 1060, 1061, 1062
N: 1056+(2^N)-1 -> 1056+((2^N)-1)*2

Как определяется ID, который находится на 0-м уровне, я расскажу чуть позже.

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

Блок имеет следующую структуру:
Поле Описание Размер
BLOCK_ID Порядковый номер блока 4 байта
TIME Время, когда был создан блок 4 байта
USER_ID ID пользователя, который создал блок 5 байт
LEVEL Уровень, на котором был майнер в момент создания блока 2 байта
SIGN Подпись от (TYPE, BLOCK_ID, PREV_BLOCK_HASH, TIME, USER_ID, LEVEL, MRKL_ROOT), сделанная при помощи node-ключа От 128 байт до 512 байт
TRANSACTIONS Транзакции До 3Mb

Время


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

Через 120 секунд после времени подписания последнего блока нода майнера на 0-м уровне создает блок, записывая в него транзакции, которые у неё накопились.

Если по какой-то причине нода майнера с 0-го уровня не отправила в сеть блок, то через 120 секунд (если 120 секунд не прошло, то все ноды ждут блока с 0-го уровня) блок могут подписать ноды с 1-го уровня и т. д. Если нода с 0-го уровня проснется и начнет всем рассылать свой блок, то у неё будет шанс его «протолкнуть» только в том случае, если большинство нодов еще не получили следующий блок.

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

Сравнение хэшей


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

Для того чтобы избежать такой сегментации, используется поиск наименьшего хэша от user_id,block_id,prev_head_hash.



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

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

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

Майнер, который находится на 0-м уровне, определяется вот так:
$ctx = hexdec(substr($hash, 0, 6));
$hi = $ctx / 127773;
$lo = $ctx % 127773;
$x = 16807 * $lo - 2836 * $hi;
if ($x <= 0)
	$x += 0x7fffffff;
$level_0_miner_id = (($ctx = $x) % ($max_miner_id + 1));
$level_0_miner_id = ($level_0_miner_id==0)?1:$level_0_miner_id;

Где $hash = sha256(sha256(user_id,block_id,prev_head_hash))), $max_miner_id — порядковый номер последнего зарегистрировавшегося майнера, prev_head_hash — это предыдущий хэш от user_id,block_id,prev_head_hash.

Таким образом, сделать так, чтобы блоки подписывали какие-то определенные майнеры, невозможно, т.к. нет значения, которым можно манипулировать с целью изменения хэша (на основе которого происходит распределение майнеров по уровням). Благодаря этому описанный вариант формирования блокчейна может использоваться на практике.
Tags:
Hubs:
+2
Comments15

Articles

Information

Website
dcoin.club
Registered
Founded
Employees
1 employee (me only)
Location
Россия