Κατανόηση των Συμβάντων Anchor
Τα προγράμματα Anchor μπορούν να εκπέμπουν συμβάντα που καταγράφονται κατά την
εκτέλεση συναλλαγών. Αυτά τα συμβάντα κωδικοποιούνται σε Base64 στα αρχεία
καταγραφής συναλλαγών με το πρόθεμα Program data:. Το crate anchor-litesvm
παρέχει βοηθητικές συναρτήσεις για την ανάλυση και την επαλήθευση αυτών των
συμβάντων.
┌─────────────────────────────────────────────────┐│ Anchor Event Structure │├────────────────┬────────────────────────────────┤│ Discriminator │ Event Data ││ (8 bytes) │ (serialized fields) │└────────────────┴────────────────────────────────┘
Ορισμός Συμβάντων
Αρχικά, ορίστε τα συμβάντα σας στο πρόγραμμα Anchor:
use anchor_lang::prelude::*;#[event]pub struct TransferEvent {pub from: Pubkey,pub to: Pubkey,pub amount: u64,pub timestamp: i64,}#[event]pub struct InitializeEvent {pub authority: Pubkey,pub name: String,}
Ανάλυση Συμβάντων
Ανάλυση Όλων των Συμβάντων Ενός Τύπου
use anchor_litesvm::{AnchorLiteSVM, EventHelpers};use solana_signer::Signer;#[test]fn test_parse_events() {let mut ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));let user = ctx.svm.create_funded_account(10_000_000_000).unwrap();// Execute instruction that emits eventslet ix = ctx.program().accounts(Transfer { /* ... */ }).args(TransferArgs { amount: 1000 }).instruction().unwrap();let result = ctx.execute_instruction(ix, &[&user]).unwrap();// Parse all TransferEvent events from the transactionlet events: Vec<TransferEvent> = result.parse_events().unwrap();assert_eq!(events.len(), 1);assert_eq!(events[0].amount, 1000);}
Ανάλυση Μεμονωμένου Συμβάντος
use anchor_litesvm::{AnchorLiteSVM, EventHelpers};#[test]fn test_parse_single_event() {let mut ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));// ... execute instruction ...// Get the first event of the typelet event: TransferEvent = result.parse_event().unwrap();println!("Transfer: {} -> {} ({})", event.from, event.to, event.amount);}
Επαλήθευση Συμβάντων
Επαλήθευση Εκπομπής Συμβάντος
use anchor_litesvm::{AnchorLiteSVM, EventHelpers};#[test]fn test_assert_event_emitted() {let mut ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));let user = ctx.svm.create_funded_account(10_000_000_000).unwrap();let ix = ctx.program().accounts(Initialize { /* ... */ }).args(InitializeArgs { name: "test".to_string() }).instruction().unwrap();let result = ctx.execute_instruction(ix, &[&user]).unwrap();// Assert that at least one InitializeEvent was emittedresult.assert_event_emitted::<InitializeEvent>();}
Το assert_event_emitted θα προκαλέσει panic αν δεν βρεθούν συμβάντα του
καθορισμένου τύπου στα αρχεία καταγραφής συναλλαγών.
Επαλήθευση Πλήθους Συμβάντων
use anchor_litesvm::{AnchorLiteSVM, EventHelpers};#[test]fn test_assert_event_count() {let mut ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));// Execute instruction that emits multiple eventslet ix = ctx.program().accounts(BatchTransfer { /* ... */ }).args(BatchTransferArgs { recipients: vec![...], amounts: vec![...] }).instruction().unwrap();let result = ctx.execute_instruction(ix, &[&user]).unwrap();// Assert exactly 3 TransferEvent events were emittedresult.assert_event_count::<TransferEvent>(3);}
Έλεγχος Ύπαρξης Συμβάντος
use anchor_litesvm::{AnchorLiteSVM, EventHelpers};#[test]fn test_has_event() {let mut ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));// ... execute instruction ...// Check without panickingif result.has_event::<TransferEvent>() {let event: TransferEvent = result.parse_event().unwrap();println!("Transfer occurred: {}", event.amount);} else {println!("No transfer in this transaction");}}
Χειροκίνητη Ανάλυση Συμβάντων
Για προχωρημένες περιπτώσεις χρήσης, μπορείτε να αναλύσετε τα δεδομένα συμβάντων απευθείας:
use anchor_litesvm::parse_event_data;#[test]fn test_manual_parse() {// If you have the base64-encoded event datalet base64_data = "SGVsbG8gV29ybGQ="; // Examplelet event: TransferEvent = parse_event_data(base64_data).unwrap();}
Σφάλματα Συμβάντων
Το enum EventError παρέχει λεπτομερείς πληροφορίες σφάλματος:
use anchor_litesvm::EventError;match result.parse_event::<TransferEvent>() {Ok(event) => println!("Amount: {}", event.amount),Err(EventError::EventNotFound) => println!("No event found"),Err(EventError::ParseError(msg)) => println!("Parse error: {}", msg),Err(EventError::Base64Error) => println!("Invalid Base64 encoding"),Err(EventError::InvalidFormat) => println!("Malformed event data"),Err(EventError::AnchorError(msg)) => println!("Anchor error: {}", msg),}
| Σφάλμα | Περιγραφή |
|---|---|
EventNotFound | Δεν υπάρχει συμβάν του καθορισμένου τύπου στα αρχεία καταγραφής |
ParseError(String) | Αποτυχία ανάλυσης δεδομένων συμβάντος |
Base64Error | Αποτυχία αποκωδικοποίησης Base64 |
InvalidFormat | Τα δεδομένα συμβάντος έχουν μη έγκυρη δομή |
AnchorError(String) | Η αποσειριοποίηση Anchor απέτυχε |
Πλήρες Παράδειγμα
Ακολουθεί ένα ολοκληρωμένο παράδειγμα που δείχνει τον χειρισμό συμβάντων:
use anchor_litesvm::{AnchorLiteSVM, EventHelpers, TestHelpers};use anchor_lang::{prelude::*, system_program};use solana_signer::Signer;// declare_program! generates client types AND re-exports event structsanchor_lang::declare_program!(vault);#[test]fn test_vault_events() {let mut ctx = AnchorLiteSVM::build_with_program(VAULT_PROGRAM_ID,include_bytes!("../target/deploy/vault.so"),);let authority = ctx.svm.create_funded_account(100_000_000_000).unwrap();let depositor = ctx.svm.create_funded_account(50_000_000_000).unwrap();let vault_pda = ctx.svm.get_pda(&[b"vault", authority.pubkey().as_ref()],&VAULT_PROGRAM_ID,);// Create vaultlet create_ix = ctx.program().accounts(vault::client::accounts::CreateVault {authority: authority.pubkey(),vault: vault_pda,system_program: system_program::ID,}).args(vault::client::args::CreateVault {}).instruction().unwrap();let result = ctx.execute_instruction(create_ix, &[&authority]).unwrap();// Assert VaultCreated eventresult.assert_event_emitted::<vault::VaultCreated>();let created_event: vault::VaultCreated = result.parse_event().unwrap();assert_eq!(created_event.vault, vault_pda);assert_eq!(created_event.authority, authority.pubkey());// Depositlet deposit_ix = ctx.program().accounts(vault::client::accounts::DepositToVault {vault: vault_pda,depositor: depositor.pubkey(),system_program: system_program::ID,}).args(vault::client::args::Deposit { amount: 10_000_000_000 }).instruction().unwrap();let result = ctx.execute_instruction(deposit_ix, &[&depositor]).unwrap();// Assert Deposit eventresult.assert_event_emitted::<vault::Deposit>();let deposit_event: vault::Deposit = result.parse_event().unwrap();assert_eq!(deposit_event.amount, 10_000_000_000);assert_eq!(deposit_event.depositor, depositor.pubkey());// Withdrawallet withdraw_ix = ctx.program().accounts(vault::client::accounts::WithdrawFromVault {vault: vault_pda,authority: authority.pubkey(),recipient: authority.pubkey(),}).args(vault::client::args::Withdraw { amount: 5_000_000_000 }).instruction().unwrap();let result = ctx.execute_instruction(withdraw_ix, &[&authority]).unwrap();// Check withdrawal eventassert!(result.has_event::<vault::Withdrawal>());let withdraw_event: vault::Withdrawal = result.parse_event().unwrap();assert_eq!(withdraw_event.amount, 5_000_000_000);println!("All event tests passed!");}
Τα συμβάντα είναι ένας εξαιρετικός τρόπος για να επαληθεύσετε ότι το πρόγραμμά σας εκτελέστηκε σωστά χωρίς να χρειαστεί να ανακτήσετε και να αποσειριοποιήσετε λογαριασμούς. Είναι ιδιαίτερα χρήσιμα για την παρακολούθηση αλλαγών κατάστασης με την πάροδο του χρόνου.
Is this page helpful?