Частичное подписание позволяет нескольким сторонам подписывать одну и ту же транзакцию в разное время или на разных устройствах. Координатор формирует сообщение, каждый необходимый подписант подписывает точные сериализованные байты сообщения, а координатор проверяет и объединяет подписи перед отправкой.
Подпись удостоверяет байты, а не намерения
Изменение плательщика комиссии, blockhash, порядка инструкций, списка аккаунтов или любых instruction data приводит к созданию другого сообщения и делает недействительными все подписи, собранные ранее.
Процесс частичного подписания
- Согласуйте инструкции транзакции и определите, кто будет оплачивать комиссию.
- Задайте срок действия транзакции и плательщика комиссии.
- Сериализуйте сообщение один раз. Считайте эти байты неизменяемыми.
- Передайте каждому подписанту байты сообщения и краткое описание в понятном для человека виде.
- Соберите подписи Ed25519 и проверьте каждую из них по одним и тем же байтам сообщения.
- Прикрепите подписи к адресам соответствующих обязательных подписантов.
- Убедитесь, что все необходимые подписи присутствуют и действительны, затем отправьте транзакцию.
Полный пример
Плательщик комиссии и отправитель SOL в примере ниже подписывают независимо друг от друга. Координатор проверяет обе подписи, объединяет их и отправляет готовую транзакцию.
В примере используется прямое подписание Ed25519, чтобы чётко обозначить границу между координатором и каждым подписантом. Кошелёк, аппаратное устройство, кастодиальный сервис или офлайн-подписант могут заменить любой из локальных keypair при условии, что он подписывает точно те же байты сообщения.
Зафиксируйте сообщение перед подписанием
Каждая подпись охватывает сериализованное сообщение транзакции. Сообщение включает следующее:
- плательщика комиссии
- последний blockhash или durable nonce
- адреса всех программ и аккаунтов
- права аккаунтов на подпись и запись
- порядок инструкций и instruction data
Сначала сформируйте эти поля, один раз сериализуйте сообщение и передайте этот массив байтов каждому подписанту. Полезно хранить хеш сообщения вместе с каждым запросом на подпись, чтобы координатор мог отклонить подпись, возвращённую для другого сообщения.
Не десериализуйте сообщение, не изменяйте его и не рассчитывайте, что ранее собранные подписи останутся действительными. Даже изменение, которое кажется технической мелочью, например замена истёкшего blockhash или смена плательщика комиссии, требует, чтобы каждый подписант подписал сообщение заново.
Согласуйте плательщика комиссии
Плательщик комиссии всегда является обязательным подписантом и должен быть выбран до того, как сообщение будет зафиксировано. Убедитесь, что на аккаунте достаточно SOL для базовой комиссии и любой приоритетной комиссии. Если комиссию будет оплачивать спонсор или бэкенд, укажите его адрес в сообщении до сбора подписи пользователя: добавление спонсора позже изменит подписываемые байты.
Координатор должен проверять, что поступившая подпись принадлежит адресу, указанному среди обязательных подписантов. Никогда не принимайте произвольный открытый ключ и не добавляйте его в транзакцию.
Управление сроком действия транзакции
Транзакция с recent blockhash действительна только до тех пор, пока её blockhash остаётся в очереди недавних blockhash
validator. Перед запуском многостороннего процесса подписания
оцените, смогут ли все подписанты ответить до lastValidBlockHeight.
Если blockhash истёк, создайте новое сообщение с новым blockhash и соберите все подписи заново. Для процессов, которые могут занять больше времени или включать офлайн-подписантов, используйте durable nonce. Durable nonce позволяет обойти ограничение окна recent blockhash, но продвижение или иное использование этого nonce всё равно делает ожидающую транзакцию недействительной.
Проверка перед отправкой
Для каждой полученной подписи:
- Проверьте подпись по зафиксированным байтам сообщения и открытому ключу ожидаемого подписанта.
- Прикрепите её к позиции этого подписанта в массиве подписей транзакции.
- Убедитесь, что собранная транзакция содержит действительные подписи всех обязательных подписантов.
- Отправьте сериализованную транзакцию, не пересобирая её сообщение.
После отправки подтвердите транзакцию, используя ту же информацию о сроке действия, которая была включена в подписанное сообщение. Если при подтверждении сообщается об истёкшем blockhash или использованном nonce, не повторяйте попытку с изменённой транзакцией; начните процесс подписания заново.
Is this page helpful?