Περίληψη
Τα προγράμματα μεταγλωττίζονται σε sBPF μέσω LLVM και εκτελούνται σε sandboxed VM με προϋπολογισμό 1.4M CU ανά συναλλαγή. Το runtime αποθηκεύει σε cache έως 512 μεταγλωττισμένα προγράμματα, παρέχει syscalls για logging, CPI, κρυπτογραφία και μνήμη, και καθυστερεί νέες αναπτύξεις κατά 1 slot.
Μεταγλώττιση
Η Solana χρησιμοποιεί το LLVM για να μεταγλωττίσει προγράμματα σε ELF binaries που περιέχουν Solana Bytecode Format (sBPF). Το ELF binary αποθηκεύεται on-chain σε έναν εκτελέσιμο λογαριασμό.
Το sBPF είναι η προσαρμοσμένη παραλλαγή της Solana του eBPF bytecode, προσαρμοσμένη για το runtime της Solana. Δεν είναι τυπικό eBPF και έχει τροποποιήσεις ειδικές για τη Solana.
Συγγραφή προγραμμάτων
Τα προγράμματα Solana γράφονται κυρίως σε Rust χρησιμοποιώντας μία από τις δύο προσεγγίσεις:
Anchor
Ένα framework που χρησιμοποιεί Rust macros για να μειώσει το boilerplate. Συνιστάται για τους περισσότερους developers.
Native Rust
Άμεση Rust χωρίς frameworks. Προσφέρει πλήρη έλεγχο αλλά απαιτεί περισσότερη χειροκίνητη υλοποίηση.
Μοντέλο εκτέλεσης προγράμματος
Όταν μια συναλλαγή επεξεργάζεται, το runtime εκτελεί κάθε εντολή διαδοχικά μέσω
του
process_message().
Για κάθε εντολή, το runtime:
-
Προετοιμάζει το πλαίσιο της εντολής. Καλεί το
prepare_next_top_level_instruction()για να αντιστοιχίσει τους δείκτες λογαριασμών της εντολής, να ορίσει τις σημαίες signer και writable, και να διαμορφώσει τοTransactionContext. -
Ελέγχει τα precompiles. Αν το πρόγραμμα είναι precompile, το runtime καλεί το
process_precompile(), το οποίο εξακολουθεί να προσθέτει και να αφαιρεί ένα stack frame (μέσωpush()καιpop()) αλλά παρακάμπτει το sBPF VM και την αναζήτηση στην cache προγραμμάτων, εκτελώντας native code απευθείας. -
Προσθέτει ένα stack frame. (Τα βήματα 3-6 συμβαίνουν μέσα στο
InvokeContext::process_instruction()καιprocess_executable_chain(), που καλούνται από τοprocess_message().) Καλεί τοpush()στοInvokeContext, το οποίο αυξάνει το ύψος της στοίβας εντολών και επιβάλλει τον κανόνα επανεισόδου: ένα πρόγραμμα μπορεί να επανεισέλθει στον εαυτό του μόνο αν ο άμεσος καλών (το πρόγραμμα στην τρέχουσα κορυφή της στοίβας εντολών) είναι το ίδιο πρόγραμμα. Η βαθιά αυτο-αναδρομή (A -> A -> A) επιτρέπεται, υπό την προϋπόθεση των ορίων βάθους στοίβας. Άλλα μοτίβα επανεισόδου (π.χ., το A καλεί το B που καλεί το A) επιστρέφουνInstructionError::ReentrancyNotAllowed. -
Επιλύει το πρόγραμμα. Το runtime καλεί το
process_executable_chain()το οποίο καθορίζει τον loader. Αν ο κάτοχος του program account είναι ο native loader, το πρόγραμμα είναι builtin και η συνάρτηση entrypoint του αναζητείται απευθείας από τοProgramCacheForTxBatch. Αν ο κάτοχος είναι ένας από τους BPF loaders (bpf_loader_deprecated,bpf_loader,bpf_loader_upgradeable, ήloader_v4), καλείται αντί αυτού το δικό του builtin entrypoint του loader. -
Εκτελεί το πρόγραμμα BPF. Για προγράμματα BPF, το loader entrypoint αναζητά το μεταγλωττισμένο εκτελέσιμο από την cache προγραμμάτων. Η συνάρτηση
execute()στη συνέχεια:- Σειριοποιεί τα δεδομένα του account σε ένα επίπεδο buffer παραμέτρων
- Δημιουργεί το sBPF VM με stack, heap και περιοχές μνήμης
- Εκτελεί τον μεταγλωττισμένο κώδικα, καταναλώνοντας compute units κατά την
εκτέλεση. Επιστρέφει
ComputationalBudgetExceededαν ξεπεραστεί ο προϋπολογισμός. - Αποσειριοποιεί τα δεδομένα του account από το buffer πίσω στην κατάσταση του account
-
Αφαιρεί το stack frame. Καλεί το
pop()το οποίο επαληθεύει ότι η εντολή δεν παραβίασε τους λογιστικούς κανόνες του runtime (τα υπόλοιπα lamport είναι ισοσκελισμένα, τα readonly accounts δεν τροποποιήθηκαν, τα μεγέθη δεδομένων των accounts είναι εντός ορίων). -
Συσσωρεύει compute units. Τα compute units που καταναλώθηκαν από την εντολή προστίθενται στο συνολικό ποσό της συναλλαγής μέσω του
saturating_add.
Κρυφή μνήμη προγράμματος
Το περιβάλλον εκτέλεσης διατηρεί μια καθολική
ProgramCache
που αποθηκεύει επαληθευμένα και μεταγλωττισμένα προγράμματα. Είναι ενήμερη για
το γράφημα διακλαδώσεων και χειρίζεται τους κανόνες ορατότητας ανάπτυξης, την
εξώθηση και την επαναμεταγλώττιση στα όρια των epochs.
Τύποι καταχωρίσεων κρυφής μνήμης
Κάθε πρόγραμμα που βρίσκεται στην κρυφή μνήμη έχει έναν
ProgramCacheEntryType
που καθορίζει τη συμπεριφορά του κατά την εκτέλεση:
| Τύπος | Περιγραφή |
|---|---|
Loaded | Επαληθευμένο και μεταγλωττισμένο πρόγραμμα, έτοιμο για εκτέλεση. |
Builtin | Εγγενές πρόγραμμα μεταγλωττισμένο στο δυαδικό αρχείο του validator (System, Stake, Vote, κ.λπ.). Δεν αποθηκεύεται on-chain. |
Unloaded | Προηγουμένως επαληθευμένο πρόγραμμα του οποίου το μεταγλωττισμένο εκτελέσιμο αρχείο εξωθήθηκε από τη μνήμη για να ελευθερωθεί χώρος. Εξακολουθεί να παρακολουθεί στατιστικά χρήσης. Μπορεί να επαναφορτωθεί χωρίς επανεπαλήθευση. |
FailedVerification | Σημάδι για προγράμματα που δεν πέρασαν τον επαληθευτή sBPF υπό το τρέχον σύνολο χαρακτηριστικών. Μπορεί να γίνει Loaded εάν οι ενεργοποιήσεις χαρακτηριστικών αλλάξουν τους κανόνες επαλήθευσης. |
Closed | Σημάδι για προγράμματα που κλείστηκαν ρητά ή δεν αναπτύχθηκαν ποτέ. Χρησιμοποιείται επίσης για λογαριασμούς (όπως λογαριασμοί buffer) που ανήκουν σε έναν φορτωτή αλλά δεν περιέχουν εκτελέσιμο κώδικα. |
DelayVisibility | Συνθετικό σημάδι που επιστρέφεται από το ProgramCacheForTxBatch::find() όταν υπάρχει μια καταχώριση Loaded αλλά δεν είναι ακόμη ενεργή (το effective_slot της είναι στο μέλλον). Δεν αποθηκεύεται ποτέ απευθείας στην κρυφή μνήμη. |
Καθυστέρηση ορατότητας
Τα νέα αναπτυγμένα ή αναβαθμισμένα προγράμματα δεν τίθενται σε ισχύ αμέσως. Η
σταθερά
DELAY_VISIBILITY_SLOT_OFFSET
είναι 1, που σημαίνει ότι ένα πρόγραμμα που αναπτύχθηκε στο slot N τίθεται σε
ισχύ στο slot N+1. Κατά τη διάρκεια του slot ανάπτυξης, οποιαδήποτε προσπάθεια
κλήσης της νέας έκδοσης επιστρέφει DelayVisibility, προκαλώντας το
περιβάλλον εκτέλεσης να αναφέρει "Το πρόγραμμα δεν έχει αναπτυχθεί."
Πολιτική εξώθησης
Η προσωρινή μνήμη διατηρεί έως και
MAX_LOADED_ENTRY_COUNT
(512) μεταγλωττισμένες καταχωρήσεις προγράμματος. Όταν επιτευχθεί το όριο, τα
λιγότερο χρησιμοποιούμενα προγράμματα εξωθούνται σε κατάσταση Unloaded. Η
χρήση παρακολουθείται από το
tx_usage_counter
(αυξάνεται κάθε φορά που μια συναλλαγή αναφέρεται στο πρόγραμμα) και το
latest_access_slot.
Επαναμεταγλώττιση ορίου epoch
Εάν μια ενεργοποίηση χαρακτηριστικού αλλάξει το
ProgramRuntimeEnvironments
σε όριο epoch, όλα τα προγράμματα στην προσωρινή μνήμη
επαναμεταγλωττίζονται
σύμφωνα με το νέο περιβάλλον.
Δεδομένα επιστροφής
Τα προγράμματα μπορούν να ορίσουν δεδομένα επιστροφής μέσω της κλήσης συστήματος
sol_set_return_data. Τα δεδομένα αποθηκεύονται σε μια δομή
TransactionReturnData
επιπέδου συναλλαγής που διατηρεί τα bytes δεδομένων και το program_id του
προγράμματος του οποίου η εντολή κάλεσε την κλήση συστήματος. Το μέγιστο μέγεθος
είναι 1.024 bytes (MAX_RETURN_DATA).
Is this page helpful?