Межпрограммный вызов
В этом разделе программа CRUD из предыдущего раздела PDA обновляется путем добавления межпрограммных вызовов (Cross Program Invocations, CPIs) — функции, которая позволяет программам Solana вызывать друг друга.
Этот учебник также показывает, как программы могут "подписывать" Program Derived Addresses (PDAs) при выполнении межпрограммных вызовов.
Инструкции update
и delete
требуют модификации для обработки переводов SOL
между аккаунтами путем вызова System Program.
Цель этого раздела включает пошаговое описание процесса реализации CPIs в программе Solana с использованием фреймворка Anchor, основываясь на концепциях PDA, рассмотренных в предыдущем разделе. Для получения дополнительной информации обратитесь к странице Межпрограммный вызов.
Для справки, эта ссылка содержит финальный код после завершения обоих разделов PDA и CPI.
Стартовый код для этого раздела включает только завершенный раздел PDA.
Обновление инструкции Update
Сначала программе нужен простой механизм "плати-за-обновление" путем изменения
структуры Update
и функции update
.
Начните с обновления файла lib.rs
, чтобы включить в область видимости элементы
из модуля system_program
.
use anchor_lang::system_program::{transfer, Transfer};
Далее, обновите структуру Update
, чтобы включить новый аккаунт под
названием vault_account
. Этот аккаунт, контролируемый программой, получает SOL
от пользователя, когда тот обновляет свой аккаунт сообщения.
#[account(mut,seeds = [b"vault", user.key().as_ref()],bump,)]pub vault_account: SystemAccount<'info>,
Далее, добавьте логику CPI в инструкцию update
для перевода 0.001 SOL с
аккаунта пользователя на аккаунт хранилища.
let transfer_accounts = Transfer {from: ctx.accounts.user.to_account_info(),to: ctx.accounts.vault_account.to_account_info(),};let cpi_context = CpiContext::new(ctx.accounts.system_program.to_account_info(),transfer_accounts,);transfer(cpi_context, 1_000_000)?;
Перестройте программу.
$build
Обновление инструкции удаления
Теперь добавьте механизм "возврата средств при удалении", изменив структуру
Delete
и функцию delete
.
Сначала обновите структуру Delete
, чтобы включить vault_account
. Это
позволяет переводить любой SOL из хранилища обратно пользователю при закрытии
его аккаунта сообщения.
#[account(mut,seeds = [b"vault", user.key().as_ref()],bump,)]pub vault_account: SystemAccount<'info>,
Также добавьте system_program
, так как CPI для перевода требует вызова System
Program.
pub system_program: Program<'info, System>,
Далее, добавьте логику CPI в инструкцию delete
для перевода SOL с аккаунта
хранилища обратно на аккаунт пользователя.
let user_key = ctx.accounts.user.key();let signer_seeds: &[&[&[u8]]] =&[&[b"vault", user_key.as_ref(), &[ctx.bumps.vault_account]]];let transfer_accounts = Transfer {from: ctx.accounts.vault_account.to_account_info(),to: ctx.accounts.user.to_account_info(),};let cpi_context = CpiContext::new(ctx.accounts.system_program.to_account_info(),transfer_accounts,).with_signer(signer_seeds);transfer(cpi_context, ctx.accounts.vault_account.lamports())?;
Обратите внимание, что _ctx: Context<Delete>
изменяется на
ctx: Context<Delete>
для использования контекста в теле функции.
Перестройте программу.
$build
Повторное развертывание программы
После внесения этих изменений повторно разверните обновленную программу. Это обеспечит доступность измененной программы для тестирования. В Solana обновление программы просто требует развертывания программы с тем же идентификатором программы.
Убедитесь, что в вашем кошельке Playground есть devnet SOL. Получите devnet SOL из Solana Faucet.
$deploy
Обновление тестового файла
Далее обновите файл anchor.test.ts
, чтобы включить новый аккаунт хранилища в
инструкции. Это требует вычисления PDA хранилища и включения его в вызовы
инструкций обновления и удаления.
Получение PDA хранилища
Сначала добавьте получение PDA хранилища:
const [vaultPda, vaultBump] = PublicKey.findProgramAddressSync([Buffer.from("vault"), wallet.publicKey.toBuffer()],program.programId);
Изменение теста обновления
Затем обновите инструкцию обновления, чтобы включить
vaultAccount
const transactionSignature = await program.methods.update(message).accounts({messageAccount: messagePda,vaultAccount: vaultPda}).rpc({ commitment: "confirmed" });
Изменение теста удаления
Затем обновите инструкцию удаления, чтобы включить vaultAccount
const transactionSignature = await program.methods.delete().accounts({messageAccount: messagePda,vaultAccount: vaultPda}).rpc({ commitment: "confirmed" });
Повторный запуск теста
После внесения этих изменений запустите тесты, чтобы убедиться, что всё работает как ожидалось:
$test
Затем вы можете изучить ссылки SolanaFM для просмотра деталей транзакции, где вы найдете CPIs для инструкций перевода внутри инструкций обновления и удаления.
CPI обновления
CPI удаления
Если вы столкнетесь с какими-либо ошибками, вы можете обратиться к финальному коду.
Следующие шаги
Поздравляем с завершением руководства по быстрому старту Solana. Вы получили практический опыт работы с ключевыми концепциями Solana, включая:
- Получение и чтение данных из аккаунтов
- Создание и отправка транзакций
- Развертывание и обновление программ Solana
- Работа с Program Derived Addresses (PDAs)
- Выполнение Cross-Program Invocations (CPIs)
Чтобы углубить понимание этих концепций, ознакомьтесь с документацией Основные концепции, которая предоставляет подробные объяснения тем, рассмотренных в этом руководстве.
Изучите больше примеров
Если вы предпочитаете учиться на примерах, ознакомьтесь с репозиторием примеров программ, содержащим различные примеры программ.
Solana Playground предлагает удобную функцию, позволяющую импортировать или просматривать проекты, используя их ссылки на GitHub. Например, откройте эту ссылку Solana Playground, чтобы просмотреть проект Anchor из этого репозитория Github.
Нажмите кнопку Import
и введите название проекта, чтобы добавить его в свой
список проектов в Solana Playground. После импорта проекта все изменения
автоматически сохраняются и сохраняются.
Is this page helpful?