Cross Program Invocation
В этом разделе программа CRUD из предыдущего раздела о PDA обновляется путем добавления Cross Program Invocations (CPIs) — функции, которая позволяет программам Solana вызывать друг друга.
В этом руководстве также показано, как программы могут "подписывать" Program Derived Addresses (PDAs) при выполнении Cross Program Invocations.
Инструкции update
и delete
необходимо изменить для обработки переводов SOL
между аккаунтами с использованием вызова System Program.
Цель этого раздела — пошагово рассмотреть процесс реализации CPIs в программе Solana с использованием фреймворка Anchor, основываясь на концепциях PDA, изученных в предыдущем разделе. Для получения дополнительной информации обратитесь к странице Cross Program Invocation.
Для справки, эта ссылка содержит финальный код после завершения разделов 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, чтобы просмотреть детали транзакции, где вы найдете CPI для инструкций передачи в рамках инструкций обновления и удаления.
Обновление CPI
Удаление CPI
Если вы столкнетесь с какими-либо ошибками, вы можете обратиться к финальному коду.
Следующие шаги
Поздравляем с завершением руководства по быстрому старту Solana. Вы получили практический опыт работы с ключевыми концепциями Solana, включая:
- Получение и чтение данных из аккаунтов
- Создание и отправка транзакций
- Развертывание и обновление программ Solana
- Работа с адресами, производными от программ (PDAs)
- Выполнение межпрограммных вызовов (CPIs)
Чтобы углубить понимание этих концепций, ознакомьтесь с документацией Основные концепции, которая предоставляет подробные объяснения тем, рассмотренных в этом руководстве.
Изучите больше примеров
Если вы предпочитаете учиться на примерах, ознакомьтесь с репозиторием примеров программ, где представлено множество примеров программ.
Solana Playground предлагает удобную функцию, позволяющую импортировать или просматривать проекты, используя их ссылки на GitHub. Например, откройте эту ссылку на Solana Playground, чтобы просмотреть проект Anchor из этого репозитория на GitHub.
Нажмите кнопку Import
и введите имя проекта, чтобы добавить его в список
проектов в Solana Playground. После импорта проекта все изменения автоматически
сохраняются и сохраняются.
Is this page helpful?