Thực thi chương trình

Tóm tắt

Các chương trình được biên dịch thành sBPF thông qua LLVM và chạy trong VM sandbox với ngân sách 1.4M CU cho mỗi giao dịch. Runtime lưu đệm tối đa 512 chương trình đã biên dịch, cung cấp syscalls cho logging, CPI, crypto và bộ nhớ, đồng thời trì hoãn các triển khai mới 1 slot.

Biên dịch

Solana sử dụng LLVM để biên dịch các chương trình thành các tệp nhị phân ELF chứa Solana Bytecode Format (sBPF). Tệp nhị phân ELF được lưu trữ on-chain trong một tài khoản thực thi.

sBPF là biến thể tùy chỉnh của Solana dựa trên bytecode eBPF, được điều chỉnh cho Solana runtime. Nó không phải là eBPF chuẩn và có các sửa đổi đặc thù của Solana.

Viết chương trình

Các chương trình Solana chủ yếu được viết bằng Rust sử dụng một trong hai cách tiếp cận:

Mô hình thực thi chương trình

Khi một giao dịch được xử lý, runtime thực thi từng lệnh tuần tự thông qua process_message(). Đối với mỗi lệnh, runtime:

  1. Chuẩn bị ngữ cảnh lệnh. Gọi prepare_next_top_level_instruction() để ánh xạ các chỉ số tài khoản của lệnh, đặt các cờ signer và writable, và cấu hình TransactionContext.

  2. Kiểm tra precompiles. Nếu chương trình là một precompile, runtime gọi process_precompile(), vẫn đẩy và lấy ra một stack frame (thông qua push()pop()) nhưng bỏ qua sBPF VM và tra cứu bộ nhớ đệm chương trình, thực thi mã native trực tiếp.

  3. Đẩy một stack frame. (Các bước 3-6 xảy ra bên trong InvokeContext::process_instruction()process_executable_chain(), được gọi từ process_message().) Gọi push() trên InvokeContext, điều này tăng chiều cao của instruction stack và thực thi quy tắc reentrancy: một program chỉ có thể tự gọi lại chính nó nếu caller trực tiếp (program ở đỉnh hiện tại của instruction stack) là cùng một program. Đệ quy sâu (A -> A -> A) được cho phép, tuân theo giới hạn độ sâu stack. Các pattern reentrancy khác (ví dụ: A gọi B gọi A) trả về InstructionError::ReentrancyNotAllowed.

  4. Phân giải program. Runtime gọi process_executable_chain() để xác định loader. Nếu owner của program account là native loader, program đó là builtin và hàm entrypoint của nó được tra cứu trực tiếp từ ProgramCacheForTxBatch. Nếu owner là một trong các BPF loader (bpf_loader_deprecated, bpf_loader, bpf_loader_upgradeable, hoặc loader_v4), entrypoint builtin của loader sẽ được gọi thay thế.

  5. Thực thi BPF program. Đối với các BPF program, loader entrypoint tra cứu executable đã biên dịch từ program cache. execute() sau đó:

    • Serialize dữ liệu account thành một parameter buffer phẳng
    • Tạo sBPF VM với các vùng stack, heap và memory
    • Chạy code đã biên dịch, tiêu thụ compute unit trong quá trình thực thi. Trả về ComputationalBudgetExceeded nếu vượt quá ngân sách.
    • Deserialize dữ liệu account từ buffer trở lại thành trạng thái account
  6. Loại bỏ stack frame. Gọi pop() để xác minh rằng instruction không vi phạm các quy tắc kế toán của runtime (số dư lamport cân bằng, các account readonly không bị sửa đổi, kích thước dữ liệu account nằm trong giới hạn).

  7. Tích lũy compute unit. Các compute unit được tiêu thụ bởi instruction được cộng vào tổng số của transaction thông qua saturating_add.

Bộ nhớ đệm chương trình

Runtime duy trì một ProgramCache toàn cục lưu trữ các chương trình đã được xác minh và biên dịch. Nó nhận biết fork-graph và xử lý các quy tắc hiển thị triển khai, loại bỏ và biên dịch lại tại ranh giới epoch.

Các loại mục trong bộ nhớ đệm

Mỗi chương trình được lưu trong bộ nhớ đệm có một ProgramCacheEntryType xác định hành vi runtime của nó:

LoạiMô tả
LoadedChương trình đã được xác minh và biên dịch, sẵn sàng để thực thi.
BuiltinChương trình native được biên dịch vào binary của validator (System, Stake, Vote, v.v.). Không được lưu trữ on-chain.
UnloadedChương trình đã được xác minh trước đó nhưng tệp thực thi đã biên dịch bị loại bỏ khỏi bộ nhớ để giải phóng không gian. Vẫn theo dõi thống kê sử dụng. Có thể được tải lại mà không cần xác minh lại.
FailedVerificationTombstone cho các chương trình không vượt qua trình xác minh sBPF theo tập tính năng hiện tại. Có thể trở thành Loaded nếu các kích hoạt tính năng thay đổi quy tắc xác minh.
ClosedTombstone cho các chương trình đã bị đóng rõ ràng hoặc chưa bao giờ được triển khai. Cũng được sử dụng cho các tài khoản (như tài khoản buffer) thuộc về một loader nhưng không chứa mã thực thi.
DelayVisibilityTombstone tổng hợp được trả về bởi ProgramCacheForTxBatch::find() khi một mục Loaded tồn tại nhưng chưa có hiệu lực (effective_slot của nó nằm trong tương lai). Không bao giờ được lưu trực tiếp trong bộ nhớ đệm.

Độ trễ hiển thị

Các chương trình mới được triển khai hoặc nâng cấp không có hiệu lực ngay lập tức. Hằng số DELAY_VISIBILITY_SLOT_OFFSET1, có nghĩa là một chương trình được triển khai trong slot N sẽ có hiệu lực ở slot N+1. Trong slot triển khai, bất kỳ nỗ lực nào để gọi phiên bản mới sẽ trả về DelayVisibility, khiến runtime báo cáo "Program is not deployed."

Chính sách loại bỏ

Bộ nhớ cache lưu trữ tối đa MAX_LOADED_ENTRY_COUNT (512) mục chương trình đã biên dịch. Khi đạt đến giới hạn, các chương trình ít được sử dụng nhất sẽ bị loại bỏ về trạng thái Unloaded. Mức độ sử dụng được theo dõi bởi tx_usage_counter (tăng lên mỗi khi một giao dịch tham chiếu đến chương trình) và latest_access_slot.

Biên dịch lại tại ranh giới epoch

Nếu việc kích hoạt tính năng thay đổi ProgramRuntimeEnvironments tại ranh giới epoch, tất cả các chương trình được lưu trong cache sẽ được biên dịch lại đối với môi trường mới.

Dữ liệu trả về

Các chương trình có thể thiết lập dữ liệu trả về thông qua syscall sol_set_return_data. Dữ liệu được lưu trữ trong một cấu trúc TransactionReturnData cấp độ giao dịch chứa các byte dữ liệu và program_id của chương trình có lệnh gọi syscall. Kích thước tối đa là 1.024 byte (MAX_RETURN_DATA).

Is this page helpful?

Mục lục

Chỉnh sửa trang

Quản lý bởi

© 2026 Solana Foundation.
Đã đăng ký bản quyền.
Kết nối