Как работают ограничения пропускной спобосности в Голосе (bandwidth)

6 месяцев назад
69 в goldvoice

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

Bandwidth

Блокчейн Голос является системой с нулевыми комиссиями за транзакции. Однако, объём информации, который можно записать в блокчейн в еденицу времени, не бесконечен. Для контроля над расходованием общей пропускной способности был разработан специальный механизм её распределения. Данный механизм является защитой системы от атак по исчерпанию ресурсов системы.

Пропускная способность аккаунта

Максимально доступная bandwidth аккаунта в системе напрямую зависит от количества Силы Голоса (vesting shares).

У аккаунта в системе существует 3 ограничителя пропускной способности:

  1. forum bandwidth: ограничивает объём операций постинга постов и комментариев, апвоутов.
  2. market bandwidth: ограничивает объём операций трансфера монет и выставления/отмены рыночных ордеров на внутренней бирже.
  3. 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 shares
  • max_virtual_bandwidth - максимальная виртуальная пропускная способность сети. См. раздел ""Глобальная пропускная способность"
  • account_average_bandwidth - показатель использования аккаунтом своей полосы
  • total_vshares - суммарное значение vesting shares всех аккаунтов в блокчейне

Если вышеуказанную формулу записать как (account_vshares * max_virtual_bandwidth) / (account_average_bandwidth * total_vshares), то получится число, показывающее долю использования аккаунтом своей полосы.

В данной формуле все переменные являются легко доступными параметрами, кроме account_average_bandwidth. Для получения данного значения требуется провести ряд вычислений.

  1. С помощью API-метода get_account_bandwidth можно получить значение bandwidth на момент последней совершённой транзакции. Данное значение не будет актуальным на текущий момент времени, так как bandwidth всё время восстанавливается (уменьшается % потраченной пропускной способности). Note: это же значение bandwidth можно получить с помощью API-вызова get_accounts, однако в этом случае bandwidth будет находиться в поле 'new_average_bandwidth' (а поле 'average_bandwidth' следует проигнорировать, так как оно относится к устаревшему механизму контроля bandwidth и является deprecated).
  2. В результатах вышеупомянутого вызова так же присутствует поле "last_bandwidth_update", оно показывает момент последнего обновления bandwidth.
  3. Если с момента последнего обновления прошло больше времени чем STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS, то account_average_bandwidth автоматически становится 0, это означает, что аккаунт может воспользоваться всей своей доступной полосой пропускания.
  4. Если же времени прошло меньше, то следует подсчитать, на сколько восстановилась bandwidth. Для этого применяется следующая формула: new_bandwidth = ((STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS - elapsed_time) * account_average_bandwidth) / STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS, где
  • elapsed_time - сколько прошло времени с момента последнего обновления bandwidth
  • account_average_bandwidth - значение bandwidth на момент последнего обновления
  1. Теперь у golosd есть данные о текущем состоянии bandwidth аккаунта, но теперь ему так же нужно определить, можно ли разрешить аккаунту совершить транзакцию. Для этого golosd подсчитывает, как изменится bandwidth после принятия транзакции, и не будет ли при этом превышена полоса пропускания. Для этого вычисляется bandwidth транзакции: trx_bandwidth = trx_size * STEEMIT_BANDWIDTH_PRECISION, где
  • trx_size - размер транзакции в байтах. Для market-операций этот размер дополнительно умножается на 10, из-за чего и происходит то, что для market операций доступная bandwidth в 10 раз меньше чем для forum
  • STEEMIT_BANDWIDTH_PRECISION - константа, определяющая точность вычислений при работе с bandwidth
  1. Вычисляется финальное значение 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() и работает по следующему алгоритму:

  1. Примерно раз в минуту (каждые 20 блоков) происходит пересчёт max_virtual_bandwidth. Первым делом проверяется, не превышает ли средний размер блока (average_block_size) 1/4 от максимального размера блока (maximum_block_size).
  2. Если превышает, то current_reserve_ratio уменьшается в 2 раза, что по сути приводит к уменьшению max_virtual_bandwidth так же в 2 раза.
  3. Если не превышает, и ранее current_reserve_ratio был ограничен, то происходит линейный рост этого показателя путём инкремента на 1 единицу.

Таким образом, ограничение общей пропускной способности активируется, когда средний размер блока становится более 25% от текущего максимально размера блока. При этом ограничение срабатывает достаточно резко, т.к. max_virtual_bandwidth падает сразу в 2 раза. При этом, недостаток bandwidth сразу же могут испытать те пользователи, которые имеют потребление полосы выше 50%. Восстановление же общей доступной полосы после включения ограничения происходит плавно, в течение 3-4 дней.

post bandwidth

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

Реализация в исходных текстах находится в steem_evaluator.cpp в void comment_evaluator::do_apply().

Подробное описание вы можете прочитать в статье https://goldvoice.club/@veritas/kak-ustroeno-ogranichenie-na-kolichestvo-publikacii-na-golose/


Мои opensource-проекты на Голосе

  • golos-witness-tools - набор скриптов для делегатов.
  • golos-otkat-py - скрипт для выполнения откатов по программам апвот50-50 и апвот100 (не поддерживается).
  • golos-scripts - разные полезные скрипты для Голоса на python
Авторы получают вознаграждение, когда пользователи голосуют за их посты.
Голосующие читатели также получают вознаграждение за свой голос.
Порядок сортировки:  Популярное
72
  ·  6 месяцев назад

Ваш пост поддержали следующие Инвесторы Сообщества "Добрый кит":
litrbooh, t3ran13, mishka, sergiy, neo, ovchinnikov, polyideic, oleg257, harhor, la-bella-vita, shuler, vadbars, rusalka, dany2323, maksina, yurgent71, zlody, amikphoto, renat242, markvial, andreyprosto, semasping, gans91, gromozeka, lira, gryph0n, ladynazgool, decha, francesco, ruta, gapel, acidgarry, kvg, aivanouski, vika-teplo, oagalakova, borisss, candy777, sterh, olga-fink, vpervye1, virt, felicita, graff0x, victorskaz, nerengot, lokkie, now, varja, upper, student61, ili, mp42b, liseykina, ksantoprotein, alexmove, process, chugoi, atvalevsky, amidabudda, nikulinsb, firestarter, vlad1m1r, amalinavia, evgeniy73, gogirotsky, vsebudethorosho, sansey, izbushka, astramar, goldenriver, onur1s, ramin, propoker, mifilin, html, metadon, vredinka2345, fxmonster, carpe-diem, kalter, valen-tina, maksh, apnigrich, orlova, cryptobandera, maryatekun, lologom, elcpa, boliwar, wmforum, alexxela, valdemar777
Поэтому я тоже проголосовал за него!

Узнать подробности о сообществе можно тут:
Разрешите представиться - Кит Добрый
Правила
Инструкция по внесению Инвестиционного взноса
Вы тоже можете стать Инвестором и поддержать проект!!!


Если Вы хотите отказаться от поддержки Доброго Кита, то ответьте на этот комментарий командой "!нехочу"


dobryj.kit теперь стал Делегатом! Ваш голос важен для всего сообщества!!!
Поддержите нас:

А мне, вот, интересно - флаганул кто?

Статья размещена на Golos Wiki - https://wiki.golos.io/golosd/mechanics/bandwidth.html и участвует в программе Golos Wiki Bounty.