Περίληψη
Κάθε 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 data | instruction_data_len / cpi_bytes_per_unit | cpi_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_unit | ACCOUNT_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 = 946instruction_data_cost = 100 / 250 = 0 (integer division)account_meta_cost = (5 * 34) / 250 = 0account_info_cost = (5 * 80) / 250 = 1per_account_data_cost = 5 * (1000 / 250) = 20total (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:
- Ο πίνακας signer seeds επικυρώνεται: το πολύ
MAX_SIGNERS(16) σύνολα signer seed. - Κάθε σύνολο seed επικυρώνεται: το πολύ
MAX_SEEDS(16) seeds ανά σύνολο, κάθε seed το πολύMAX_SEED_LEN(32) bytes. - Καλείται το
Pubkey::create_program_addressμε τα seeds και το program ID του καλούντος (όχι του καλούμενου). - Εάν τα seeds δεν παράγουν έγκυρο PDA (δηλαδή, το προκύπτον σημείο βρίσκεται
στην καμπύλη ed25519), το CPI αποτυγχάνει με
BadSeeds. - Τα παραγόμενα 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_costCUs.sol_get_return_data: Διαβάζει τα δεδομένα επιστροφής που ορίστηκαν από την πιο πρόσφατα εκτελεσμένη εντολή. Επιστρέφει τα δεδομένα μαζί με το program ID που τα όρισε. Το κόστος είναι(data_len + 32) / cpi_bytes_per_unit + syscall_base_costCUs (32 bytes για το program ID).
Τα δεδομένα επιστροφής αποθηκεύονται ανά συναλλαγή και αντικαθίστανται από κάθε
εντολή που καλεί το sol_set_return_data. Στην αρχή κάθε κλήσης προγράμματος,
το runtime
επαναφέρει τα δεδομένα επιστροφής
σε κενά. Αφού επιστρέψει ένα CPI, ο καλών μπορεί να διαβάσει όποια δεδομένα
επιστροφής όρισε τελευταίος ο καλούμενος (ή οποιοδήποτε πρόγραμμα κάλεσε ο
καλούμενος).
Τα δεδομένα επιστροφής περιορίζονται σε 1.024 bytes. Μόνο το τελευταίο
πρόγραμμα που καλεί το sol_set_return_data στην αλυσίδα κλήσεων καθορίζει τι
βλέπει ο καλών. Εάν ένας καλούμενος πραγματοποιήσει περαιτέρω CPIs που ορίζουν
δεδομένα επιστροφής, τα δικά του δεδομένα επιστροφής αντικαθίστανται.
Is this page helpful?