Μοντέλο κόστους CPI και συγχρονισμός δεδομένων

Περίληψη

Κάθε CPI κοστίζει ~1.000 CUs βάσης συν κόστη σειριοποίησης. Τα δεδομένα λογαριασμού συγχρονίζονται πριν και μετά την εκτέλεση του καλούμενου. Η υπογραφή PDA χρησιμοποιεί το program ID του καλούντος. Τα δεδομένα επιστροφής περιορίζονται σε 1.024 bytes.

Μοντέλο κόστους CPI

Τα κόστη CPI αντλούνται από τον ίδιο προϋπολογισμό υπολογισμού συναλλαγής (κοινό μετρητή). Ο πλήρης τύπος κόστους για κάθε κλήση invoke / invoke_signed:

total_cpi_cost = invocation_cost
+ instruction_data_cost
+ account_meta_cost (SIMD-0339 only)
+ account_info_cost (SIMD-0339 only)
+ per_account_data_cost (for each non-executable account)
+ callee_execution_cost

Ανάλυση κόστους

Συστατικό κόστουςΤύποςΠηγή
Κλήση (σταθερό)invoke_units = 1.000 CUs (946 με SIMD-0339)Χρεώνεται στην είσοδο CPI
Σειριοποίηση instruction datainstruction_data_len / cpi_bytes_per_unitcpi_bytes_per_unit = 250. Χρεώνεται στο translate_instruction.
Σειριοποίηση account meta (SIMD-0339)(num_account_metas * 34) / cpi_bytes_per_unitΚάθε AccountMeta είναι 34 bytes (32 pubkey + 1 is_signer + 1 is_writable). Χρεώνεται στο translate_instruction.
Μετάφραση account info (SIMD-0339)(num_account_infos * 80) / cpi_bytes_per_unitACCOUNT_INFO_BYTE_SIZE = 80 bytes (32 key + 32 owner + 8 lamports + 8 data_len). Χρεώνεται στο translate_account_infos.
Δεδομένα ανά λογαριασμόaccount_data_len / cpi_bytes_per_unitΧρεώνεται ανά λογαριασμό στο CallerAccount::from_account_info και για εκτελέσιμους λογαριασμούς.
Εκτέλεση καλούμενουΌποια CUs καταναλώνει το πρόγραμμα του καλούμενουΑφαιρείται από τον κοινό μετρητή κατά την εκτέλεση του καλούμενου.

Παράδειγμα υπολογισμού κόστους

Ένα CPI με 100 bytes instruction data, 5 account metas, 5 account infos (το καθένα με 1.000 bytes δεδομένων), με ενεργό το SIMD-0339:

invocation_cost = 946
instruction_data_cost = 100 / 250 = 0 (integer division)
account_meta_cost = (5 * 34) / 250 = 0
account_info_cost = (5 * 80) / 250 = 1
per_account_data_cost = 5 * (1000 / 250) = 20
total (before callee) = 967 CUs

Συγχρονισμός δεδομένων λογαριασμού

Η κατάσταση του λογαριασμού συγχρονίζεται μεταξύ του καλούντος και του καλούμενου σε δύο σημεία κατά τη διάρκεια ενός CPI. Αυτό διασφαλίζει ότι και οι δύο πλευρές βλέπουν μια συνεπή προβολή των δεδομένων του λογαριασμού.

Συγχρονισμός πριν το CPI (από τον καλούντα στον καλούμενο)

Πριν εκτελεστεί ο καλούμενος, η update_callee_account αντιγράφει τις τρέχουσες τροποποιήσεις του καλούντος στην προβολή λογαριασμού του καλούμενου:

ΠεδίοΚατεύθυνσηΠότε
LamportsΚαλών -> ΚαλούμενοςΕάν η τιμή διαφέρει από την τρέχουσα προβολή του καλούμενου
Μήκος δεδομένωνΚαλών -> ΚαλούμενοςΕάν ο καλών έχει αλλάξει το μέγεθος του λογαριασμού. Δεν πρέπει να υπερβαίνει το original_data_len + MAX_PERMITTED_DATA_INCREASE (10 KiB).
Περιεχόμενο δεδομένωνΚαλών -> ΚαλούμενοςΕάν τα δεδομένα του λογαριασμού είναι τροποποιήσιμα (το can_data_be_changed επιτυγχάνει)
ΚάτοχοςΚαλών -> ΚαλούμενοςΟρίζεται τελευταίο, ώστε οι αλλαγές δεδομένων/lamport να επιτρέπονται υπό τον παλιό κάτοχο

Συγχρονισμός μετά το CPI (από τον καλούμενο στον καλούντα)

Αφού επιστρέψει ο καλούμενος, η update_caller_account αντιγράφει τις τροποποιήσεις του καλούμενου πίσω στην προβολή του καλούντος. Αυτό εκτελείται μόνο για λογαριασμούς που έχουν επισημανθεί ως εγγράψιμοι:

ΠεδίοΚατεύθυνσηΠότε
LamportsΚαλούμενος -> ΚαλώνΑντιγράφεται πάντα πίσω
ΚάτοχοςΚαλούμενος -> ΚαλώνΑντιγράφεται πάντα πίσω
Μήκος δεδομένωνΚαλούμενος -> ΚαλώνΕάν άλλαξε. Ο δείκτης του τμήματος δεδομένων VM και το πεδίο σειριοποιημένου μήκους ενημερώνονται. Εάν ο λογαριασμός συρρικνώθηκε, η ελευθερωμένη μνήμη μηδενίζεται. Εάν το νέο μήκος υπερβαίνει το original_data_len + MAX_PERMITTED_DATA_INCREASE, επιστρέφει InvalidRealloc.
Περιεχόμενο δεδομένωνΚαλούμενος -> ΚαλώνΑντιγράφεται από το buffer δεδομένων του καλούμενου στην περιοχή σειριοποιημένων δεδομένων του καλούντος

Όρια realloc

Τα δεδομένα λογαριασμού μπορούν να αλλάξουν μέγεθος κατά τη διάρκεια CPI έως και MAX_PERMITTED_DATA_INCREASE = 10.240 bytes (10 KiB) πέρα από το μήκος δεδομένων του λογαριασμού κατά την έναρξη της τρέχουσας εντολής ανώτατου επιπέδου. Αυτός ο περιορισμός επιβάλλεται τόσο στο update_callee_account (προ-CPI) όσο και στο update_caller_account (μετά-CPI). Η υπέρβασή του επιστρέφει InvalidRealloc.

Υπογραφή PDA

Όταν καλείται το invoke_signed, το runtime παράγει διευθύνσεις PDA από τα παρεχόμενα seeds και το program ID του καλούντος. Αυτό συμβαίνει στο translate_signers_rust:

  1. Ο πίνακας signer seeds επικυρώνεται: το πολύ MAX_SIGNERS (16) σύνολα signer seed.
  2. Κάθε σύνολο seed επικυρώνεται: το πολύ MAX_SEEDS (16) seeds ανά σύνολο, κάθε seed το πολύ MAX_SEED_LEN (32) bytes.
  3. Καλείται το Pubkey::create_program_address με τα seeds και το program ID του καλούντος (όχι του καλούμενου).
  4. Εάν τα seeds δεν παράγουν έγκυρο PDA (δηλαδή, το προκύπτον σημείο βρίσκεται στην καμπύλη ed25519), το CPI αποτυγχάνει με BadSeeds.
  5. Τα παραγόμενα PDA pubkeys συλλέγονται και μεταβιβάζονται στο prepare_next_instruction ως έγκυροι υπογράφοντες. Κατά τον έλεγχο προνομίων, εάν ένας λογαριασμός καλούμενου επισημαίνεται ως υπογράφων και το pubkey του ταιριάζει με ένα από αυτά τα παραγόμενα PDAs, ο έλεγχος υπογράφοντος περνάει επιτυχώς.

Το PDA παράγεται χρησιμοποιώντας το program ID του καλούντος, όχι του καλούμενου. Αυτό σημαίνει ότι μόνο το πρόγραμμα που κατέχει το PDA (αυτό του οποίου το ID χρησιμοποιήθηκε για να το παραχθεί) μπορεί να υπογράψει εξ ονόματός του. Ένα πρόγραμμα δεν μπορεί να υπογράψει για PDAs που παράγονται από άλλα προγράμματα.

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

Τα προγράμματα μπορούν να μεταβιβάσουν δεδομένα πίσω στους καλούντες χρησιμοποιώντας τον μηχανισμό δεδομένων επιστροφής. Αυτό χρησιμοποιεί δύο syscalls:

  • sol_set_return_data: Ορίζει έως και MAX_RETURN_DATA (1.024) bytes δεδομένων επιστροφής για την τρέχουσα εντολή. Το κόστος είναι data_len / cpi_bytes_per_unit + syscall_base_cost CUs.
  • sol_get_return_data: Διαβάζει τα δεδομένα επιστροφής που ορίστηκαν από την πιο πρόσφατα εκτελεσμένη εντολή. Επιστρέφει τα δεδομένα μαζί με το program ID που τα όρισε. Το κόστος είναι (data_len + 32) / cpi_bytes_per_unit + syscall_base_cost CUs (32 bytes για το program ID).

Τα δεδομένα επιστροφής αποθηκεύονται ανά συναλλαγή και αντικαθίστανται από κάθε εντολή που καλεί το sol_set_return_data. Στην αρχή κάθε κλήσης προγράμματος, το runtime επαναφέρει τα δεδομένα επιστροφής σε κενά. Αφού επιστρέψει ένα CPI, ο καλών μπορεί να διαβάσει όποια δεδομένα επιστροφής όρισε τελευταίος ο καλούμενος (ή οποιοδήποτε πρόγραμμα κάλεσε ο καλούμενος).

Τα δεδομένα επιστροφής περιορίζονται σε 1.024 bytes. Μόνο το τελευταίο πρόγραμμα που καλεί το sol_set_return_data στην αλυσίδα κλήσεων καθορίζει τι βλέπει ο καλών. Εάν ένας καλούμενος πραγματοποιήσει περαιτέρω CPIs που ορίζουν δεδομένα επιστροφής, τα δικά του δεδομένα επιστροφής αντικαθίστανται.

Is this page helpful?

Διαχειρίζεται από

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