Συχνές Ερωτήσεις
Υποβάλετε τις ερωτήσεις σας στο StackExchange.
Berkeley Packet Filter (BPF)
Τα προγράμματα onchain της Solana μεταγλωττίζονται μέσω της υποδομής μεταγλωττιστή LLVM σε μια Εκτελέσιμη και Συνδέσιμη Μορφή (ELF) που περιέχει μια παραλλαγή του Berkeley Packet Filter (BPF) bytecode.
Επειδή η Solana χρησιμοποιεί την υποδομή μεταγλωττιστή LLVM, ένα πρόγραμμα μπορεί να γραφτεί σε οποιαδήποτε γλώσσα προγραμματισμού που μπορεί να στοχεύσει το backend BPF του LLVM.
Το BPF παρέχει ένα αποδοτικό σύνολο εντολών που μπορεί να εκτελεστεί σε μια διερμηνευμένη εικονική μηχανή ή ως αποδοτικές εντολές μεταγλωττισμένες σε εγγενή κώδικα just-in-time.
Χάρτης μνήμης
Ο χάρτης εικονικής διεύθυνσης μνήμης που χρησιμοποιείται από τα προγράμματα SBF της Solana είναι σταθερός και διαμορφωμένος ως εξής
- Ο κώδικας προγράμματος ξεκινά στο 0x100000000
- Τα δεδομένα στοίβας ξεκινούν στο 0x200000000
- Τα δεδομένα σωρού ξεκινούν στο 0x300000000
- Οι παράμετροι εισόδου προγράμματος ξεκινούν στο 0x400000000
Οι παραπάνω εικονικές διευθύνσεις είναι διευθύνσεις εκκίνησης, αλλά στα προγράμματα δίνεται πρόσβαση σε ένα υποσύνολο του χάρτη μνήμης. Το πρόγραμμα θα πανικοβληθεί αν προσπαθήσει να διαβάσει ή να γράψει σε μια εικονική διεύθυνση στην οποία δεν του έχει δοθεί πρόσβαση, και θα επιστραφεί ένα σφάλμα "AccessViolation" που περιέχει τη διεύθυνση και το μέγεθος της απόπειρας παραβίασης.
InvalidAccountData
Αυτό το σφάλμα προγράμματος μπορεί να συμβεί για πολλούς λόγους. Συνήθως, προκαλείται από την παροχή ενός λογαριασμού στο πρόγραμμα που το πρόγραμμα δεν αναμένει, είτε σε λάθος θέση στην εντολή είτε ένας λογαριασμός μη συμβατός με την εντολή που εκτελείται.
Μια υλοποίηση ενός προγράμματος μπορεί επίσης να προκαλέσει αυτό το σφάλμα κατά την εκτέλεση μιας εντολής διαπρογραμματικής κλήσης και την παράλειψη παροχής του λογαριασμού για το πρόγραμμα που καλείτε.
InvalidInstructionData
Αυτό το σφάλμα προγράμματος μπορεί να προκύψει κατά την προσπάθεια
αποσειριοποίησης της εντολής. Ελέγξτε ότι η δομή που περνάτε ταιριάζει ακριβώς
με την εντολή. Μπορεί να υπάρχει κάποια συμπλήρωση μεταξύ των πεδίων. Αν το
πρόγραμμα υλοποιεί το Rust trait Instruction
τότε δοκιμάστε να συσκευάσετε και
να αποσυσκευάσετε τον τύπο εντολής Instruction
για να προσδιορίσετε την ακριβή
κωδικοποίηση που αναμένει το πρόγραμμα.
MissingRequiredSignature
Ορισμένες εντολές απαιτούν ο λογαριασμός να είναι υπογεγραμμένος. Αυτό το σφάλμα επιστρέφεται αν ένας λογαριασμός αναμένεται να είναι υπογεγραμμένος αλλά δεν είναι.
Μια υλοποίηση ενός προγράμματος μπορεί επίσης να προκαλέσει αυτό το σφάλμα κατά
την εκτέλεση μιας διασταυρούμενης κλήσης προγράμματος που
απαιτεί μια υπογεγραμμένη διεύθυνση προγράμματος, αλλά οι σπόροι υπογραφής που
περνούν στο invoke_signed
δεν ταιριάζουν με τους σπόρους υπογραφής που
χρησιμοποιούνται για τη δημιουργία της διεύθυνσης προγράμματος
create_program_address
.
Stack
Το SBF χρησιμοποιεί πλαίσια στοίβας αντί για μεταβλητό δείκτη στοίβας. Κάθε πλαίσιο στοίβας είναι μεγέθους 4KB.
Εάν ένα πρόγραμμα παραβιάζει αυτό το μέγεθος πλαισίου στοίβας, ο μεταγλωττιστής θα αναφέρει την υπέρβαση ως προειδοποίηση.
Για παράδειγμα:
warning: too many stack frames in function _ZN16curve25519_dalek7edwards21EdwardsBasepointTable6create17h178b3d2411f7f082E, frame size 4128
Το μήνυμα προσδιορίζει ποιο σύμβολο υπερβαίνει το πλαίσιο στοίβας του, αλλά το όνομα μπορεί να είναι παραμορφωμένο.
Για να αποκωδικοποιήσετε ένα σύμβολο Rust χρησιμοποιήστε το rustfilt.
Η παραπάνω προειδοποίηση προήλθε από ένα πρόγραμμα Rust, οπότε το αποκωδικοποιημένο όνομα συμβόλου είναι:
curve25519_dalek::edwards::EdwardsBasepointTable::create
Ο λόγος που αναφέρεται μια προειδοποίηση αντί για σφάλμα είναι επειδή ορισμένα
εξαρτώμενα crates μπορεί να περιλαμβάνουν λειτουργικότητα που παραβιάζει τους
περιορισμούς πλαισίου στοίβας ακόμη κι αν το πρόγραμμα δεν χρησιμοποιεί αυτή τη
λειτουργικότητα. Εάν το πρόγραμμα παραβιάζει το μέγεθος στοίβας κατά το χρόνο
εκτέλεσης, θα αναφερθεί ένα σφάλμα CallDepth
.
Τα πλαίσια στοίβας SBF καταλαμβάνουν ένα εύρος εικονικών διευθύνσεων που ξεκινά
από το 0x200000000
.
Μέγεθος σωρού
Τα προγράμματα έχουν πρόσβαση σε έναν σωρό χρόνου εκτέλεσης μέσω των API της
Rust alloc
. Για τη διευκόλυνση γρήγορων κατανομών, χρησιμοποιείται ένας απλός
σωρός bump 32KB. Ο σωρός δεν υποστηρίζει free
ή realloc
.
Εσωτερικά, τα προγράμματα έχουν πρόσβαση στην περιοχή μνήμης 32KB που ξεκινά από την εικονική διεύθυνση 0x300000000 και μπορούν να υλοποιήσουν έναν προσαρμοσμένο σωρό με βάση τις συγκεκριμένες ανάγκες του προγράμματος.
Τα προγράμματα Rust υλοποιούν τον σωρό απευθείας ορίζοντας ένα προσαρμοσμένο
global_allocator
Φορτωτές
Τα προγράμματα αναπτύσσονται και εκτελούνται από φορτωτές χρόνου εκτέλεσης, επί του παρόντος υπάρχουν δύο υποστηριζόμενοι φορτωτές BPF Loader και BPF loader deprecated
Οι φορτωτές μπορεί να υποστηρίζουν διαφορετικές διεπαφές δυαδικών εφαρμογών,
οπότε οι προγραμματιστές πρέπει να γράφουν τα προγράμματά τους για και να τα
αναπτύσσουν στον ίδιο φορτωτή. Εάν ένα πρόγραμμα γραμμένο για έναν φορτωτή
αναπτυχθεί σε διαφορετικό, το αποτέλεσμα είναι συνήθως ένα σφάλμα
AccessViolation
λόγω αναντιστοιχίας στην αποσειριοποίηση των παραμέτρων
εισόδου του προγράμματος.
Για όλους τους πρακτικούς σκοπούς, τα προγράμματα θα πρέπει πάντα να γράφονται με στόχο τον τελευταίο φορτωτή BPF και ο τελευταίος φορτωτής είναι ο προεπιλεγμένος για τη διεπαφή γραμμής εντολών και τα API javascript.
Ανάπτυξη
Η ανάπτυξη προγράμματος SBF είναι η διαδικασία μεταφόρτωσης ενός κοινόχρηστου
αντικειμένου BPF στα δεδομένα λογαριασμού προγράμματος και η επισήμανση του
λογαριασμού ως εκτελέσιμου. Ένας πελάτης διαχωρίζει το κοινόχρηστο αντικείμενο
SBF σε μικρότερα κομμάτια και τα στέλνει ως δεδομένα οδηγιών των
Write
οδηγιών στον φορτωτή όπου ο φορτωτής γράφει αυτά τα δεδομένα στα δεδομένα
λογαριασμού του προγράμματος. Μόλις ληφθούν όλα τα κομμάτια, ο πελάτης στέλνει
μια
Finalize
οδηγία στον φορτωτή, ο φορτωτής στη συνέχεια επικυρώνει ότι τα δεδομένα SBF
είναι έγκυρα και επισημαίνει τον λογαριασμό του προγράμματος ως εκτελέσιμο.
Μόλις ο λογαριασμός του προγράμματος επισημανθεί ως εκτελέσιμος, οι επόμενες
συναλλαγές μπορούν να εκδώσουν οδηγίες για επεξεργασία από αυτό το πρόγραμμα.
Όταν μια εντολή κατευθύνεται σε ένα εκτελέσιμο πρόγραμμα SBF, ο φορτωτής διαμορφώνει το περιβάλλον εκτέλεσης του προγράμματος, σειριοποιεί τις παραμέτρους εισόδου του προγράμματος, καλεί το σημείο εισόδου του προγράμματος και αναφέρει τυχόν σφάλματα που προέκυψαν.
Για περισσότερες πληροφορίες, δείτε ανάπτυξη προγραμμάτων.
Σειριοποίηση παραμέτρων εισόδου
Οι φορτωτές SBF σειριοποιούν τις παραμέτρους εισόδου του προγράμματος σε έναν πίνακα byte που στη συνέχεια περνάει στο σημείο εισόδου του προγράμματος, όπου το πρόγραμμα είναι υπεύθυνο για την αποσειριοποίησή του στην αλυσίδα. Μία από τις αλλαγές μεταξύ του παλαιού φορτωτή και του τρέχοντος φορτωτή είναι ότι οι παράμετροι εισόδου σειριοποιούνται με τέτοιο τρόπο ώστε οι διάφορες παράμετροι να βρίσκονται σε ευθυγραμμισμένες θέσεις μέσα στον ευθυγραμμισμένο πίνακα byte. Αυτό επιτρέπει στις υλοποιήσεις αποσειριοποίησης να αναφέρονται απευθείας στον πίνακα byte και να παρέχουν ευθυγραμμισμένους δείκτες στο πρόγραμμα.
Ο τελευταίος φορτωτής σειριοποιεί τις παραμέτρους εισόδου του προγράμματος ως εξής (όλη η κωδικοποίηση είναι little endian):
- 8 bytes μη προσημασμένος αριθμός λογαριασμών
- Για κάθε λογαριασμό
- 1 byte που υποδεικνύει αν πρόκειται για διπλότυπο λογαριασμό, αν δεν είναι διπλότυπο τότε η τιμή είναι 0xff, διαφορετικά η τιμή είναι ο δείκτης του λογαριασμού του οποίου είναι διπλότυπο.
- Αν είναι διπλότυπο: 7 bytes γέμισμα
- Αν δεν είναι διπλότυπο:
- 1 byte boolean, true αν ο λογαριασμός είναι υπογράφων
- 1 byte boolean, true αν ο λογαριασμός είναι εγγράψιμος
- 1 byte boolean, true αν ο λογαριασμός είναι εκτελέσιμος
- 4 bytes γέμισμα
- 32 bytes του δημόσιου κλειδιού του λογαριασμού
- 32 bytes του δημόσιου κλειδιού του ιδιοκτήτη του λογαριασμού
- 8 bytes μη προσημασμένος αριθμός των lamport που ανήκουν στον λογαριασμό
- 8 bytes μη προσημασμένος αριθμός των bytes δεδομένων του λογαριασμού
- x bytes δεδομένων λογαριασμού
- 10k bytes γέμισμα, χρησιμοποιείται για realloc
- αρκετό γέμισμα για να ευθυγραμμιστεί η μετατόπιση σε 8 bytes.
- 8 bytes εποχή rent
- 8 bytes μη προσημασμένος αριθμός δεδομένων εντολής
- x bytes δεδομένων εντολής
- 32 bytes του αναγνωριστικού προγράμματος
Is this page helpful?