Состояние (стэйт) системы

Состояние системы — необходимый минимум данных, для функцонирования ноды. Каркас Graphene, на котором построен GOLOS, исполняет операции из транзакций в каждом блоке, который соответствует консенсусу (очереди делегатов, соответствие подписей). Каждый блок происходит обработка данных, отложенных действий, что приводит к иттерационной сущности состояния системы. Часть данных хранятся там постоянно, что накладывает определенные требования на серверное оборудование, на котором запущена нода.

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

Dynamic global property object (dgpo)

Данный объект хранит основные свойства сети, содержит информацию о токенах в обращении и другую важную информацию. В исходном коде он часто представлен в виде переменной dgp, нода модифицирует его состояние с каждой иттерацией, поэтому dynamic global property можно с уверенностью считать самой важной частью состояния системы. Рассмотрим его публичные свойства, доступные через метод get_dynamic_global_properties при обращении к плагину database_api:

  • current_witness (пример значения: "blockchained") — делегат актуального блока;

  • head_block_number (пример значения: 34939787) — номер актуального блока;

  • head_block_id (пример значения: "0215238bf875e34e09a0c7335c3751c40520e73f") — идентификатор (он же хэш) актуального блока;

  • time (пример значения: "2020-02-19T11:40:57") — время генерации актуального блока;

  • last_irreversible_block_num (пример значения: 34939769) — номер последнего необратимого блока;

  • current_supply (пример значения: "200739832.421 GOLOS") — общее количество токенов GOLOS в системе;

  • total_vesting_fund (пример значения: "80099681.756 GOLOS") — количество токенов GOLOS переведенных в долю сети (GOLOS POWER);

  • total_vesting_shares (пример значения: "251336005597.634797 GESTS") — общая количественная мера доли сети в GESTS;

  • total_reward_fund_steem (пример значения: "255.357 GOLOS") — баланс пула наград;

  • total_reward_shares2 (пример значения: "21280044314718424") — количественная мера конкуренции за пул наград;

  • current_aslot (пример значения: 35108019) — текущий номер слота делегата на подпись (содержит в себе нумерацию слота от старта в сети, включая пропущенные делегатами блоки);

  • recent_slots_filled (пример значения: "340282366920938463463374607431768211455") — используется для вычисления процента делегатов участвующих в подписи блоков;

  • participation_count (пример значения: 128) — необходимо разделить на 128, чтобы получить процент делегатов участвующих в подписи блоков;

  • maximum_block_size (пример значения: 65536) — максимальный размер блока в байтах (голосуемый параметр сети);

  • average_block_size (пример значения: 209) — средний размер блока, рассчитывается по формуле average_block_size = (99 * average_block_size + new_block_size) / 100, используется для обновления current_reserve_ratio для поддержания около 50% или меньше в пропускной способности сети;

  • max_virtual_bandwidth (пример значения: "5986734968066277376") — максимальная пропускная способность сети рассчитывается по формуле maximum_block_size * CHAIN_BANDWIDTH_AVERAGE_WINDOW_SECONDS / CHAIN_BLOCK_INTERVAL, максимальная виртуальная пропускная способность сети по формуле max_bandwidth * current_reserve_ratio

  • current_reserve_ratio (пример значения: 20000) — Раз в 20 блоков (1 минута) происходит проверка average_block_size <= 25% maximum_block_size. Если оно выполняется, то данное значение увеличивается на 1 (линейно, каждый блок), но не более CHAIN_MAX_RESERVE_RATIO (20000). Если условие не выполнено, то current_reserve_ratio делится пополам, что должно сразу снизить нагрузку на сеть, защищая ее от участников, использующих объемные транзакции. Другими словами уменьшение вдвое резервного соотношения не уменьшит вдвое использование сети, но ограничит пользователей которые уже попытаются превысить более 50% от их пропускной способности. Когда резервное соотношение падает вдвое от максимального значения (10000 вместо 20000), восстановление общей виртуальной пропускной способности займет около 7 суток.

  • и другие...

Уникальность транзакций и TaPoS (Transactions as Proof of Stake)

Нода проверяет все входящие транзакции на уникальность в пуле транзакций. После того как наступает expiration (ограничено в настройках константой CHAIN_MAX_TIME_UNTIL_EXPIRATION в один час), транзакция удаляется из пула.

Все транзакции в GOLOS должны соответствовать концепции TaPoS, то-есть ссылаться на один из прошлых блоков (ref_block_num в 2 байтовом представлении (бинарное «и» десятичного представления номера блока с hex ffff) и ref_block_prefix состоящий из десятичного представления 5, 6, 7, 8 байтов от бинарного состояния хэша в обратном порядке), что позволяет иницатору транзакции опираться на актуальное для него состояние системы не беспокоясь о необратимом блоке. В случае, если он опирался на состояние системы в случайном минорном форке, то транзакция не попадет в основную цепочку. Таким образом участники сети могут контролировать исполнение очереди транзакций и строить взаимодействие не дожидаясь необратимости блока. Это, в свою очередь, накладывает ограничение на финальный учет подобных действий, поэтому большинство важных транзакций должны находиться уже в необратимом состоянии для проверяющей стороны.

Нода выделяет пространство block_summary_object с размерностью в 2 байта (чтобы номер блока прошедший через операцию бинарного «и» с hex ffff умещался в диапазоне от 0 до 65536) и принимая новые блоки перезаписывает по кругу идентификаторы (хэши) в этом пространстве (и индексе block_summary_index). 65537 блоков охватывают временной промежуток 196611 секунд (примерно 2.27 суток). Соответственно новые транзакции могут ссылаться только на блоки из этого пространства, чтобы нода могла сверить соответствие идентификатора блока (из ref_block_num) с контрольной суммой из ref_block_prefix.