Производный адрес программы (PDA)

Программные производные адреса (PDA) предоставляют разработчикам Solana два основных варианта использования:

  • Детерминированные учетные записи: PDA предоставляют механизм для детерминированного получения адреса с использованием комбинации необязательных «семян» (предопределенных входных данных) и определенного идентификатора программы.
  • Возможность подписи программ: Среда выполнения Solana позволяет программам «подписываться» для КПК, которые получены на основе идентификатора программы.

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

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

Производный адрес программы

Важно понимать, что простое выведение программного производного адреса (PDA) не приводит к автоматическому созданию учетной записи на этом адресе. Учетные записи с PDA в качестве внутрицепочечного адреса должны быть явно созданы с помощью программы, используемой для получения адреса. Получение PDA можно сравнить с поиском адреса на карте. Наличие адреса не означает, что в этом месте что-то построено.

Info

В этом разделе мы рассмотрим детали получения PDAs. Подробности того, как программы используют PDA для подписи, будут рассмотрены в разделе о межпрограммных обращениях (CPI), так как там требуется контекст для обеих концепций.

Ключевые точки #

  • PDA - это адреса, полученные детерминированным с использованием комбинации атрибутов определяемых пользователем семян и идентификатор программы.

  • PDA - это адреса, которые выпадают из кривой Ed25519 и не имеют закрытого ключа соответственно.

  • Программы Solana могут программно "подписать" для PDA, которые производятся с помощью идентификатора программы.

  • Получение PDA не приводит к автоматическому созданию учетной записи на цепи.

  • Учетная запись, использующая PDA в качестве адреса, должна быть явно создана с помощью специальной инструкции в программе Solana.

Что такое PDA #

PDA - это адреса, детерминируемые и выглядящие как стандартные публичные ключи, но не имеют связанных приватных ключей. Это означает, что ни один из внешних пользователь не может генерировать действительную подпись для адреса. Тем не менее, runtime позволяет программно «подписать» программы для КПК без использования персонального ключа.

Для контекста, пары ключей Solana - это точки на кривой Ed25519 (криптография с эллиптическими кривыми), которые имеют открытый ключ и соответствующий закрытый ключ. Мы часто используем открытые ключи в качестве уникальных идентификаторов для новых учетных записей в сети, а закрытые ключи - для подписи.

Адрес кривой

PDA - это точка, которая намеренно выведена для падения с кривой Ed25519 с помощью заранее определенного набора входных данных. Точка, которая не находится на кривой Ed25519, не имеет действительного соответствующего закрытого ключа и не может быть использована для криптографических операций (подписи).

PDA можно использовать в качестве адреса (уникального идентификатора) для учетной записи на цепочке, что позволяет легко хранить, отображать и извлекать состояние программы.

Выключенный адрес кривой

Как вывести PDA #

Для выведения PDA требуется 3 входа.

  • Необязательные семена: Предопределенные входные данные (например, строка, число, адреса других учетных записей), используемые для получения КПК. Эти данные преобразуются в буфер байтов.
  • Затравка: Дополнительный вход (со значением в диапазоне 255-0), который используется для гарантии того, что будет сгенерирован правильный КПК (вне кривой). Эта затравка (начиная с 255) добавляется к дополнительным затравкам при генерации PDA, чтобы «сбить» точку с кривой Ed25519. Зерно неровности иногда называют «nonce».
  • Идентификатор программы: адрес программы, на основе которой создается PDA. Это также программа, которая может «подписывать» от имени PDA.

Вывод PDA

Примеры ниже содержат ссылки на Solana Playground, где вы можете запустить примеры в браузере.

Адрес программы поиска #

Чтобы вывести PDA, мы можем использовать метод findProgramAddressSync из @solana/web3.js. Существуют эквиваленты этой функции в других языках программирования (например, Rust), но в этом разделе мы рассмотрим примеры с использованием Javascript.

При использовании метода findProgramAddressSync мы передаем:

  • предопределенные необязательные семена, преобразованные в буфер байтов, и
  • идентификатор (адрес) программы, используемый для получения PDA.

После того, как найден правильный PDA, метод findProgramAddressSync возвращает адрес (PDA) и семя бампа, использованное для получения PDA.

В приведенном ниже примере PDA создается без предоставления каких-либо необязательных семян.

 

Вы можете запустить этот пример на Playana Playground. Вывод семян PDA всегда будет одинаковым:

 

Следующий пример ниже добавляет необязательное семя "helloWorld".

 

Вы можете запустить этот пример на Playana Playground. Вывод семян PDA всегда будет одинаковым:

 

Обратите внимание, что семена кусков составляет 254. Это означает, что 255 получала точку на кривой Ed25519 и не является PDA.

Семя неровности, возвращаемое findProgramAddressSync, - это первое значение (между 255-0) для заданной комбинации необязательных семян и идентификатора программы, которое выводит действительный PDA.

Info

Это первое действительное семя неровности называется «канонической неровностью». Для безопасности программы рекомендуется использовать только каноническую кочку при работе с PDA.

Создать адрес программы #

Под капотом findProgramAddressSync будет итеративно добавлять дополнительное семя неровности (nonce) в буфер семян и вызывать метод createProgramAddressSync. Зерно неровности начинается со значения 255 и уменьшается на 1 до тех пор, пока не будет найдено действительное PDA (вне кривой).

Вы можете повторить предыдущий пример, используя createProgramAddressSync и явно передав семя неровности, равное 254.

 

Вы можете запустить этот пример на Playana Playground. Учитывая те же самые сиды и ID программы, вывод PDA будет соответствовать предыдущим:

 

Каноническая неровность #

Под «канонической неровностью» понимается первая затравка неровности (начиная с 255 и уменьшаясь на 1), из которой получен действительный PDA. Для обеспечения безопасности программы рекомендуется использовать только PDA, полученные из канонической неровности.

Используя предыдущий пример, в приведенном ниже примере сделана попытка получить PDA, используя все семена неровности от 255 до 0.

 

Запустите пример на Playground и вы увидите следующий вывод:

 

Как и ожидалось, семя 255 выдает ошибку, и первым семенем, с помощью которого был получен действительный PDA, является 254.

Однако обратите внимание, что затравки 253-251 приводят к действительным PDA с разными адресами. Это означает, что при одинаковых опциональных семенах и programId семя неровности с другим значением все равно может вывести действительный PDA.

Warning

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

Создание учётных записей PDA #

Этот пример программы на Playground демонстрирует, как создать учетную запись, используя КПК в качестве адреса новой учетной записи . Пример программы написан с помощью Anchor framework.

В файле lib.rs вы найдете следующую программу, которая содержит единственную инструкцию для создания новой учетной записи с использованием PDA в качестве адреса учетной записи. В новой учетной записи хранится адрес пользователя и семя шишки, использованное для получения PDA.

lib.rs
 

Семяны, используемые для получения PDA, включают в себя строку data с жестким кодом и адрес учетной записи user, предоставленный в инструкции. Система Anchor автоматически определяет канонические семена неровностей.

 

Ограничение init предписывает Anchor вызвать системную программу для создания новой учетной записи с PDA в качестве адреса. По сути это делается через CPI.

 

В тестовом файле (pda-account.test.ts), расположенном внутри вышеприведенной ссылки Solana Playground , вы найдете Javascript, эквивалентный получению PDA.

 

Затем транзакция будет отправлена для вызова инструкции initialize для создания новой он-цепной учетной записи с PDA в качестве адреса. Как только транзакция отправлена, используется для получения учетной записи в цепочке, созданной по адресу.

 

Обратите внимание, что если вы запускаете инструкцию initialize более одного раза с использованием того же адреса user как seed, то транзакция будет прервана. Это происходит потому, что учетная запись по производному адресу уже существует.