Skip to main content

Быстрый доступ

Ознакомьтесь с примером:

GitHub

Реализация на Anchor

dApp (Скоро!)

Попробовать сейчас

Пошаговое руководство

Создайте вашу программу и обновите её с хуками разрешений и делегирования, используя Permission Program MagicBlock ACLseoPoyC3cBqoUtkbjZ4aDrkurZW86v19pXz2XQnp1 и Delegation Program DELeGGvXpWV2fqJUhqcF5ZSYMS4JTLjteaAMARRSaeSh:
1
Пишите вашу программу на Solana как обычно.
2
Добавьте хуки разрешений для создания и управления контролем доступа, посмотреть детали
3
Добавьте хуки делегирования для разрешений и аккаунтов с ограниченным доступом, чтобы применять ограничения.
Эти общедоступные средства проверки поддерживаются для разработки. Не забудьте добавить конкретный ER валидатор в свою инструкцию при делегировании:
4
Разверните вашу программу на Solana с помощью Anchor CLI.
5
Подпишите сообщение пользователя, чтобы получить токен авторизации с СДИ-эндпоинта.
6
Запросите токен авторизации и отправляйте конфиденциальные транзакции.

Пример «Камень-Ножницы-Бумага»

Могут потребоваться следующие пакеты программного обеспечения, другие версии также могут быть совместимы:
Программное обеспечениеВерсияРуководство по установке
Solana2.3.13Установите Solana
Rust1.85.0Установите Rust
Anchor0.32.1Установите Anchor
Node24.10.0Установите Node
The latest Permission Program requires SDK version >=0.8.0. See migration guide for details.

Фрагменты Кода

Простая программа «Камень-Ножницы-Бумага», где игрок может делать выбор и видеть результат:
#[program]
pub mod anchor_rock_paper_scissor {

    use super::*;

    // 1️⃣ Create and auto-join as Player 1
    pub fn create_game(ctx: Context<CreateGame>, game_id: u64) -> Result<()> {
        let game = &mut ctx.accounts.game;
        let player1 = ctx.accounts.player1.key();

        game.game_id = game_id;
        game.player1 = Some(player1);
        game.player2 = None;
        game.result = GameResult::None;

        msg!("Game ID: {}", game_id);
        msg!("Player 1 PDA: {}", player1);

        // initialize PlayerChoice for player 1
        let player_choice = &mut ctx.accounts.player_choice;
        player_choice.game_id = game_id;
        player_choice.player = player1;
        player_choice.choice = None;

        msg!("Game {} created and joined by {}", game_id, player1);

        Ok(())
    }

    // 2️⃣ Player 2 joins the game
    pub fn join_game(ctx: Context<JoinGame>, game_id: u64) -> Result<()> {
        let game = &mut ctx.accounts.game;
        let player = ctx.accounts.player.key();

        require!(game.player1 != Some(player), GameError::CannotJoinOwnGame);
        require!(game.player2.is_none(), GameError::GameFull);

        game.player2 = Some(player);

        // Create PlayerChoice PDA for player 2
        let player_choice = &mut ctx.accounts.player_choice;
        player_choice.game_id = game_id;
        player_choice.player = player;
        player_choice.choice = None;

        msg!("{} joined Game {} as player 2", player, game_id);
        Ok(())
    }

    // 3️⃣ Player makes a choice
    pub fn make_choice(ctx: Context<MakeChoice>, _game_id: u64, choice: Choice) -> Result<()> {
        let player_choice = &mut ctx.accounts.player_choice;
        require!(player_choice.choice.is_none(), GameError::AlreadyChose);

        player_choice.choice = choice.into();
        msg!(
            "Player {:?} made choice {:?}",
            player_choice.player,
            player_choice.choice
        );

        Ok(())
    }

    // 4️⃣ Reveal and record the winner
    pub fn reveal_winner(ctx: Context<RevealWinner>) -> Result<()> {
        let game = &mut ctx.accounts.game;
        let player1_choice = &ctx.accounts.player1_choice;
        let player2_choice = &ctx.accounts.player2_choice;

        // 1️⃣ Clone choices into game
        game.player1_choice = player1_choice.choice.clone().into();
        game.player2_choice = player2_choice.choice.clone().into();

        // 2️⃣ Ensure both players exist
        let player1 = game.player1.ok_or(GameError::MissingOpponent)?;
        let player2 = game.player2.ok_or(GameError::MissingOpponent)?;

        // 3️⃣ Ensure both players made a choice
        let choice1 = game
            .player1_choice
            .clone()
            .ok_or(GameError::MissingChoice)?;
        let choice2 = game
            .player2_choice
            .clone()
            .ok_or(GameError::MissingChoice)?;

        // 4️⃣ Determine winner based on choices
        game.result = match (choice1, choice2) {
            (Choice::Rock, Choice::Scissors)
            | (Choice::Paper, Choice::Rock)
            | (Choice::Scissors, Choice::Paper) => GameResult::Winner(player1),

            (Choice::Rock, Choice::Paper)
            | (Choice::Paper, Choice::Scissors)
            | (Choice::Scissors, Choice::Rock) => GameResult::Winner(player2),

            _ => GameResult::Tie,
        };

        msg!("Result: {:?}", &game.result);

        Ok(())
    }

}

#[derive(Accounts)]
#[instruction(game_id: u64)]
pub struct CreateGame<'info> {
    #[account(
        init_if_needed,
        payer = player1,
        space = 8 + Game::LEN,
        seeds = [GAME_SEED, &game_id.to_le_bytes()],
        bump
    )]
    pub game: Account<'info, Game>,

    #[account(
        init_if_needed,
        payer = player1,
        space = 8 + PlayerChoice::LEN,
        seeds = [PLAYER_CHOICE_SEED, &game_id.to_le_bytes(), player1.key().as_ref()],
        bump
    )]
    pub player_choice: Account<'info, PlayerChoice>,

    #[account(mut)]
    pub player1: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
#[instruction(game_id: u64)]
pub struct JoinGame<'info> {
    #[account(
        mut,
        seeds = [GAME_SEED, &game_id.to_le_bytes()],
        bump
    )]
    pub game: Account<'info, Game>,

    #[account(
        init_if_needed,
        payer = player,
        space = 8 + PlayerChoice::LEN,
        seeds = [PLAYER_CHOICE_SEED, &game_id.to_le_bytes(), player.key().as_ref()],
        bump
    )]
    pub player_choice: Account<'info, PlayerChoice>,

    #[account(mut)]
    pub player: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
#[instruction(game_id: u64)]
pub struct MakeChoice<'info> {
    #[account(
        mut,
        seeds = [PLAYER_CHOICE_SEED, &game_id.to_le_bytes(), player.key().as_ref()],
        bump
    )]
    pub player_choice: Account<'info, PlayerChoice>,

    #[account(mut)]
    pub player: Signer<'info>,
}

#[derive(Accounts)]
pub struct RevealWinner<'info> {
    #[account(mut, seeds = [GAME_SEED, &game.game_id.to_le_bytes()], bump)]
    pub game: Account<'info, Game>,

    /// Player1's choice PDA (derived automatically)
    #[account(
        mut,
        seeds = [PLAYER_CHOICE_SEED, &game.game_id.to_le_bytes(), game.player1.unwrap().as_ref()],
        bump
    )]
    pub player1_choice: Account<'info, PlayerChoice>,

    /// Player2's choice PDA (derived automatically)
    #[account(
        mut,
        seeds = [PLAYER_CHOICE_SEED, &game.game_id.to_le_bytes(), game.player2.unwrap().as_ref()],
        bump
    )]
    pub player2_choice: Account<'info, PlayerChoice>,
    #[account(mut)]
    pub payer: Signer<'info>,
}

#[account]
pub struct Game {
    pub game_id: u64,
    pub player1: Option<Pubkey>,
    pub player2: Option<Pubkey>,
    pub player1_choice: Option<Choice>,
    pub player2_choice: Option<Choice>,
    pub result: GameResult,
}
impl Game {
    pub const LEN: usize = 8                // game_id
        + (32 + 1) * 2                       // player1, player2
        + (1 + 1) * 2                        // player1_choice, player2_choice
        + (1 + 32); // result (1 byte tag + 32 bytes pubkey for Winner variant)
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, PartialEq, Eq, Debug)]
pub enum GameResult {
    Winner(Pubkey),
    Tie,
    None,
}

#[account]
pub struct PlayerChoice {
    pub game_id: u64,
    pub player: Pubkey,
    pub choice: Option<Choice>,
}
impl PlayerChoice {
    pub const LEN: usize = 8 + 8 + 32 + 2;
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, PartialEq, Eq, Debug)]
pub enum Choice {
    Rock,
    Paper,
    Scissors,
}

#[error_code]
pub enum GameError {
    #[msg("You already made your choice.")]
    AlreadyChose,
    #[msg("You cannot join your own game.")]
    CannotJoinOwnGame,
    #[msg("Both players must make a choice first.")]
    MissingChoice,
    #[msg("Opponent not found.")]
    MissingOpponent,
    #[msg("Game is already full.")]
    GameFull,
}

/// ... Other context and accounts for delegation and privacy

⬆️ Вернуться к началу


Контроль доступа

Детализированный контроль доступа.

Конфиденциальность на блокчейне

Механизмы и концепции обеспечения конфиденциальности

Авторизация

Система авторизации

Система соответствия требованиям

Стандарты и руководства по соблюдению требований

Solana Explorer

Получайте информацию о ваших транзакциях и аккаунтах в сети Solana:

Solana Explorer

Официальный обозреватель Solana

Solscan

Обозреватель блокчейна Solana

Провайдеры Solana RPC

Отправляйте транзакции и запросы через существующих RPC-провайдеров:

Solana

Бесплатные публичные ноды

Helius

Бесплатные общие ноды

Triton

Выделенные высокопроизводительные ноды

Панель валидаторов Solana

Следите за обновлениями инфраструктуры валидаторов Solana в реальном времени:

Solana Beach

Аналитика по валидаторам

Validators App

Метрики валидаторов

Статус серверов

Подпишитесь на обновления статуса серверов Solana и MagicBlock:

Solana Status

Подписка на обновления статуса серверов Solana

MagicBlock Status

Подписка на статус серверов MagicBlock

Продукты MagicBlock

Эфемерный роллап (ER)

Выполнение транзакций в реальном времени без комиссий и с высокой безопасностью в сети Solana.

Приватный эфемерный роллап (PER)

Защита конфиденциальных данных с помощью приватных вычислений.

Проверяемая функция случайности (VRF)

Генерация доказуемо честной случайности напрямую в блокчейне.