Перейти к основному содержимому

Подача контента

Запись протокола никогда не несёт файл. Она несёт CID — самоописывающий хеш контента, хранящегося где-то ещё, — что держит квитанцию в 10 МБ вне полезной нагрузки gossip, которую каждый узел должен хранить и воспроизводить, при этом всё же позволяя арбитру установить, что изображение, на которое он смотрит, — то, что сторона подписала.

Кто-то всё же должен держать байты. Этот кто-то — ваш узел, и он уже это делает: подача контента включена по умолчанию и не требует конфигурации.

Почему это в узле, а не в демоне

Первая версия этого закрепляла (pin) через отдельный демон Kubo, достигаемый по --ipfs-api-url. Это работало и стоило больше, чем казалось: вторая идентичность пира в сети, среда исполнения Go и её резидентная память рядом с узловой, и неаутентифицированная поверхность управления /api/v0 на порту 5001, которая позволяет любому, кто её достигнет, закреплять, откреплять и читать всё, что демон держит, — смягчаемая лишь привязкой к loopback.

Более глубокая проблема была в умолчании. Запуск демона — это работа, поэтому закрепление было opt-in, поэтому почти никто бы его не включил, — а гарантия долговечности, в которую никто не входит, — не гарантия. Узел теперь говорит bitswap в процессе, на той же идентичности libp2p, с которой он уже делает gossip, что и позволяет поведению быть включённым по умолчанию. Это, в свою очередь, и делает премию вознаграждения измеряющей нечто реальное: когда подают все, множитель отделяет узлы, которые действительно держат и отвечают за контент, от узлов, которые офлайн или обрезали, а не операторов, потрудившихся установить Go, от тех, кто не потрудился.

Что ваш узел держит, и что нет

Он держит контент, на который ссылаются записи вложений, которые он принял, в пределах своего окна хранения. Он не извлекает каждый CID, который видит, — узел, который бы это делал, хранил бы что угодно, на что кто-либо решил бы его направить.

Эта граница не обещание, это арифметика: вложение должно называть расчёт, а расчёт требует реального резервирования против реального эскроу. Потолок того, что запрашивается у вашего диска, — это фактический объём торговли сети, а не терпение незнакомца.

Всё извлечённое проверяется против его CID перед тем, как быть сохранённым, пришло ли оно от пира или от шлюза.

Спросите свой узел, что он держит:

curl -s -X POST http://localhost:7080/rpc -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"getHeldContent","params":{"cid":"bafkrei..."}}'
# {"jsonrpc":"2.0","id":1,"result":{"content":"<base64>"}} ← держится
# {"jsonrpc":"2.0","id":1,"result":{"content":null}} ← не держится

Откуда берётся первая копия

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

--content-gateway https://ipfs.example.com # по умолчанию: https://ipfs.filebase.io

Шлюз — это недоверенный транспорт, не власть. Он может подать неверные байты, никакие байты или залогировать, кто что запросил; он не может изменить, какой контент называет CID, потому что CID — это хеш того контента. Байты, которые не то, что CID называет, отклоняются, а шлюз, который что-либо подменяет, неотличим от просто лежащего.

Приватность — единственное, что проверка не исправляет: кто бы ни управлял шлюзом, он узнаёт, что ваш узел запросил этот CID. Вот почему флаг существует — направьте его на свой собственный — и почему это запасной вариант, а не первый выбор. Ваш узел предпочитает своих пиров.

Если вы уже запускаете Kubo

--ipfs-api-url http://127.0.0.1:5001 всё ещё работает и теперь значит нечто более узкое, чем раньше: контент протокола закрепляется в вашем демоне тоже, помещая копию куда-то, что собственное окно хранения вашего узла не управляет. Это больше не то, как узел подаёт контент.

Отключение, и что это стоит

openfiat-node --no-content-serving

Этот узел ничего не хранит и не может ответить на вызов извлекаемости, поэтому зарабатывает сниженную долю. Это честный исход — он делает для сети меньше — и это правильный флаг, если диска действительно нет. Узел всё же бросает вызов своим пирам в любом случае: измерение, кто подаёт контент, — сервис, который узел выполняет, хранит ли он что-либо сам или нет.

Как работает вызов

Узел выбирает CID, который сеть знает, просит у другого узла байты и хеширует то, что возвращается. Адрес контента есть хеш его контента, поэтому вернуть правильные байты — не то, что узел может сделать, не имея их. Это единственный сигнал качества узла, который проверяется, а не принимается на веру.

Только некоторые CID могут решить вопрос. Дайджест CID с кодеком raw берётся по самому файлу; CID dag-pb адресует корень нарезанного DAG, поэтому пир мог бы вернуть правильный файл и всё же провалить наивную проверку хеша. Провайдеры переключаются между двумя на 262 144 байтах, поэтому вызовы отбирают файлы на или ниже 256 КиБ — аватары почти всегда, вложения иногда. Этого достаточно, чтобы отделить узел, закрепляющий всё, от того, что не закрепляет ничего, что и нужно множителю; это не доказательство того, что узел держит конкретное большое вложение, и ничто не утверждает, что это так.

Что такое множитель

Узел, который отвечает, сохраняет свою полную долю; узел, который не может, масштабируется до 0.7, поэтому подающий узел зарабатывает примерно 1.43× того, что зарабатывает в остальном идентичный узел, который не подаёт. Обе цифры — [PROPOSED — NEEDS SIGN-OFF] — см. OFS-4100 §9.2 и crates/rewards/src/params.rs.

Премия выражена как штраф по причине, которая не презентационна. Эмиссия за эпоху фиксирована, и эти множители решают, как она делится. Бонус выше 1.0 не заплатил бы закрепляющему узлу из воздуха, он отчеканил бы эмиссию, которой в ведре инфраструктуры нет, — что параметры вознаграждения прямо отвергают. Поэтому закрепляющий узел сохраняет свою полную долю, а незакрепляющий узел уступает часть своей.

0.7 вместо 0.4 у только-gossip, потому что хранение — меньшая услуга сети, чем соединение с цепочкой: узел, который не закрепляет, всё же ретранслирует, проверяет и подаёт всё остальное.

Как долго хранится контент

Не каждый узел должен нести всю историю.

--retention 30 # по умолчанию: скользящее окно в 30 дней
--retention 365 # более длинное окно, всё ещё скользящее
--retention archival # хранить всё, навсегда — явный выбор

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

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