Εκτέλεση Προγράμματος

Σύνοψη

Τα προγράμματα μεταγλωττίζονται σε sBPF μέσω LLVM και εκτελούνται σε μια απομονωμένη VM με προϋπολογισμό 1,4M CU ανά συναλλαγή. Το runtime αποθηκεύει στην κρυφή μνήμη έως 512 μεταγλωττισμένα προγράμματα, παρέχει syscalls για καταγραφή, CPI, κρυπτογραφία και μνήμη, και καθυστερεί νέες αναπτύξεις κατά 1 slot.

Μεταγλώττιση

Η Solana χρησιμοποιεί LLVM για να μεταγλωττίζει προγράμματα σε ELF δυαδικά αρχεία που περιέχουν το Solana Bytecode Format (sBPF). Το δυαδικό αρχείο ELF αποθηκεύεται onchain σε ένα εκτελέσιμο λογαριασμό.

Το sBPF είναι η προσαρμοσμένη παραλλαγή της Solana του eBPF bytecode, προσαρμοσμένη για το Solana runtime. Δεν είναι τυπικό eBPF και διαθέτει τροποποιήσεις ειδικές για τη Solana.

Συγγραφή προγραμμάτων

Τα προγράμματα Solana γράφονται κυρίως σε Rust χρησιμοποιώντας μία από τρεις προσεγγίσεις:

Δείτε Cross-Program Invocations για έννοιες και παραδείγματα CPI που ισχύουν σε αυτές τις προσεγγίσεις.

Μοντέλο εκτέλεσης προγράμματος

Όταν επεξεργάζεται μια συναλλαγή, το runtime εκτελεί κάθε εντολή διαδοχικά μέσω process_message(). Για κάθε εντολή, το runtime:

  1. Προετοιμάζει το πλαίσιο εντολής. Καλεί prepare_next_top_level_instruction() για να αντιστοιχίσει τους δείκτες λογαριασμού της εντολής, να ορίσει τις σημαίες υπογράφοντος και εγγράψιμου, και να διαμορφώσει το TransactionContext.

  2. Ελέγχει precompiles. Εάν το πρόγραμμα είναι ένα precompile, το runtime καλεί process_precompile(), το οποίο εξακολουθεί να ωθεί και να αναδύει ένα stack frame (μέσω push() και pop()) αλλά παρακάμπτει την sBPF VM και την αναζήτηση κρυφής μνήμης προγράμματος, εκτελώντας native κώδικα απευθείας.

  3. Ωθεί ένα stack frame. (Τα βήματα 3-6 συμβαίνουν μέσα στο InvokeContext::process_instruction() και process_executable_chain(), που καλούνται από process_message().) Καλεί push() στο InvokeContext, το οποίο αυξάνει το ύψος στοίβας εντολών και επιβάλλει τον κανόνα επανεισόδου: ένα πρόγραμμα μπορεί να επανεισέλθει στον εαυτό του μόνο εάν ο άμεσος καλών (το πρόγραμμα στην κορυφή της τρέχουσας στοίβας εντολών) είναι το ίδιο πρόγραμμα. Η βαθιά αυτο-αναδρομή (A -> A -> A) επιτρέπεται, υπό τα όρια βάθους στοίβας. Άλλα μοτίβα επανεισόδου (π.χ., το A καλεί το B που καλεί το A) επιστρέφουν InstructionError::ReentrancyNotAllowed.

  4. Επιλύει το πρόγραμμα. Το runtime καλεί process_executable_chain() το οποίο προσδιορίζει τον φορτωτή. Εάν ο κάτοχος του program account είναι ο native loader, το πρόγραμμα είναι builtin και η συνάρτηση entrypoint του αναζητείται απευθείας από το ProgramCacheForTxBatch. Εάν ο κάτοχος είναι ένας από τους BPF loaders (bpf_loader_deprecated, bpf_loader, bpf_loader_upgradeable, ή loader_v4), το δικό του builtin entrypoint του φορτωτή καλείται αντ' αυτού.

  5. Εκτελεί το BPF πρόγραμμα. Για BPF προγράμματα, το loader entrypoint αναζητά το μεταγλωττισμένο εκτελέσιμο από την κρυφή μνήμη προγράμματος. Η συνάρτηση execute() στη συνέχεια:

    • Σειριοποιεί δεδομένα λογαριασμού σε ένα επίπεδο buffer παραμέτρων
    • Δημιουργεί την sBPF VM με στοίβα, heap και περιοχές μνήμης
    • Εκτελεί τον μεταγλωττισμένο κώδικα, καταναλώνοντας μονάδες υπολογισμού κατά την εκτέλεση. Επιστρέφει ComputationalBudgetExceeded εάν ο προϋπολογισμός υπερβαίνεται.
    • Αποσειριοποιεί δεδομένα λογαριασμού από το buffer πίσω στην κατάσταση λογαριασμού
  6. Αναδύει το stack frame. Καλεί pop() το οποίο επαληθεύει ότι η εντολή δεν παραβίασε τους κανόνες λογιστικής του runtime (τα υπόλοιπα lamport είναι ισορροπημένα, οι λογαριασμοί μόνο ανάγνωσης δεν τροποποιήθηκαν, τα μεγέθη δεδομένων λογαριασμού είναι εντός ορίων).

  7. Συσσωρεύει μονάδες υπολογισμού. Οι μονάδες υπολογισμού που καταναλώθηκαν από την εντολή προστίθενται στο σύνολο της συναλλαγής μέσω saturating_add.

Κρυφή μνήμη προγράμματος

Το runtime διατηρεί μια παγκόσμια ProgramCache που αποθηκεύει επαληθευμένα και μεταγλωττισμένα προγράμματα. Είναι ενήμερη για το fork-graph και χειρίζεται κανόνες ορατότητας ανάπτυξης, εκτόπιση και επαναμεταγλώττιση ορίων epoch.

Τύποι καταχώρισης κρυφής μνήμης

Κάθε αποθηκευμένο πρόγραμμα στην κρυφή μνήμη έχει έναν ProgramCacheEntryType που καθορίζει τη συμπεριφορά του κατά την εκτέλεση:

ΤύποςΠεριγραφή
LoadedΕπαληθευμένο και μεταγλωττισμένο πρόγραμμα, έτοιμο για εκτέλεση.
BuiltinNative πρόγραμμα μεταγλωττισμένο στο δυαδικό αρχείο validator (System, Stake, Vote, κ.λπ.). Δεν αποθηκεύεται onchain.
UnloadedΠροηγουμένως επαληθευμένο πρόγραμμα του οποίου το μεταγλωττισμένο εκτελέσιμο εκτοπίστηκε από τη μνήμη για να ελευθερωθεί χώρος. Εξακολουθεί να παρακολουθεί στατιστικά χρήσης. Μπορεί να επαναφορτωθεί χωρίς επαναλήπτη επαλήθευση.
FailedVerificationTombstone για προγράμματα που δεν πέρασαν τον sBPF verifier στο τρέχον σύνολο χαρακτηριστικών. Μπορεί να γίνει Loaded εάν οι ενεργοποιήσεις χαρακτηριστικών αλλάξουν τους κανόνες επαλήθευσης.
ClosedTombstone για προγράμματα που έκλεισαν ρητά ή δεν αναπτύχθηκαν ποτέ. Χρησιμοποιείται επίσης για λογαριασμούς (όπως buffer accounts) που ανήκουν σε φορτωτή αλλά δεν περιέχουν εκτελέσιμο κώδικα.
DelayVisibilityΣυνθετικό tombstone που επιστρέφεται από ProgramCacheForTxBatch::find() όταν υπάρχει μια καταχώριση Loaded αλλά δεν είναι ακόμη αποτελεσματική (το effective_slot της βρίσκεται στο μέλλον). Δεν αποθηκεύεται ποτέ απευθείας στην κρυφή μνήμη.

Καθυστέρηση ορατότητας

Τα νεοαναπτυχθέντα ή αναβαθμισμένα προγράμματα δεν τίθενται σε ισχύ αμέσως. Η σταθερά DELAY_VISIBILITY_SLOT_OFFSET έχει τιμή 1, που σημαίνει ότι ένα πρόγραμμα που αναπτύχθηκε στο slot N τίθεται σε ισχύ στο slot N+1. Κατά τη διάρκεια του slot ανάπτυξης, κάθε προσπάθεια επίκλησης της νέας έκδοσης επιστρέφει DelayVisibility, προκαλώντας το runtime να αναφέρει "Το πρόγραμμα δεν έχει αναπτυχθεί."

Πολιτική εκτόπισης

Η κρυφή μνήμη χωράει έως MAX_LOADED_ENTRY_COUNT (512) μεταγλωττισμένες καταχωρίσεις προγραμμάτων. Όταν φτάσει το όριο, τα λιγότερο χρησιμοποιούμενα προγράμματα εκτοπίζονται στην κατάσταση Unloaded. Η χρήση παρακολουθείται από tx_usage_counter (αυξάνεται κάθε φορά που μια συναλλαγή αναφέρεται στο πρόγραμμα) και latest_access_slot.

Επαναμεταγλώττιση ορίου epoch

Εάν μια ενεργοποίηση χαρακτηριστικού αλλάξει τα ProgramRuntimeEnvironments σε ένα όριο epoch, όλα τα αποθηκευμένα προγράμματα επαναμεταγλωττίζονται έναντι του νέου περιβάλλοντος.

Δεδομένα επιστροφής

Τα προγράμματα μπορούν να ορίσουν δεδομένα επιστροφής μέσω του syscall sol_set_return_data. Τα δεδομένα αποθηκεύονται σε μια δομή TransactionReturnData σε επίπεδο συναλλαγής που περιέχει τα bytes δεδομένων και το program_id του προγράμματος του οποίου η εντολή κάλεσε το syscall. Το μέγιστο μέγεθος είναι 1.024 bytes (MAX_RETURN_DATA).

Is this page helpful?

© 2026 Ίδρυμα Solana. Με επιφύλαξη παντός δικαιώματος.