Пропускная способность
Блокчейн Голос является системой с нулевыми комиссиями за транзакции. Однако, объём информации, который можно записать в блокчейн в единицу времени, не бесконечен. Для контроля над расходованием общей пропускной способности был разработан специальный механизм её распределения.
Пропускная способность аккаунта
Максимально доступная bandwidth аккаунта в системе напрямую зависит от количества Силы Голоса (vesting shares).
У аккаунта в системе существует 3 ограничителя пропускной способности:
forum bandwidth: ограничивает объём операций постинга постов и комментариев, апвоутов.
market bandwidth: ограничивает объём операций трансфера монет и выставления/отмены рыночных ордеров на внутренней бирже.
post bandwidth: штрафует аккаунт уменьшением выплаты за пост, если аккаунт постит слишком много постов.
forum и market bandwidth
При превышении данного типа bandwidth возникает ошибка: Account exceeded maximum allowed bandwidth per vesting share.
Данные типы bandwidth по сути являются единой сущностью. Отличие в том, что market bandwidth представляет собой 1/10 от общей bandwidth аккаунта. Например, пусть bandwidth аккаунта - 100 KB. Тогда:
forum bandwidth: 100 KB
market bandwidth: 10 KB
Время восстановления bandwidth от 0 до 100% определяется константой STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS и составляет 7 дней (актуально для 0.17.0).
Механизм вычисления bandwidth
В исходных текстах происходит в database.cpp в bool database::update_account_bandwidth.
При получении транзакции аккаунта нода golosd проверяет, не превысил ли аккаунт отведённую ему полосу пропускания. Это происходит по следующей формуле:
has_bandwidth = (account_vshares * max_virtual_bandwidth) > (account_average_bandwidth * total_vshares)
has_bandwidth: результат сравнения, получается True если есть доступная полоса, и False если нетaccount_vshares- Сила Голоса аккаунта в виде vesting sharesmax_virtual_bandwidth- максимальная виртуальная пропускная способность сети.account_average_bandwidth- показатель использования аккаунтом своей полосыtotal_vshares- суммарное значение vesting shares всех аккаунтов в блокчейне
Если вышеуказанную формулу записать как (account_vshares * max_virtual_bandwidth) / (account_average_bandwidth * total_vshares), то получится число, показывающее долю использования аккаунтом своей полосы.
В данной формуле все переменные являются легко доступными параметрами, кроме account_average_bandwidth. Для получения данного значения требуется провести ряд вычислений.
С помощью API-метода
get_account_bandwidthможно получить значение bandwidth на момент последней совершённой транзакции. Данное значение не будет актуальным на текущий момент времени, так как bandwidth всё время восстанавливается (уменьшается % потраченной пропускной способности). Note: это же значение bandwidth можно получить с помощью API-вызоваget_accounts, однако в этом случае bandwidth будет находиться в поле'new_average_bandwidth'(а поле'average_bandwidth'следует проигнорировать, так как оно относится к устаревшему механизму контроля bandwidth и является deprecated).В результатах вышеупомянутого вызова так же присутствует поле
"last_bandwidth_update", оно показывает момент последнего обновления bandwidth.Если с момента последнего обновления прошло больше времени чем
STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS, тоaccount_average_bandwidthавтоматически становится 0, это означает, что аккаунт может воспользоваться всей своей доступной полосой пропускания.Если же времени прошло меньше, то следует подсчитать, на сколько восстановилась bandwidth. Для этого применяется следующая формула:
new_bandwidth = ((STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS - elapsed_time) * account_average_bandwidth) / STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS, гдеelapsed_time- сколько прошло времени с момента последнего обновления bandwidthaccount_average_bandwidth- значение bandwidth на момент последнего обновления
Теперь у golosd есть данные о текущем состоянии bandwidth аккаунта, но теперь ему так же нужно определить, можно ли разрешить аккаунту совершить транзакцию. Для этого golosd подсчитывает, как изменится bandwidth после принятия транзакции, и не будет ли при этом превышена полоса пропускания. Для этого вычисляется bandwidth транзакции:
trx_bandwidth = trx_size * STEEMIT_BANDWIDTH_PRECISION, гдеtrx_size- размер транзакции в байтах. Для market-операций этот размер дополнительно умножается на 10, из-за чего и происходит то, что для market операций доступная bandwidth в 10 раз меньше чем для forumSTEEMIT_BANDWIDTH_PRECISION- константа, определяющая точность вычислений при работе с bandwidth
Вычисляется финальное значение
account_average_bandwidth = new_bandwidth + trx_bandwidth
Получение значений bandwidth в килобайтах
Мы можем самостоятельно вычислять максимально доступную bandwidth аккаунта и потреблённую на текущий момент.
Для получения значения потреблённой полосы, получается формула следующего вида:
used_kb = account_average_bandwidth / STEEMIT_BANDWIDTH_PRECISION / 1024
Для получения максимально доступной аккаунту полосы получается следующая формула. Какую долю от суммарной СГ имеет аккаунт, такую долю он и может взять из общей max_virtual_bandwidth:
avail_kb = account_vshares/total_vesting_shares * max_virtual_bandwidth / STEEMIT_BANDWIDTH_PRECISION / 1024
Практическую реализацию вычисления bandwidth вы можете посмотреть в функции get_bandwidth в functions.py, которая используется в скрипте get_bandwidth.py.
Глобальная пропускная способность
При общей высокой загруженности сети срабатывает механизм ограничения общей пропускной способности через снижение max_virtual_bandwidth.
В исходных текстах механизм реализован в database.cpp в функции void database::update_global_dynamic_data() и работает по следующему алгоритму:
Примерно раз в минуту (каждые 20 блоков) происходит пересчёт
max_virtual_bandwidth. Первым делом проверяется, не превышает ли средний размер блока (average_block_size) 1/4 от максимального размера блока (maximum_block_size).Если превышает, то
current_reserve_ratioуменьшается в 2 раза, что по сути приводит к уменьшениюmax_virtual_bandwidthтак же в 2 раза.Если не превышает, и ранее
current_reserve_ratioбыл ограничен, то происходит линейный рост этого показателя путём инкремента на 1 единицу.
Таким образом, ограничение общей пропускной способности активируется, когда средний размер блока становится более 25% от текущего максимально размера блока. При этом ограничение срабатывает достаточно резко, т.к. max_virtual_bandwidth падает сразу в 2 раза. При этом, недостаток bandwidth сразу же могут испытать те пользователи, которые имеют потребление полосы выше 50%. Восстановление же общей доступной полосы после включения ограничения происходит плавно, в течение 3-4 дней.
post bandwidth
Является самостоятельным ограничителем и никак не связана с пропускной способностью сети. Предназначение - штрафовать аккаунт, который постит слишком часто.
Реализация в исходных текстах находится в steem_evaluator.cpp в void comment_evaluator::do_apply()
Last updated