Περίληψη
Πριν από την εκτέλεση, το περιβάλλον εκτέλεσης φορτώνει λογαριασμούς, επικυρώνει τον πληρωτή των τελών, ελέγχει την απαλλαγή από ενοίκιο και σειριοποιεί τα δεδομένα λογαριασμού σε μια διάταξη μνήμης στην οποία τα προγράμματα μπορούν να έχουν πρόσβαση.
Αυτή η σελίδα καλύπτει τα εσωτερικά του περιβάλλοντος εκτέλεσης. Οι περισσότεροι προγραμματιστές δεν χρειάζονται αυτές τις πληροφορίες για την ανάπτυξη προγραμμάτων. Δείτε τη δομή λογαριασμού για την προοπτική που αφορά τους προγραμματιστές.
Φόρτωση λογαριασμού
Πριν από την εκτέλεση μιας συναλλαγής, το περιβάλλον εκτέλεσης φορτώνει όλους
τους αναφερόμενους λογαριασμούς μέσω του
load_transaction_accounts().
Αυτή η διαδικασία εκτελεί διάφορες επικυρώσεις:
-
Επικύρωση πληρωτή τελών: Ο πληρωτής τελών (πρώτος λογαριασμός) πρέπει να υπάρχει, να είναι λογαριασμός συστήματος ή λογαριασμός nonce και να έχει αρκετά lamports για να καλύψει τα τέλη (
validate_fee_payer()). Μετά την πληρωμή των τελών, ο λογαριασμός πρέπει είτε να παραμείνει απαλλαγμένος από ενοίκιο είτε να μηδενιστεί εντελώς στα 0 lamports. Δεν μπορεί να καταλήξει μεταξύ 0 και του ελάχιστου ορίου απαλλαγής από ενοίκιο. Οι λογαριασμοί nonce πρέπει πάντα να διατηρούν αρκετά lamports για να παραμένουν απαλλαγμένοι από ενοίκιο. Εάν ο πληρωτής δεν είναι ούτε λογαριασμός συστήματος ούτε λογαριασμός nonce, η συναλλαγή αποτυγχάνει μεTransactionError::InvalidAccountForFee. -
Όριο μεγέθους φορτωμένων δεδομένων: Το συνολικό μέγεθος όλων των φορτωμένων λογαριασμών (συμπεριλαμβανομένου ενός
TRANSACTION_ACCOUNT_BASE_SIZEτων 64 bytes ανά λογαριασμό) δεν πρέπει να υπερβαίνει τοMAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES(64 MiB). Η υπέρβαση αυτού του ορίου παράγειTransactionError::MaxLoadedAccountsDataSizeExceeded. -
Επικύρωση program account: Κάθε πρόγραμμα που καλείται από μια εντολή πρέπει να υπάρχει και να ανήκει σε έναν έγκυρο φορτωτή: έναν από τους
PROGRAM_OWNERS(BPF Loader Upgradeable, BPF Loader, BPF Loader Deprecated, Loader V4) ή τον native loader. Εάν ο program account δεν υπάρχει, η συναλλαγή αποτυγχάνει μεTransactionError::ProgramAccountNotFound. Εάν υπάρχει αλλά έχει έναν μη έγκυρο ιδιοκτήτη, η συναλλαγή αποτυγχάνει μεTransactionError::InvalidProgramForExecution. -
Ανύπαρκτοι λογαριασμοί: Οι λογαριασμοί που δεν υπάρχουν on-chain φορτώνονται ως προεπιλεγμένοι λογαριασμοί (0 lamports, κενά δεδομένα, ιδιοκτησία του προγράμματος συστήματος) με
rent_epochορισμένο σεu64::MAX.
Μορφή σειριοποίησης BPF
Όταν ένα πρόγραμμα καλείται, το runtime σειριοποιεί τους λογαριασμούς σε ένα
συνεχόμενο προσωρινό buffer μνήμης και το μεταβιβάζει στο BPF VM. Η μορφή
σειριοποίησης (για την τυπική ευθυγραμμισμένη μορφή που χρησιμοποιείται από
όλους τους loaders εκτός από τον παρωχημένο loader-v1) ορίζεται στο
serialize_parameters_aligned().
Το buffer ξεκινά με ένα u64 (8 bytes, little-endian) που περιέχει τον αριθμό
των λογαριασμών. Στη συνέχεια, για κάθε λογαριασμό στην εντολή, το buffer
περιέχει:
| Offset | Μέγεθος | Πεδίο | Τύπος |
|---|---|---|---|
| 0 | 1 | δείκτης διπλότυπου | u8 (0xFF = μοναδικός, index = διπλότυπο αυτού του λογαριασμού) |
| 1 | 1 | is_signer | u8 (0 ή 1) |
| 2 | 1 | is_writable | u8 (0 ή 1) |
| 3 | 1 | executable | u8 (0 ή 1) |
| 4 | 4 | original_data_len (δεσμευμένο, πάντα 0) | [0u8; 4] |
| 8 | 32 | key | Pubkey |
| 40 | 32 | owner | Pubkey |
| 72 | 8 | lamports | u64 (little-endian) |
| 80 | 8 | data_len | u64 (little-endian) |
| 88 | data_len | data | [u8] |
| 88 + data_len | 10240 + padding | χώρος realloc + ευθυγράμμιση | Μηδενισμένο σε MAX_PERMITTED_DATA_INCREASE (10 KiB) + padding για ευθυγράμμιση σε BPF_ALIGN_OF_U128 (8 bytes) |
| ... | 8 | rent_epoch | u64 (little-endian) |
Μετά από όλους τους λογαριασμούς, το buffer προσθέτει:
| Μέγεθος | Πεδίο |
|---|---|
| 8 | instruction_data_len (u64, little-endian) |
| instruction_data_len | instruction_data |
| 32 | program_id (Pubkey) |
Για διπλότυπους λογαριασμούς, γράφεται μόνο 1 byte (ο δείκτης διπλότυπου με το ευρετήριο του αρχικού) συν 7 bytes padding.
Αποδιπλοποίηση λογαριασμών
Όταν το ίδιο δημόσιο κλειδί λογαριασμού εμφανίζεται πολλές φορές στον πίνακα
accounts μιας εντολής, το runtime
αποδιπλοποιεί
αυτούς. Κάθε καταχώρηση στη λίστα λογαριασμών της εντολής λαμβάνει τη δική της
δομή
InstructionAccount,
αλλά οι καταχωρήσεις που αναφέρονται στον ίδιο λογαριασμό επιπέδου συναλλαγής
δείχνουν στα ίδια υποκείμενα δεδομένα.
Η μέθοδος
is_instruction_account_duplicate
καθορίζει αν ένα δεδομένο ευρετήριο λογαριασμού εντολής είναι η πρώτη εμφάνιση ή
διπλότυπο αναζητώντας το ευρετήριο λογαριασμού επιπέδου συναλλαγής και
βρίσκοντας το πρώτο ευρετήριο επιπέδου εντολής που αντιστοιχεί σε αυτό:
- Αν το τρέχον ευρετήριο λογαριασμού εντολής ισούται με το πρώτο αντιστοιχισμένο
ευρετήριο, δεν είναι διπλότυπο (επιστρέφει
None). - Διαφορετικά, επιστρέφει
Some(first_index), όπου τοfirst_indexείναι το ευρετήριο της πρώτης εμφάνισης.
Επειδή όλες οι αναφορές στον ίδιο λογαριασμό μοιράζονται το ίδιο υποκείμενο
AccountSharedData, οι τροποποιήσεις μέσω οποιασδήποτε αναφοράς είναι άμεσα
ορατές μέσω όλων των άλλων αναφορών. Ωστόσο, μόνο ένας μεταβλητός δανεισμός
μπορεί να διατηρηθεί τη φορά. Η προσπάθεια δανεισμού του ίδιου λογαριασμού
μεταβλητά μέσω δύο διαφορετικών ευρετηρίων λογαριασμού εντολής ταυτόχρονα
επιστρέφει InstructionError::AccountBorrowFailed. Τα προγράμματα πρέπει να
απελευθερώσουν έναν δανεισμό πριν αποκτήσουν άλλον στον ίδιο υποκείμενο
λογαριασμό.
Μετά την εκτέλεση του προγράμματος, το runtime αποσειριοποιεί το buffer
(deserialize_parameters_aligned())
και εφαρμόζει τυχόν αλλαγές στα lamports, data (συμπεριλαμβανομένων αλλαγών
μήκους έως MAX_PERMITTED_DATA_INCREASE), και owner.
Is this page helpful?