Перейти к содержанию

Аккаунты и адреса Ethereum: модель издателя

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

Будем пользоваться тремя учебными обозначениями: P — адрес издателя, R — адрес читателя, C — адрес реестра. Это не реальные ключи и не строки, которые нужно отправлять в публичную сеть. Такие обозначения позволяют рассуждать о вызовах, не смешивая учебную роль с конкретной инфраструктурой.

Адрес как участник исполнения

Адрес Ethereum содержит двадцать байтов. В Solidity ему соответствует тип address. В веб-интерфейсе адрес обычно показывают шестнадцатеричной строкой с префиксом 0x. Этот способ записи удобен человеку, но внутри вычисления сравниваются значения, а не внешний вид строки или подпись рядом с аватаром.

У аккаунта могут быть связанные с ним состояние и исполняемый код. Традиционно отдельно рассматривают внешние аккаунты, которыми управляет ключ, и аккаунты контрактов. Современные механизмы делегирования и смарт-аккаунтов усложняют эту картину, поэтому правило «у адреса есть код — значит это обязательно старый вид контрактного кошелька» нельзя превращать в универсальный способ определения личности.

Для нашего реестра достаточно более устойчивого вопроса: какой адрес EVM считает непосредственным отправителем текущего вызова? Если издателем назначен мультиподписной контракт, публикацию выполняет этот контракт после своего согласования. Проверка адреса не требует, чтобы издатель обязательно был обычным кошельком с одним ключом.

Вариант А: P → C.publish(17, H1)
           непосредственный отправитель в C: P

Вариант Б: R → редакционный контракт M → C.publish(17, H1)
           непосредственный отправитель в C: M

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

Издатель, экземпляр и номер курса

В системе встречаются три похожих идентификатора. Адрес издателя отвечает на вопрос «кто может изменить запись». Адрес реестра отвечает на вопрос «где находится выбранный код и состояние». Номер курса отвечает на вопрос «какую запись внутри этого состояния читаем». Они не взаимозаменяемы.

Пусть два реестра находятся по адресам C1 и C2. В обоих есть курс 17. В первом издатель объявил H1, во втором — H7. Сравнение номера курса не объясняет, какой выпуск нужен вашему сайту. Клиент обязан выбрать сеть и адрес экземпляра, а затем обратиться к номеру 17 в этом экземпляре.

Точно так же один адрес может существовать в разных сетях. Набор байтов адреса не содержит гарантии, что он указывает на ожидаемый контракт в локальной сети с chainId = 31337. Поэтому запись развёртывания впоследствии будет содержать сеть, адрес и описание интерфейса. Ссылка только на укороченное 0x123…456 недостаточна даже для собственного редакционного инструмента.

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

Нулевой адрес и первоначальное назначение

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

address public immutable publisher;

constructor(address publisher_) {
    if (publisher_ == address(0)) revert Unauthorized();
    publisher = publisher_;
}

Перед нами фрагмент будущего CourseCatalog; ошибка Unauthorized определяется в том же контракте. Он показывает важную последовательность: значение проверяется до присваивания. При ошибке экземпляр не должен появиться с недопустимым издателем. Успешно созданный экземпляр сохраняет ровно переданный адрес, который может отличаться от адреса разворачивающего аккаунта.

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

Что следует из владения адресом

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

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

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

Наконец, подпись не раскрывает юридическую личность подписавшего. Связь P с редакцией ProfessorWeb устанавливается вне контракта: публикацией известных реквизитов, правилами управления и выбранными каналами проверки. Поэтому будущий интерфейс должен говорить «выпуск объявлен адресом издателя», если дополнительная связь не подтверждена. Такое описание точнее обещания, что произвольный адрес самостоятельно доказывает авторство текста. Устройство аккаунтов содержит необходимые различия для дальнейшей модели.

Смена выбранного аккаунта

Пусть редактор открыл панель с адресом P, а затем переключил кошелёк на R. Ранее прочитанный издатель не меняется, но возможный отправитель новой транзакции уже другой. Интерфейс обязан пересчитать доступные действия и не продолжать старое намерение молча. Контракт в любом случае проверит реального отправителя при исполнении.

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

Для упражнения замените внешний P на контракт M, который принимает решения двумя участниками. Список редакторов изменяется внутри M, а адрес publisher в реестре остаётся прежним. Этот пример показывает, почему адрес субъекта и список людей за ним не следует сливать в одно поле.

Оглавление курса. Листинги, расчёты и наблюдения здесь разобраны как ожидаемое поведение; компиляция, учебные программы и проверки при написании не запускались.

Оглавление серии