Κατανόηση των Anchor Account Discriminators
Τα προγράμματα Anchor προσαρτούν έναν discriminator 8 byte σε όλα τα δεδομένα λογαριασμού. Αυτός ο discriminator είναι ένα hash του ονόματος τύπου λογαριασμού και χρησιμοποιείται για την επαλήθευση ότι τα δεδομένα λογαριασμού αντιστοιχούν στον αναμενόμενο τύπο.
┌─────────────────────────────────────────────────┐│ Account Data Layout │├────────────────┬────────────────────────────────┤│ Discriminator │ Account Fields ││ (8 bytes) │ (variable size) │└────────────────┴────────────────────────────────┘
Τα βοηθητικά προγράμματα λογαριασμού anchor-litesvm διαχειρίζονται αυτόν τον
discriminator αυτόματα.
Ανάκτηση Λογαριασμών Anchor
Βασική Ανάκτηση Λογαριασμού
use anchor_litesvm::AnchorLiteSVM;use anchor_lang::prelude::*;use solana_signer::Signer;use solana_program::pubkey::Pubkey;#[account]pub struct UserAccount {pub name: String,pub balance: u64,pub authority: Pubkey,}#[test]fn test_fetch_account() {let mut ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));let user = ctx.create_funded_account(10_000_000_000).unwrap();// ... initialize the account ...let (user_pda, _) = Pubkey::find_program_address(&[b"user", user.pubkey().as_ref()],&PROGRAM_ID,);// Fetch and deserialize the accountlet account: UserAccount = ctx.get_account(&user_pda).unwrap();assert_eq!(account.name, "Alice");assert_eq!(account.authority, user.pubkey());}
Το get_account<T>() επικυρώνει αυτόματα τον discriminator 8 byte για να διασφαλίσει ότι τα δεδομένα λογαριασμού αντιστοιχούν στον αναμενόμενο τύπο.
Αποσειριοποίηση Χωρίς Έλεγχο
Για PDAs ή προσαρμοσμένες διατάξεις λογαριασμού όπου η επικύρωση discriminator
ενδέχεται να αποτύχει, χρησιμοποιήστε το get_account_unchecked:
use anchor_litesvm::AnchorLiteSVM;#[test]fn test_fetch_unchecked() {let ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));// Fetch without discriminator validationlet account: UserAccount = ctx.get_account_unchecked(&some_pda).unwrap();}
Χρησιμοποιήστε το get_account_unchecked με προσοχή. Χωρίς επικύρωση
discriminator, ενδέχεται να αποσειριοποιήσετε μη έγκυρα δεδομένα.
Χρησιμοποιήστε το μόνο όταν είστε βέβαιοι για τον τύπο του λογαριασμού.
Χρήση του Μodule Λογαριασμού Άμεσα
Μπορείτε επίσης να χρησιμοποιήσετε απευθείας τις συναρτήσεις αποσειριοποίησης λογαριασμού:
use anchor_litesvm::{get_anchor_account, get_anchor_account_unchecked};use litesvm::LiteSVM;#[test]fn test_direct_account_fetch() {let mut svm = LiteSVM::new();// ... setup ...// Fetch with discriminator checklet account: UserAccount = get_anchor_account(&svm, &account_pubkey).unwrap();// Fetch without discriminator checklet account: UserAccount = get_anchor_account_unchecked(&svm, &account_pubkey).unwrap();}
Σφάλματα Λογαριασμού
Το enum AccountError παρέχει λεπτομερείς πληροφορίες σφάλματος:
use anchor_litesvm::AccountError;#[test]fn test_handle_errors() {let ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));let result: Result<UserAccount, AccountError> = ctx.get_account(&nonexistent_pubkey);match result {Ok(account) => println!("Found account: {}", account.name),Err(AccountError::AccountNotFound(pubkey)) => {println!("Account not found: {}", pubkey);}Err(AccountError::DiscriminatorMismatch) => {println!("Wrong account type!");}Err(AccountError::DeserializationError(msg)) => {println!("Failed to deserialize: {}", msg);}}}
| Σφάλμα | Περιγραφή |
|---|---|
AccountNotFound(Pubkey) | Δεν υπάρχει λογαριασμός στη δοθείσα διεύθυνση |
DiscriminatorMismatch | Ο discriminator λογαριασμού δεν αντιστοιχεί στον αναμενόμενο τύπο |
DeserializationError(String) | Αποτυχία αποσειριοποίησης δεδομένων λογαριασμού |
Εργασία με Πολλαπλούς Τύπους Λογαριασμών
Ανάκτηση Διαφορετικών Τύπων Λογαριασμών
use anchor_litesvm::AnchorLiteSVM;use anchor_lang::prelude::*;#[account]pub struct Config {pub admin: Pubkey,pub fee_bps: u16,}#[account]pub struct UserProfile {pub owner: Pubkey,pub username: String,pub created_at: i64,}#[account]pub struct Order {pub user: Pubkey,pub amount: u64,pub status: OrderStatus,}#[derive(AnchorSerialize, AnchorDeserialize, Clone)]pub enum OrderStatus {Pending,Completed,Cancelled,}#[test]fn test_multiple_account_types() {let ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));// Each account type is deserialized correctlylet config: Config = ctx.get_account(&config_pda).unwrap();let profile: UserProfile = ctx.get_account(&profile_pda).unwrap();let order: Order = ctx.get_account(&order_pda).unwrap();assert_eq!(config.fee_bps, 100);assert_eq!(profile.username, "alice");assert!(matches!(order.status, OrderStatus::Pending));}
Έλεγχος Ύπαρξης Λογαριασμού Πριν την Ανάκτηση
use anchor_litesvm::AnchorLiteSVM;#[test]fn test_check_before_fetch() {let ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));let user_pda = Pubkey::new_unique();// Check existence firstif ctx.account_exists(&user_pda) {let account: UserAccount = ctx.get_account(&user_pda).unwrap();println!("Found: {}", account.name);} else {println!("Account not initialized yet");}}
Πλήρες Παράδειγμα
Ακολουθεί ένα ολοκληρωμένο παράδειγμα που παρουσιάζει τη διαχείριση λογαριασμών:
use anchor_litesvm::AnchorLiteSVM;use anchor_litesvm::TestHelpers;use anchor_lang::prelude::*;use solana_signer::Signer;use solana_program::pubkey::Pubkey;anchor_lang::declare_program!(counter);#[test]fn test_counter_workflow() {let mut ctx = AnchorLiteSVM::build_with_program(id(),include_bytes!("../target/deploy/counter.so"),);let authority = ctx.svm.create_funded_account(10_000_000_000).unwrap();// Derive the counter PDAlet (counter_pda, bump) = Pubkey::find_program_address(&[b"counter", authority.pubkey().as_ref()],&id(),);// Verify counter doesn't exist yetassert!(!ctx.account_exists(&counter_pda));// Initialize using generated client typeslet init_ix = ctx.program().accounts(counter::client::accounts::Initialize {authority: authority.pubkey(),counter: counter_pda,system_program: anchor_lang::system_program::ID,}).args(counter::client::args::Initialize {}).instruction().unwrap();ctx.execute_instruction(init_ix, &[&authority]).unwrap();// Verify counter exists and has correct initial stateassert!(ctx.account_exists(&counter_pda));let counter: counter::Counter = ctx.get_account(&counter_pda).unwrap();assert_eq!(counter.count, 0);assert_eq!(counter.authority, authority.pubkey());assert_eq!(counter.bump, bump);// Increment using generated client typeslet increment_ix = ctx.program().accounts(counter::client::accounts::Increment {authority: authority.pubkey(),counter: counter_pda,}).args(counter::client::args::Increment {}).instruction().unwrap();ctx.execute_instruction(increment_ix, &[&authority]).unwrap();// Verify incrementedlet counter: counter::Counter = ctx.get_account(&counter_pda).unwrap();assert_eq!(counter.count, 1);// Increment againctx.execute_instruction(increment_ix.clone(), &[&authority]).unwrap();let counter: counter::Counter = ctx.get_account(&counter_pda).unwrap();assert_eq!(counter.count, 2);println!("Counter test passed! Final count: {}", counter.count);}
Is this page helpful?