Tóm tắt
Mỗi CPI tốn ~1.000 CU cơ bản cộng với chi phí serialization. Dữ liệu tài khoản được đồng bộ trước và sau khi thực thi callee. Ký PDA sử dụng program ID của caller. Dữ liệu trả về giới hạn ở 1.024 byte.
Mô hình chi phí CPI
Chi phí CPI được trừ từ cùng một ngân sách tính toán giao dịch (đồng hồ đo
chung). Công thức chi phí đầy đủ cho mỗi lần gọi 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
Phân tích chi phí
| Thành phần chi phí | Công thức | Nguồn |
|---|---|---|
| Invocation (cố định) | invoke_units = 1.000 CU (946 với SIMD-0339) | Tính phí tại điểm vào CPI |
| Serialization instruction data | instruction_data_len / cpi_bytes_per_unit | cpi_bytes_per_unit = 250. Tính phí trong translate_instruction. |
| Serialization account meta (SIMD-0339) | (num_account_metas * 34) / cpi_bytes_per_unit | Mỗi AccountMeta là 34 byte (32 pubkey + 1 is_signer + 1 is_writable). Tính phí trong translate_instruction. |
| Translation account info (SIMD-0339) | (num_account_infos * 80) / cpi_bytes_per_unit | ACCOUNT_INFO_BYTE_SIZE = 80 byte (32 key + 32 owner + 8 lamports + 8 data_len). Tính phí trong translate_account_infos. |
| Dữ liệu theo từng tài khoản | account_data_len / cpi_bytes_per_unit | Tính phí cho mỗi tài khoản trong CallerAccount::from_account_info và cho tài khoản executable. |
| Thực thi callee | Bất kỳ CU nào mà chương trình callee tiêu thụ | Trừ từ đồng hồ đo chung trong quá trình thực thi callee. |
Ví dụ tính toán chi phí
Một CPI với 100 byte instruction data, 5 account meta, 5 account info (mỗi cái có 1.000 byte dữ liệu), SIMD-0339 đang hoạt động:
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
Đồng bộ hóa dữ liệu tài khoản
Trạng thái tài khoản được đồng bộ hóa giữa caller và callee tại hai thời điểm trong quá trình CPI. Điều này đảm bảo cả hai bên đều thấy một cái nhìn nhất quán về dữ liệu tài khoản.
Đồng bộ trước CPI (caller sang callee)
Trước khi callee thực thi,
update_callee_account
sao chép các thay đổi đang diễn ra của caller sang chế độ xem tài khoản của
callee:
| Trường | Hướng | Khi nào |
|---|---|---|
| Lamports | Caller -> Callee | Nếu giá trị khác với chế độ xem hiện tại của callee |
| Độ dài data | Caller -> Callee | Nếu caller đã thay đổi kích thước tài khoản. Không được vượt quá original_data_len + MAX_PERMITTED_DATA_INCREASE (10 KiB). |
| Nội dung data | Caller -> Callee | Nếu data của tài khoản có thể sửa đổi (can_data_be_changed thành công) |
| Owner | Caller -> Callee | Được đặt cuối cùng, để các thay đổi data/lamport được phép dưới owner cũ |
Đồng bộ sau CPI (callee sang caller)
Sau khi callee trả về,
update_caller_account
sao chép các thay đổi của callee trở lại chế độ xem của caller. Điều này chỉ
chạy cho các tài khoản được đánh dấu là writable:
| Trường | Hướng | Khi nào |
|---|---|---|
| Lamports | Callee -> Caller | Luôn được sao chép lại |
| Owner | Callee -> Caller | Luôn được sao chép lại |
| Độ dài data | Callee -> Caller | Nếu có thay đổi. Con trỏ data slice của VM và trường độ dài serialized được cập nhật. Nếu tài khoản bị thu nhỏ, bộ nhớ được giải phóng sẽ được đặt về zero. Nếu độ dài mới vượt quá original_data_len + MAX_PERMITTED_DATA_INCREASE, trả về InvalidRealloc. |
| Nội dung data | Callee -> Caller | Được sao chép từ data buffer của callee sang vùng data serialized của caller |
Giới hạn realloc
Dữ liệu tài khoản có thể được thay đổi kích thước trong CPI lên đến
MAX_PERMITTED_DATA_INCREASE
= 10.240 byte (10 KiB) vượt quá độ dài dữ liệu của tài khoản tại thời điểm bắt
đầu lệnh cấp cao nhất hiện tại. Giới hạn này được thực thi trong cả
update_callee_account
(trước CPI) và
update_caller_account
(sau CPI). Vượt quá giới hạn này sẽ trả về InvalidRealloc.
Ký PDA
Khi invoke_signed được gọi, runtime sẽ suy ra địa chỉ PDA từ các seed được
cung cấp và program ID của caller. Điều này xảy ra trong
translate_signers_rust:
- Mảng signer seed được xác thực: tối đa
MAX_SIGNERS(16) bộ signer seed. - Mỗi bộ seed được xác thực: tối đa
MAX_SEEDS(16) seed trên mỗi bộ, mỗi seed tối đaMAX_SEED_LEN(32) byte. Pubkey::create_program_addressđược gọi với các seed và program ID của caller (không phải của callee).- Nếu các seed không tạo ra PDA hợp lệ (tức là điểm kết quả nằm trên đường cong
ed25519), CPI sẽ thất bại với
BadSeeds. - Các pubkey PDA được suy ra sẽ được thu thập và truyền đến
prepare_next_instructionnhư các signer hợp lệ. Trong quá trình kiểm tra đặc quyền, nếu một tài khoản callee được đánh dấu là signer và pubkey của nó khớp với một trong các PDA được suy ra này, kiểm tra signer sẽ thành công.
PDA được suy ra bằng program ID của caller, không phải của callee. Điều này có nghĩa là chỉ chương trình sở hữu PDA (chương trình có ID được sử dụng để suy ra nó) mới có thể ký thay mặt cho nó. Một chương trình không thể ký cho các PDA được suy ra từ các chương trình khác.
Dữ liệu trả về
Các chương trình có thể truyền dữ liệu trả lại cho caller bằng cách sử dụng cơ chế return data. Điều này sử dụng hai syscall:
sol_set_return_data: Thiết lập tối đaMAX_RETURN_DATA(1.024) byte dữ liệu trả về cho lệnh hiện tại. Chi phí làdata_len / cpi_bytes_per_unit + syscall_base_costCU.sol_get_return_data: Đọc dữ liệu trả về được thiết lập bởi lệnh được thực thi gần đây nhất. Trả về dữ liệu cùng với program ID đã thiết lập nó. Chi phí là(data_len + 32) / cpi_bytes_per_unit + syscall_base_costCU (32 byte cho program ID).
Dữ liệu trả về được lưu trữ theo từng giao dịch và bị ghi đè bởi mỗi lệnh gọi
sol_set_return_data. Khi bắt đầu mỗi lần gọi chương trình, runtime
đặt lại dữ liệu trả về
thành rỗng. Sau khi CPI trả về, bên gọi có thể đọc bất kỳ dữ liệu trả về nào mà
bên được gọi (hoặc bất kỳ chương trình nào mà bên được gọi đã gọi) đặt cuối
cùng.
Dữ liệu trả về bị giới hạn ở 1.024 byte. Chỉ chương trình cuối cùng gọi
sol_set_return_data trong chuỗi gọi mới quyết định những gì bên gọi nhìn
thấy. Nếu bên được gọi thực hiện thêm các CPI đặt dữ liệu trả về, dữ liệu trả
về của chính bên được gọi sẽ bị ghi đè.
Is this page helpful?