메인 콘텐츠로 건너뛰기

빠른 접근

다른 구현의 기본 카운터 예제를 확인해 보세요。

GitHub

Native Rust 구현

GitHub

Pinocchio 구현

Guide

로컬 개발


단계별 가이드

프로그램을 빌드하고 MagicBlock의 Delegation Program DELeGGvXpWV2fqJUhqcF5ZSYMS4JTLjteaAMARRSaeSh 을 사용해 delegation hooks를 추가하여 업그레이드하세요。
1

프로그램 작성 및 delegation instructions 추가

평소와 같이 Solana 프로그램을 작성하세요。
2

Base Layer에서 PDA Delegate 하기

CPI hooks를 추가해 상태 계정을 Ephemeral Rollup 세션을 통해 delegate, commit, undelegate 할 수 있게 하세요。

이 공용 검증자들은 개발용으로 지원됩니다. 위임 명령에 해당 ER 검증자를 반드시 추가하세요.

메인넷
  • 아시아 (as.magicblock.app): MAS1Dt9qreoRMQ14YQuhg8UTZMMzDdKhmkZMECCzk57
  • EU (eu.magicblock.app): MEUGGrYPxKk17hCr7wpT6s8dtNokZj5U2L57vjYMS8e
  • 미국 (us.magicblock.app): MUS3hc9TCw4cGC12vHNoYcCGzJG1txjgQLZWVoeNHNd
  • TEE (mainnet-tee.magicblock.app): MTEWGuqxUpYZGFJQcp8tLN7x5v9BSeoFHYWQQ3n3xzo
데브넷
  • 아시아 (devnet-as.magicblock.app): MAS1Dt9qreoRMQ14YQuhg8UTZMMzDdKhmkZMECCzk57
  • EU (devnet-eu.magicblock.app): MEUGGrYPxKk17hCr7wpT6s8dtNokZj5U2L57vjYMS8e
  • 미국 (devnet-us.magicblock.app): MUS3hc9TCw4cGC12vHNoYcCGzJG1txjgQLZWVoeNHNd
  • TEE (devnet-tee.magicblock.app): FnE6VJT5QNZdedZPnCoLsARgBwoE6DeJNjBs2H1gySXA
로컬넷
  • 로컬 ER (localhost:7799): mAGicPQYBMvcYveUZA5F5UNNwyHvfYh5xkLS2Fr1mev
3

ER에서 PDA Commit 하기

Solana CLI를 사용해 프로그램을 Solana에 직접 배포하세요。
4

ER에서 PDA Undelegate 하기

SVM RPC 사양을 준수하는 트랜잭션을 수정 없이 온체인과 오프체인에서 전송하세요。

Counter 예제

다음 소프트웨어 패키지가 필요할 수 있으며, 다른 버전도 호환될 수 있습니다.
소프트웨어버전설치 가이드
Solana2.3.13Solana 설치
Rust1.85.0Rust 설치
Node24.10.0Node 설치

코드 스니펫

이 프로그램은 두 가지 주요 instruction을 구현합니다。
  1. InitializeCounter: 카운터를 초기화하고 0으로 설정 (Base Layer에서 호출)
  2. IncreaseCounter: 초기화된 카운터를 X만큼 증가 (Base Layer 또는 ER에서 호출)
이 프로그램은 카운터의 위임과 위임 해제를 위한 전용 instruction도 구현합니다。
  1. Delegate: 카운터를 Base Layer에서 ER로 위임 (Base Layer에서 호출)
  2. CommitAndUndelegate: 카운터를 ER에서 Base Layer로 동기화하도록 예약하고 ER에서 위임 해제 (ER에서 호출)
  3. Commit: 카운터를 ER에서 Base Layer로 동기화하도록 예약 (ER에서 호출)
  4. Undelegate: Base Layer에서 카운터를 위임 해제 (validator CPI를 통해 Base Layer에서 호출)
The undelegation callback discriminator [196, 28, 41, 206, 48, 37, 51, 167] and its instruction processor must be specified in your program. This instruction triggered by Delegation Program reverts account ownership on the Base Layer after calling undelegation on ER.With [#ephemeral] Anchor macro from MagicBlock’s Ephemeral Rollup SDK, the undelegation callback discriminator and processor are injected into your program.
아래는 프로그램의 핵심 구조입니다。
pub enum ProgramInstruction {
    InitializeCounter,
    IncreaseCounter {
        increase_by: u64
    },
    Delegate,
    CommitAndUndelegate,
    Commit,
    Undelegate {
        pda_seeds: Vec<Vec<u8>>
    }
}

#[derive(BorshDeserialize)]
struct IncreaseCounterPayload {
    increase_by: u64,
}

impl ProgramInstruction {
    pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
        // Ensure the input has at least 8 bytes for the variant
        if input.len() < 8 {
            return Err(ProgramError::InvalidInstructionData);
        }

        // Extract the first 8 bytes as variant
        let (variant_bytes, rest) = input.split_at(8);
        let mut variant = [0u8; 8];
        variant.copy_from_slice(variant_bytes);

        Ok(match variant {
            [0, 0, 0, 0, 0, 0, 0, 0] => Self::InitializeCounter,
            [1, 0, 0, 0, 0, 0, 0, 0] => {
                let payload = IncreaseCounterPayload::try_from_slice(rest)?;
                Self::IncreaseCounter {
                    increase_by: payload.increase_by,
                }
            },
            [2, 0, 0, 0, 0, 0, 0, 0] => Self::Delegate,
            [3, 0, 0, 0, 0, 0, 0, 0] => Self::CommitAndUndelegate,
            [4, 0, 0, 0, 0, 0, 0, 0] => Self::Commit,
            [196, 28, 41, 206, 48, 37, 51, 167] => {
                let pda_seeds: Vec<Vec<u8>> = Vec::<Vec<u8>>::try_from_slice(rest)?;
                Self::Undelegate {
                    pda_seeds
                }
            }
            _ => return Err(ProgramError::InvalidInstructionData),
        })
    }
}
“Undelegate” instruction은 정확한 discriminator를 가져야 합니다. 이것은 사용자가 직접 호출하지 않으며, Base Layer의 validator가 ER에서 계정을 undelegate 한 뒤 CPI callback으로 프로그램을 호출합니다.
⬆️ Back to Top

고급 코드 스니펫

위임된 PDA를 리사이즈할 때:
  • PDA는 새로운 계정 크기에서도 rent-exempt 상태를 유지할 만큼 충분한 lamports를 가지고 있어야 합니다。
  • 추가 lamports가 필요하다면, 차액을 제공하기 위해 payer account도 위임되어 있어야 합니다
  • PDA는 프로그램이 소유하고 있어야 하며, 트랜잭션에는 lamports 전송에 필요한 signer가 포함되어야 합니다。
  • system_instruction::allocate 를 사용합니다。
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct Counter {
    pub count: u64,
}

// Resize counter account
pub fn resize_counter_account(
    counter_acc: &AccountInfo,
    payer: &AccountInfo,
    program_id: &Pubkey,
    new_size: usize,
    bump: u8,
) -> ProgramResult {
    let rent = Rent::get()?;
    let lamports_required = rent.minimum_balance(new_size);

    let current_lamports = counter_acc.lamports();
    if lamports_required > current_lamports {
        let lamports_to_add = lamports_required - current_lamports;
        invoke_signed(
            &system_instruction::transfer(
                &payer.key,
                &counter_acc.key,
                lamports_to_add,
            ),
            &[payer.clone(), counter_acc.clone()],
            &[&[COUNTER_SEED, &[bump]]],
        )?;
    }

    // Allocate new size
    invoke_signed(
        &system_instruction::allocate(&counter_acc.key, new_size as u64),
        &[counter_acc.clone()],
        &[&[COUNTER_SEED, &[bump]]],
    )?;

    // Assign back to program
    invoke_signed(
        &system_instruction::assign(&counter_acc.key, program_id),
        &[counter_acc.clone()],
        &[&[COUNTER_SEED, &[bump]]],
    )?;

    msg!("Counter account resized to {} bytes", new_size);
    Ok(())
}
⬆️ Back to Top

Solana 익스플로러

Solana에서의 트랜잭션과 계정 정보를 확인해 보세요.

Solana 익스플로러

공식 Solana 익스플로러

Solscan

Solana 블록체인 살펴보기

Solana RPC 제공업체

기존 RPC 제공업체를 통해 트랜잭션과 요청을 전송하세요.

Solana

Free Public Nodes

Helius

Free Shared Nodes

Triton

Dedicated High-Performance Nodes

Solana 검증자 대시보드

Solana 검증자 인프라의 실시간 업데이트를 확인하세요.

Solana Beach

Get Validator Insights

Validators App

Discover Validator Metrics

서버 상태

Solana와 MagicBlock의 서버 상태를 확인해 보세요.

Solana Status

Subscribe to Solana Server Updates

MagicBlock Status

Subscribe to MagicBlock Server Status