Trên Solana, hợp đồng thông minh được gọi là chương trình. Chương trình là một tài khoản không trạng thái chứa mã thực thi. Mã này được tổ chức thành các hàm gọi là lệnh. Người dùng tương tác với chương trình bằng cách gửi một giao dịch chứa một hoặc nhiều lệnh. Một giao dịch có thể bao gồm các lệnh từ nhiều chương trình.
Khi một chương trình được triển khai, Solana sử dụng LLVM để biên dịch nó thành định dạng thực thi và liên kết được (ELF). Tệp ELF chứa mã nhị phân của chương trình ở định dạng Solana Bytecode Format (sBPF) và được lưu trên chuỗi trong một tài khoản thực thi.
sBPF là phiên bản tùy chỉnh của Solana cho bytecode eBPF.
Viết chương trình
Phần lớn các chương trình được viết bằng Rust, với hai cách tiếp cận phát triển phổ biến:
- Anchor: Anchor là một framework được thiết kế cho việc phát triển Solana nhanh chóng và dễ dàng. Nó sử dụng Rust macros để giảm mã boilerplate—rất phù hợp cho người mới bắt đầu.
- Native Rust: Viết chương trình bằng Rust mà không tận dụng bất kỳ framework nào. Cách tiếp cận này cung cấp nhiều tính linh hoạt hơn nhưng đi kèm với độ phức tạp tăng lên.
Cập nhật chương trình
Để
sửa đổi
một chương trình hiện có, một tài khoản phải được chỉ định là
quyền nâng cấp.
(Thường là cùng tài khoản đã triển khai chương trình
ban đầu.) Nếu quyền nâng cấp bị thu hồi và đặt thành None, chương trình không
thể được cập nhật nữa.
Xác minh chương trình
Solana hỗ trợ bản build có thể xác minh, cho phép người dùng kiểm tra xem mã trên chuỗi của chương trình có khớp với mã nguồn công khai của nó hay không. Framework Anchor cung cấp hỗ trợ tích hợp để tạo bản build có thể xác minh.
Để kiểm tra xem một chương trình hiện có đã được xác minh hay chưa, hãy tìm kiếm ID chương trình của nó trên Solana Explorer. Ngoài ra, bạn có thể sử dụng Solana Verifiable Build CLI của Ellipsis Labs để xác minh độc lập các chương trình on-chain.
Các chương trình tích hợp sẵn
System Program
System Program là tài khoản duy nhất có thể tạo các tài khoản mới. Theo mặc định, tất cả các tài khoản mới đều thuộc sở hữu của System Program, mặc dù nhiều tài khoản được chỉ định cho chủ sở hữu mới ngay khi tạo. System Program thực hiện các chức năng chính sau:
| Chức năng | Mô tả |
|---|---|
| Tạo tài khoản mới | Chỉ System Program mới có thể tạo các tài khoản mới. |
| Phân bổ không gian | Thiết lập dung lượng byte cho trường dữ liệu của mỗi tài khoản. |
| Chỉ định quyền sở hữu chương trình | Sau khi System Program tạo một tài khoản, nó có thể chỉ định lại chủ sở hữu chương trình được chỉ định cho một program account khác. Đó là cách các chương trình tùy chỉnh tiếp quản quyền sở hữu các tài khoản mới được tạo bởi System Program. |
| Chuyển SOL | Chuyển lamports (SOL) từ các tài khoản hệ thống sang các tài khoản khác. |
Địa chỉ của system program là 11111111111111111111111111111111.
Các chương trình loader
Mỗi chương trình đều thuộc sở hữu của một chương trình khác—loader của nó. Loader được sử dụng để triển khai, triển khai lại, nâng cấp hoặc đóng các chương trình. Chúng cũng được sử dụng để hoàn thiện một chương trình và chuyển quyền quản lý chương trình.
Hiện tại có năm chương trình loader, như được hiển thị trong bảng dưới đây.
| Loader | ID chương trình | Ghi chú | Liên kết hướng dẫn |
|---|---|---|---|
| native | NativeLoader1111111111111111111111111111111 | Sở hữu bốn loader còn lại | — |
| v1 | BPFLoader1111111111111111111111111111111111 | Các lệnh quản lý bị vô hiệu hóa, nhưng các chương trình vẫn thực thi | — |
| v2 | BPFLoader2111111111111111111111111111111111 | Các lệnh quản lý bị vô hiệu hóa, nhưng các chương trình vẫn thực thi | Hướng dẫn |
| v3 | BPFLoaderUpgradeab1e11111111111111111111111 | Các chương trình có thể được cập nhật sau khi triển khai. Tệp thực thi chương trình được lưu trữ trong một program data account riêng biệt | Hướng dẫn |
| v4 | LoaderV411111111111111111111111111111111111 | Đang phát triển (chưa phát hành) | Hướng dẫn |
Các chương trình được triển khai với loader-v3 hoặc loader-v4 có thể được sửa đổi sau khi triển khai, tùy thuộc vào quyền nâng cấp của chúng.
Khi một chương trình mới được triển khai, phiên bản loader mới nhất sẽ được sử dụng theo mặc định.
Chương trình biên dịch sẵn
Ngoài các chương trình loader, Solana cung cấp các chương trình biên dịch sẵn sau đây.
Xác minh chữ ký ed25519
Chương trình ed25519 được sử dụng để xác minh một hoặc nhiều chữ ký ed25519.
| Chương trình | ID Chương trình | Mô tả | Hướng dẫn |
|---|---|---|---|
| Chương trình Ed25519 | Ed25519SigVerify111111111111111111111111111 | Xác minh chữ ký ed25519. Nếu bất kỳ chữ ký nào thất bại, lỗi sẽ được trả về. | Hướng dẫn |
Chương trình ed25519 xử lý một lệnh. u8 đầu tiên của lệnh chứa số lượng chữ ký
cần kiểm tra, theo sau là một byte đệm. Sau đó, cấu trúc sau đây được tuần tự
hóa, một lần cho mỗi chữ ký cần kiểm tra.
struct Ed25519SignatureOffsets {signature_offset: u16, // offset to ed25519 signature of 64 bytessignature_instruction_index: u16, // instruction index to find signaturepublic_key_offset: u16, // offset to public key of 32 bytespublic_key_instruction_index: u16, // instruction index to find public keymessage_data_offset: u16, // offset to start of message datamessage_data_size: u16, // size of message datamessage_instruction_index: u16, // index of instruction data to get message data}
process_instruction() {for i in 0..count {// i'th index values referenced:instructions = &transaction.message().instructionsinstruction_index = ed25519_signature_instruction_index != u16::MAX ? ed25519_signature_instruction_index : current_instruction;signature = instructions[instruction_index].data[ed25519_signature_offset..ed25519_signature_offset + 64]instruction_index = ed25519_pubkey_instruction_index != u16::MAX ? ed25519_pubkey_instruction_index : current_instruction;pubkey = instructions[instruction_index].data[ed25519_pubkey_offset..ed25519_pubkey_offset + 32]instruction_index = ed25519_message_instruction_index != u16::MAX ? ed25519_message_instruction_index : current_instruction;message = instructions[instruction_index].data[ed25519_message_data_offset..ed25519_message_data_offset + ed25519_message_data_size]if pubkey.verify(signature, message) != Success {return Error}}return Success}
Xác minh khôi phục secp256k1
Chương trình secp256k1 được sử dụng để xác minh các thao tác khôi phục khóa công khai secp256k1.
| Chương trình | ID Chương trình | Mô tả | Hướng dẫn |
|---|---|---|---|
| Chương trình Secp256k1 | KeccakSecp256k11111111111111111111111111111 | Xác minh các thao tác khôi phục khóa công khai secp256k1 (ecrecover). | Hướng dẫn |
Chương trình secp256k1 xử lý một lệnh. Byte đầu tiên của lệnh chứa số lượng khóa công khai cần kiểm tra. Sau đó, cấu trúc sau đây được tạo một lần cho mỗi khóa công khai, sau đó được tuần tự hóa và thêm vào dữ liệu lệnh.
struct Secp256k1SignatureOffsets {secp_signature_offset: u16, // offset to [signature,recovery_id] of 64+1 bytessecp_signature_instruction_index: u8, // instruction index to find signaturesecp_pubkey_offset: u16, // offset to ethereum_address pubkey of 20 bytessecp_pubkey_instruction_index: u8, // instruction index to find pubkeysecp_message_data_offset: u16, // offset to start of message datasecp_message_data_size: u16, // size of message datasecp_message_instruction_index: u8, // instruction index to find message data}
process_instruction() {for i in 0..count {// i'th index values referenced:instructions = &transaction.message().instructionssignature = instructions[secp_signature_instruction_index].data[secp_signature_offset..secp_signature_offset + 64]recovery_id = instructions[secp_signature_instruction_index].data[secp_signature_offset + 64]ref_eth_pubkey = instructions[secp_pubkey_instruction_index].data[secp_pubkey_offset..secp_pubkey_offset + 20]message_hash = keccak256(instructions[secp_message_instruction_index].data[secp_message_data_offset..secp_message_data_offset + secp_message_data_size])pubkey = ecrecover(signature, recovery_id, message_hash)eth_pubkey = keccak256(pubkey[1..])[12..]if eth_pubkey != ref_eth_pubkey {return Error}}return Success}
Điều này cho phép người dùng chỉ định bất kỳ dữ liệu lệnh nào trong giao dịch cho dữ liệu chữ ký và tin nhắn. Bằng cách chỉ định một sysvar hướng dẫn đặc biệt, người dùng cũng có thể nhận dữ liệu từ chính giao dịch.
Chi phí của giao dịch sẽ tính số lượng chữ ký cần xác minh nhân với hệ số nhân chi phí xác minh chữ ký.
Chương trình secp256r1 được sử dụng để xác minh tối đa 8 chữ ký secp256r1.
| Chương trình | ID Chương trình | Mô tả | Hướng dẫn |
|---|---|---|---|
| Chương trình Secp256r1 | Secp256r1SigVerify1111111111111111111111111 | Xác minh tối đa 8 chữ ký secp256r1. Nhận chữ ký, khóa công khai và thông điệp. Trả về lỗi nếu bất kỳ chữ ký nào thất bại. | Hướng dẫn |
Chương trình secp256r1 xử lý một lệnh. u8 đầu tiên của lệnh là số lượng chữ ký
cần kiểm tra, theo sau là một byte đệm. Sau đó, cấu trúc sau đây được tạo cho
mỗi chữ ký, sau đó được tuần tự hóa và thêm vào dữ liệu lệnh.
struct Secp256r1SignatureOffsets {signature_offset: u16, // offset to compact secp256r1 signature of 64 bytessignature_instruction_index: u16, // instruction index to find signaturepublic_key_offset: u16, // offset to compressed public key of 33 bytespublic_key_instruction_index: u16, // instruction index to find public keymessage_data_offset: u16, // offset to start of message datamessage_data_size: u16, // size of message datamessage_instruction_index: u16, // index of instruction data to get message data}
Giá trị S thấp được áp dụng cho tất cả các chữ ký để tránh tính dễ thay đổi chữ ký ngẫu nhiên.
process_instruction() {if data.len() < SIGNATURE_OFFSETS_START {return Error}num_signatures = data[0] as usizeif num_signatures == 0 || num_signatures > 8 {return Error}expected_data_size = num_signatures * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_STARTif data.len() < expected_data_size {return Error}for i in 0..num_signatures {offsets = parse_signature_offsets(data, i)signature = get_data_slice(data, instruction_datas, offsets.signature_instruction_index, offsets.signature_offset, SIGNATURE_SERIALIZED_SIZE)if s > half_curve_order {return Error}pubkey = get_data_slice(data, instruction_datas, offsets.public_key_instruction_index, offsets.public_key_offset, COMPRESSED_PUBKEY_SERIALIZED_SIZE)message = get_data_slice(data, instruction_datas, offsets.message_instruction_index, offsets.message_data_offset, offsets.message_data_size)if !verify_signature(signature, pubkey, message) {return Error}}return Success}
Các chương trình cốt lõi
Các chương trình trong danh sách dưới đây cung cấp chức năng cốt lõi của mạng.
| Chương trình | ID Chương trình | Mô tả | Hướng dẫn |
|---|---|---|---|
| System | 11111111111111111111111111111111 | Tạo tài khoản mới, phân bổ dữ liệu tài khoản, gán tài khoản cho các chương trình sở hữu, chuyển lamport từ các tài khoản thuộc sở hữu của System Program và thanh toán phí giao dịch | SystemInstruction |
| Vote | Vote111111111111111111111111111111111111111 | Tạo và quản lý các tài khoản theo dõi trạng thái bỏ phiếu và phần thưởng của validator | VoteInstruction |
| Stake | Stake11111111111111111111111111111111111111 | Tạo và quản lý các tài khoản đại diện cho stake và phần thưởng cho các ủy quyền cho validator | StakeInstruction |
| Config | Config1111111111111111111111111111111111111 | Thêm dữ liệu cấu hình vào chuỗi, theo sau là danh sách các khóa công khai được phép sửa đổi nó. Không giống như các chương trình khác, chương trình Config không định nghĩa bất kỳ lệnh riêng lẻ nào. Nó chỉ có một lệnh ngầm định: "store". Dữ liệu lệnh của nó là một tập hợp các khóa kiểm soát quyền truy cập vào tài khoản và dữ liệu được lưu trữ bên trong nó | ConfigInstruction |
| Compute Budget | ComputeBudget111111111111111111111111111111 | Đặt giới hạn và giá đơn vị tính toán cho các giao dịch, cho phép người dùng kiểm soát tài nguyên tính toán và phí ưu tiên | ComputeBudgetInstruction |
| Address Lookup Table | AddressLookupTab1e1111111111111111111111111 | Quản lý các bảng tra cứu địa chỉ, cho phép các giao dịch tham chiếu nhiều tài khoản hơn so với số lượng có thể chứa trong danh sách tài khoản của giao dịch | ProgramInstruction |
| ZK ElGamal Proof | ZkE1Gama1Proof11111111111111111111111111111 | Cung cấp xác minh bằng chứng không-tri-thức cho dữ liệu được mã hóa ElGamal | — |
Is this page helpful?