Τεκμηρίωση SolanaΑνάπτυξη προγραμμάτων

Συχνές Ερωτήσεις

Υποβάλετε τις ερωτήσεις σας στο 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?

Πίνακας Περιεχομένων

Επεξεργασία Σελίδας