Cross Program Invocation

У цьому розділі програма CRUD з попереднього розділу про PDA оновлюється шляхом додавання міжпрограмних викликів (Cross Program Invocations, CPIs) — функції, яка дозволяє програмам Solana викликати одна одну.

Цей посібник також показує, як програми можуть "підписуватися" за адреси, похідні від програми (Program Derived Addresses, PDAs) під час здійснення міжпрограмних викликів.

Інструкції update та delete потребують модифікації для обробки переказів SOL між рахунками шляхом виклику System Program.

Мета цього розділу включає покроковий процес реалізації CPIs у програмі Solana за допомогою фреймворку Anchor, спираючись на концепції PDA, розглянуті в попередньому розділі. Для отримання додаткової інформації зверніться до сторінки Cross Program Invocation.

Для довідки, це посилання містить фінальний код після завершення обох розділів PDA та CPI.

Початковий код для цього розділу включає лише завершений розділ PDA.

Оновлення інструкції Update

Спочатку програмі потрібен простий механізм "плати за оновлення" шляхом зміни структури Update та функції update.

Почніть з оновлення файлу lib.rs, щоб включити в область видимості елементи з модуля system_program.

lib.rs
use anchor_lang::system_program::{transfer, Transfer};

Далі оновіть структуру Update, щоб включити новий рахунок під назвою vault_account. Цей рахунок, контрольований програмою, отримує SOL від користувача, коли він оновлює свій рахунок повідомлення.

lib.rs
#[account(
mut,
seeds = [b"vault", user.key().as_ref()],
bump,
)]
pub vault_account: SystemAccount<'info>,

Далі додайте логіку CPI в інструкцію update для переказу 0.001 SOL з облікового запису користувача на обліковий запис сховища.

lib.rs
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)?;

Перебудуйте програму.

Terminal
$
build

Оновлення інструкції видалення

Тепер додайте механізм "повернення коштів при видаленні", змінивши структуру Delete та функцію delete.

Спочатку оновіть структуру Delete, щоб включити vault_account. Це дозволяє переказувати будь-який SOL зі сховища назад користувачу, коли вони закривають свій акаунт повідомлення.

lib.rs
#[account(
mut,
seeds = [b"vault", user.key().as_ref()],
bump,
)]
pub vault_account: SystemAccount<'info>,

Також додайте system_program, оскільки CPI для переказу вимагає виклику System Program.

lib.rs
pub system_program: Program<'info, System>,

Далі додайте логіку CPI в інструкцію delete для переказу SOL з облікового запису сховища назад на обліковий запис користувача.

lib.rs
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> для використання контексту в тілі функції.

Перебудуйте програму.

Terminal
$
build

Повторне розгортання програми

Після внесення цих змін повторно розгорніть оновлену програму. Це забезпечить доступність модифікованої програми для тестування. У Solana оновлення програми просто вимагає розгортання програми з тим самим ідентифікатором програми.

Переконайтеся, що ваш гаманець Playground має devnet SOL. Отримайте devnet SOL з Solana Faucet.

Terminal
$
deploy

Оновлення тестового файлу

Далі оновіть файл anchor.test.ts, щоб включити новий акаунт сховища в інструкції. Це вимагає отримання PDA сховища та включення його в виклики інструкцій оновлення та видалення.

Отримання PDA сховища

Спочатку додайте отримання PDA сховища:

anchor.test.ts
const [vaultPda, vaultBump] = PublicKey.findProgramAddressSync(
[Buffer.from("vault"), wallet.publicKey.toBuffer()],
program.programId
);

Зміна тесту оновлення

Потім оновіть інструкцію оновлення, щоб включити vaultAccount

anchor.test.ts
const transactionSignature = await program.methods
.update(message)
.accounts({
messageAccount: messagePda,
vaultAccount: vaultPda
})
.rpc({ commitment: "confirmed" });

Зміна тесту видалення

Потім оновіть інструкцію видалення, щоб включити vaultAccount

anchor.test.ts
const transactionSignature = await program.methods
.delete()
.accounts({
messageAccount: messagePda,
vaultAccount: vaultPda
})
.rpc({ commitment: "confirmed" });

Повторний запуск тесту

Після внесення цих змін запустіть тести, щоб переконатися, що все працює як очікувалося:

Terminal
$
test

Потім ви можете переглянути посилання SolanaFM для перегляду деталей транзакції, де ви знайдете CPIs для інструкцій переказу в межах інструкцій оновлення та видалення.

CPI оновленняCPI оновлення

CPI видаленняCPI видалення

Якщо ви зіткнулися з помилками, ви можете звернутися до фінального коду.

Наступні кроки

Вітаємо із завершенням посібника Solana Quickstart. Ви отримали практичний досвід роботи з ключовими концепціями Solana, включаючи:

  • Отримання та читання даних з акаунтів
  • Створення та надсилання транзакцій
  • Розгортання та оновлення програм Solana
  • Робота з Program Derived Addresses (PDAs)
  • Виконання Cross-Program Invocation (CPIs)

Щоб поглибити розуміння цих концепцій, перегляньте документацію Основні концепції, яка надає детальні пояснення тем, висвітлених у цьому посібнику.

Дослідіть більше прикладів

Якщо ви віддаєте перевагу навчанню на прикладах, перегляньте Репозиторій прикладів програм для різноманітних прикладів програм.

Solana Playground пропонує зручну функцію, яка дозволяє імпортувати або переглядати проєкти за допомогою їхніх посилань на GitHub. Наприклад, відкрийте це посилання Solana Playground, щоб переглянути проєкт Anchor з цього репозиторію Github.

Натисніть кнопку Import та введіть назву проєкту, щоб додати його до свого списку проєктів у Solana Playground. Після імпорту проєкту всі зміни автоматично зберігаються.

Is this page helpful?