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

Звёзды и роли

Каждый участник сети — звезда: запись в StarRegistry с владельцем, ключом подписи, ролью и эпохой регистрации.

struct StarInfo {
address owner; // холодный кошелёк, получает награды
address signer; // горячий ключ на сервере
Role role; // None | Node | CP | Banned
uint64 registerEpoch;
}

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

Подписант — горячий ключ на сервере. Им программа подписывает рабочие сообщения: отработанные интервалы, отчёты, обращения к другим участникам.

  • Узел своим подписантом транзакций не отправляет.
  • Control Plane отправляет: публикация отработанного времени и ретрансляция операций без газа оплачиваются с адреса подписанта. Поэтому на нём должен быть ETH.

Захват сервера даёт подписанта, но не деньги: claimNode и claimCp берут получателя из реестра, а не из того, кто вызвал функцию.

Один адрес может подписывать только за одну звезду. register и updateSigner отказывают, если подписант уже принадлежит другой.

StarRegistry.updateSigner(starId, newSigner)

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

В Stargate это кнопка Rotate signer на карточке звезды — тот же вызов, подписанный тем же кошельком.

Полное восстановление выглядит так:

  1. Выключите взломанный сервер.
  2. Поднимите чистый и возьмите его новый адрес подписанта из баннера при запуске.
  3. Вызовите updateSigner с кошелька владельца.

У подписанта узла ETH нет вовсе. У подписанта Control Plane его немного — см. пополнить подписанта, — так что выводить со старого адреса нечего.

РольЗначениеЧто значит
None0Звезды нет: не регистрировалась или удалена
Node1Возит трафик, получает из пула узлов
CP2Выдаёт сессии и публикует отработанное время, получает из пула CP
Banned3Заблокирована: ничего не получает и не может публиковать

Пул узлов и пул CP — разные деньги, их пополняют разные доли каждой оплаты Orbit. Control Plane не берёт себе часть заработка узлов.

StarRegistry.register(signer)

Вызвать может кто угодно. Ни залога, ни очереди, ни одобрения. Вызов возвращает starId, и роль сразу Node. Один владелец может держать сколько угодно звёзд.

Уйти из сети:

StarRegistry.deregister(starId)

Только владелец и только пока роль Node. Control Plane сначала понижают до узла.

Сейчас, на стадии теста, роль CP выдаёт основатель вручную: вызывает forceSetRole, который доступен только владельцу реестра. Если хотите запустить Control Plane, напишите нам. Других способов получить роль в контрактах пока нет.

Дальше роль можно будет получить без чьего-либо решения. Звезда вносит стейк, и если она удовлетворяет требованиям, контракт повышает её до Control Plane сам. Сами требования — размер стейка и условия повышения — в итоге будет устанавливать DAO, а не основатель.

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

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

forceSetRole(starId, Banned, withSlashing) блокирует звезду. Второй аргумент ставит постоянную метку:

slashedCp[signer] = true

Метка ставится, только если прежней ролью звезды был CP. Бан узла с этим флагом ничего лишнего не делает. Однажды поставленную метку не снять, и подписанту с ней откажут и EpochAttestations.push, и RewardDistributor.claimCp.

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

CPEndpointRegistry.setEndpoint(starId, host, port) вызывает владелец звезды, и только пока у неё роль CP. Порт 0 значит «порт протокола по умолчанию» и так и хранится.

Если звезда потеряла роль, запись остаётся, но это не мешает: каждое чтение заново проверяет роль, поэтому getActiveEndpoints() перестаёт отдавать пониженную звезду сразу. Освободить место в хранилище может кто угодно вызовом cleanupStale(starIds).

CPEndpointRegistry.setRealityKey(starId, key) публикует открытый ключ фронта Control Plane, 32 байта. Правило то же: владелец и только при роли CP. getRealityKey(starId) возвращает ключ или ноль, если звезда не Control Plane, а clearEndpoint удаляет ключ вместе с эндпоинтом.