설치
필요한 의존성을 추가하세요:
cargo add --dev anchor-litesvm litesvm litesvm-utils
anchor-litesvm이란?
anchor-litesvm 크레이트는 anchor-client와 유사한 간소화된 구문을
제공하지만 RPC 오버헤드가 없습니다. Anchor 타입으로 타입 안전성을 유지하면서
순수 LiteSVM 대비 78% 코드 감소를 달성합니다.
AnchorContext
- 프로덕션 호환 테스트 컨텍스트
- anchor-client와 동일한 API 패턴
- LiteSVM 인스턴스, 페이어, 프로그램 관리
- RPC 오버헤드 없이 명령어 실행
Program API - 유연한 명령어 빌딩 - 타입 안전한 계정 및 인수 처리 - 친숙한 anchor-client 구문
계정 역직렬화 - Anchor 계정 조회 및 역직렬화 - 자동 식별자 처리 - PDA 및 커스텀 레이아웃 지원
이벤트 파싱
- 트랜잭션 로그에서 이벤트 파싱
- 이벤트 발생 검증
- 타입 안전한 이벤트 역직렬화
빠른 예제
Anchor 1.0에서는 declare_program!를 사용하여 프로그램의 IDL에서 클라이언트
타입을 생성하세요. 이 매크로는 타입 안전한 명령어 빌딩을 위한
client::accounts::* 및 client::args::* 모듈을 생성합니다:
use anchor_litesvm::AnchorLiteSVM;use anchor_litesvm::{AssertionHelpers, TestHelpers};use anchor_lang::system_program;use solana_sdk::signature::{read_keypair_file, Signer};// Generate client types from your program's IDLanchor_lang::declare_program!(my_program);#[test]fn test_anchor_program() {// One-line setup — reads program keypair for the correct IDlet program_keypair = read_keypair_file("target/deploy/my_program-keypair.json").unwrap();let mut ctx = AnchorLiteSVM::build_with_program(program_keypair.pubkey(),include_bytes!("../target/deploy/my_program.so"),);// Create a funded account via TestHelpers on ctx.svmlet user = ctx.svm.create_funded_account(10_000_000_000).unwrap();// Derive PDAlet seed: u64 = 42;let pda = ctx.svm.get_pda(&[b"user", user.pubkey().as_ref(), &seed.to_le_bytes()],&program_keypair.pubkey(),);// Build instruction using generated client typeslet ix = ctx.program().accounts(my_program::client::accounts::Initialize {user: user.pubkey(),user_account: pda,system_program: system_program::ID,}).args(my_program::client::args::Initialize {seed,name: "test".to_string(),}).instruction().unwrap();// Execute and assert in one chainctx.execute_instruction(ix, &[&user]).unwrap().assert_success();// Fetch and deserialize the accountlet account: my_program::MyAccount = ctx.get_account(&pda).unwrap();assert_eq!(account.name, "test");}
declare_program!(my_program)는 컴파일 시점에
target/idl/my_program.json에서 IDL을 읽어 client::accounts::* 및
client::args::* 모듈을 생성합니다. 이를 위해서는 먼저 프로그램을 빌드해야
합니다.
비교: Raw LiteSVM vs anchor-litesvm
이전 (Raw LiteSVM)
use litesvm::LiteSVM;use solana_keypair::Keypair;use solana_signer::Signer;use solana_program::instruction::{AccountMeta, Instruction};use solana_message::Message;use solana_transaction::Transaction;let mut svm = LiteSVM::new();svm.add_program(program_id, program_bytes).unwrap();let payer = Keypair::new();svm.airdrop(&payer.pubkey(), 10_000_000_000).unwrap();// Manually compute 8-byte discriminatorlet discriminator = {let mut hasher = sha2::Sha256::new();hasher.update(b"global:initialize");let result = hasher.finalize();result[..8].to_vec()};// Manually serialize args and build instructionlet mut data = discriminator;data.extend_from_slice(&borsh::to_vec(&args).unwrap());let accounts = vec![AccountMeta::new(user.pubkey(), true),AccountMeta::new(user_pda, false),AccountMeta::new_readonly(system_program::id(), false),];let ix = Instruction::new_with_bytes(program_id, &data, accounts);let tx = Transaction::new_signed_with_payer(&[ix],Some(&payer.pubkey()),&[&payer],svm.latest_blockhash(),);svm.send_transaction(tx).unwrap();// Manually deserialize with discriminator skiplet account_data = svm.get_account(&pda).unwrap().data;let account: UserAccount = UserAccount::try_deserialize(&mut &account_data[8..]).unwrap();
이후 (anchor-litesvm)
use anchor_litesvm::AnchorLiteSVM;anchor_lang::declare_program!(my_program);let mut ctx = AnchorLiteSVM::build_with_program(program_id, program_bytes);let user = ctx.svm.create_funded_account(10_000_000_000).unwrap();let ix = ctx.program().accounts(my_program::client::accounts::Initialize {user: user.pubkey(),user_account: user_pda,system_program: anchor_lang::system_program::ID,}).args(my_program::client::args::Initialize { name: "test".to_string() }).instruction().unwrap();ctx.execute_instruction(ix, &[&user]).unwrap().assert_success();let account: my_program::UserAccount = ctx.get_account(&user_pda).unwrap();
주요 구성 요소
AnchorLiteSVM 빌더
| 메서드 | 설명 |
|---|---|
new() | 새 빌더 인스턴스를 생성합니다 |
with_payer(keypair) | 커스텀 페이어 keypair를 설정합니다 |
deploy_program(id, bytes) | 배포할 프로그램을 추가합니다 |
build() | AnchorContext를 빌드합니다 |
build_with_program(id, bytes) | 단일 프로그램을 위한 편의 메서드 |
build_with_programs(programs) | 여러 프로그램을 배포합니다 |
AnchorContext
| 메서드 | 설명 |
|---|---|
svm | 내부 LiteSVM 인스턴스에 직접 접근합니다 (공개 필드) |
program_id | 프로그램 ID (공개 필드) |
program() | 명령어 빌드를 위한 Program를 반환합니다 |
payer() | 페이어 Keypair를 가져옵니다 |
execute_instruction(ix, signers) | 단일 명령어를 실행합니다 |
execute_instructions(ixs, signers) | 하나의 트랜잭션에서 여러 명령어를 실행합니다 |
send_and_confirm_transaction(&tx) | 원시 트랜잭션을 전송합니다 |
get_account<T>(pubkey) | Anchor 계정을 가져와 역직렬화합니다 |
get_account_unchecked<T>(pubkey) | 판별자 검사 없이 가져옵니다 |
create_funded_account(lamports) | 새 keypair를 생성하고 자금을 지원합니다 |
airdrop(pubkey, lamports) | 주소에 SOL을 에어드롭합니다 |
latest_blockhash() | 현재 블록해시를 가져옵니다 |
account_exists(pubkey) | 계정 존재 여부를 확인합니다 |
deploy_program(id, bytes) | 추가 프로그램을 배포합니다 (ProgramTestExt 경유) |
Program
| 메서드 | 설명 |
|---|---|
accounts(accounts) | 명령어 계정을 설정합니다 (모든 ToAccountMetas 타입) |
args(args) | 명령어 인수를 설정합니다 (모든 InstructionData 타입) |
instruction() | 최종 Instruction를 빌드합니다 |
id() | 프로그램 ID를 가져옵니다 |
ctx.svm — TestHelpers & AssertionHelpers
ctx.svm는 litesvm-utils를 통해 TestHelpers 및 AssertionHelpers
트레이트를 사용할 수 있는 공개 LiteSVM 필드입니다:
| 메서드 | 설명 |
|---|---|
ctx.svm.create_funded_account(lamports) | keypair 생성 및 자금 지원 |
ctx.svm.create_token_mint(authority, decimals) | SPL 토큰 민트 생성 |
ctx.svm.create_associated_token_account(mint, owner) | ATA 생성 |
ctx.svm.mint_to(mint, token_account, authority, amount) | 토큰 민트 |
ctx.svm.get_pda(seeds, program_id) | PDA 주소 도출 |
ctx.svm.get_pda_with_bump(seeds, program_id) | bump seed로 PDA 도출 |
ctx.svm.assert_token_balance(token_account, expected) | 토큰 잔액 확인 |
ctx.svm.assert_account_closed(pubkey) | 계정 종료 여부 확인 |
ctx.svm.assert_sol_balance(pubkey, expected) | SOL 잔액 확인 |
문제 해결
일반적인 오류
| 오류 | 원인 | 해결 방법 |
|---|---|---|
AccountNotFound | 계정이 존재하지 않음 | 데이터를 가져오기 전에 계정이 생성되었는지 확인 |
DiscriminatorMismatch | 잘못된 계정 유형 | 올바른 계정 구조체를 사용하고 있는지 확인 |
DeserializationError | 유효하지 않은 계정 데이터 | 계정이 올바르게 초기화되었는지 확인 |
| No programs added | deploy_program() 없이 build() 호출됨 | 빌드하기 전에 최소 하나의 프로그램을 추가하세요 |
| Missing client types | declare_program!가 호출되지 않음 | 먼저 anchor build를 실행하여 IDL을 생성한 후 declare_program!를 호출하세요 |
Is this page helpful?