MỚI: Helius mua lại Light Protocol
Phân phiên bản giao dịch Solana: legacy, v0 và v1
Blog/Kiến thức nền tảng

Phân phiên bản giao dịch Solana: legacy, v0 và v1

Nhà nghiên cứuLostin trên X
Đọc trong 26 phút

Lược sử các định dạng giao dịch của Solana

Solana có ba định dạng giao dịch: legacy, v0 và v1. Xét ở cấp độ tổng quan, tất cả đều phục vụ cùng một mục đích: đóng gói chữ ký, tài khoản và chỉ thị để validator thực thi trên các chương trình onchain.

Điều thay đổi theo thời gian là định dạng truyền tải, tức cách các phần thông tin này được tuần tự hóa và truyền qua mạng.

Mỗi định dạng mới được ra mắt để khắc phục những hạn chế xuất hiện khi các ứng dụng Solana trở nên phức tạp hơn, đồng thời duy trì khả năng tương thích ngược để các định dạng cũ tiếp tục hoạt động.

Cả ba định dạng cùng tồn tại trên mạng và nhà phát triển có thể sử dụng định dạng phù hợp nhất với giao dịch họ đang xây dựng.

Giao dịch legacy

Định dạng ban đầu được gọi là legacy vì nó có trước cơ chế phân phiên bản giao dịch và không chứa mã nhận dạng phiên bản.

Kích thước tối đa 1.232 byte bắt nguồn từ thiết kế mạng ban đầu của Solana: giao dịch được định cỡ để vừa với MTU tối thiểu 1.280 byte của IPv6, còn lại 1.232 byte sau phần dữ liệu phụ trợ của mạng.

Cách này hoạt động tốt với các giao dịch nhỏ, nhưng không gian ngày càng trở nên hạn chế khi ứng dụng phát triển. Mỗi địa chỉ tài khoản được đưa trực tiếp vào giao dịch chiếm 32 byte, còn mỗi chữ ký Ed25519 chiếm thêm 64 byte.

Do đó, trên thực tế, các giao dịch có nhiều tài khoản có thể chạm giới hạn byte từ lâu trước khi đạt giới hạn khóa tài khoản của runtime.

Giao dịch v0

Nỗ lực đầu tiên nhằm giảm áp lực này là giao dịch v0, được đưa lên mainnet-beta vào tháng 10 năm 2022. Thay vì tăng giới hạn 1.232 byte, v0 giới thiệu Address Lookup Tables (ALT).

ALT lưu trữ địa chỉ tài khoản onchain, cho phép giao dịch v0 tham chiếu đến chúng bằng chỉ mục một byte thay vì lặp lại từng khóa công khai 32 byte. Nhờ đó, giao dịch có thể đạt giới hạn 64 tài khoản của runtime mà vẫn nằm trong giới hạn kích thước gói hiện có.

v0 là phần mở rộng tăng dần của định dạng legacy: nó bổ sung tiền tố phiên bản 0x80 và một phần tra cứu địa chỉ, đồng thời giữ nguyên cách mã hóa thông điệp và chỉ thị cơ bản.

Việc giới thiệu cơ chế phân phiên bản cũng thiết lập một khuôn khổ cho phép các định dạng giao dịch mới cùng tồn tại với giao dịch legacy thay vì thay thế chúng.

ALT giải quyết vấn đề trước mắt về kích thước danh sách tài khoản nhưng cũng tạo ra những phức tạp mới. Ứng dụng cần tạo và duy trì các bảng tra cứu onchain, validator phải phân giải các mục trong bảng trước khi thực thi, còn dịch vụ RPC và trình lập chỉ mục cần các địa chỉ đã phân giải để tái dựng giao dịch hoàn chỉnh.

Việc giải mã dữ liệu lịch sử cũng trở nên khó khăn hơn nhiều nếu bảng tra cứu mà giao dịch thô tham chiếu đã bị đóng. Vì vậy, v0 nén danh sách tài khoản hiệu quả nhưng phải đánh đổi bằng cách đưa một phụ thuộc onchain bên ngoài vào biểu diễn truyền tải của giao dịch.

ALT được các nhà phát triển Solana áp dụng rộng rãi. Nghiên cứu được thực hiện ngay trước khi giao dịch v1 ra mắt cho thấy khoảng 62% giao dịch v0 tham chiếu ít nhất một ALT.

Bổ sung phí ưu tiên vào thiết kế hiện có

Phí ưu tiên cũng được giới thiệu trên Solana vào năm 2022, trước khi giao dịch v0 được kích hoạt trên mainnet, dù bản thân định dạng v0 đã được thiết kế vào thời điểm đó. Thay vì thiết kế lại một trong hai định dạng giao dịch, Solana bổ sung cấu hình phí thông qua Compute Budget Program hiện có. Giao dịch có thể chứa các chỉ thị như SetComputeUnitLimit và SetComputeUnitPrice, cho phép người dùng yêu cầu ngân sách tính toán và đính kèm một khoản phí bổ sung để được ưu tiên lập lịch. Cách này hoạt động tốt như nhau cho giao dịch legacy và v0, đồng thời tránh phải có một cơ chế phí riêng cho từng định dạng.

Đây là một giải pháp thực dụng, tương thích ngược nhưng không thực sự tinh gọn. Phí ưu tiên và giới hạn tính toán về bản chất là siêu dữ liệu cấp giao dịch, nhưng legacy và v0 không có trường riêng cho chúng, nên các thiết lập này được bổ sung vào luồng chỉ thị dưới dạng lệnh gọi chương trình. Điều đó có nghĩa là giao dịch phải tham chiếu Compute Budget Program, cấu hình chiếm byte chỉ thị và validator phải kiểm tra các chỉ thị này trong quá trình tiếp nhận giao dịch để khôi phục thiết lập phí và tài nguyên.

Do đó, v0 không phải là một bản thiết kế lại toàn diện định dạng giao dịch của Solana. Mục tiêu chính là giải quyết nút thắt địa chỉ tài khoản bằng Address Lookup Tables, trong khi giữ nguyên phần lớn cấu trúc thông điệp legacy. Vì các chỉ thị Compute Budget đã cung cấp cách tương thích để hỗ trợ phí ưu tiên trên cả hai định dạng, không có nhiều lý do để mở rộng thêm phạm vi của v0.

Kích thước giao dịch lớn hơn

Theo thời gian, Solana chuyển cơ chế tiếp nhận giao dịch từ UDP sang QUIC, nơi các luồng không còn bị giới hạn trong một tải trọng duy nhất có kích thước bằng MTU. Vì vậy, mức trần 1.232 byte ban đầu không còn là yêu cầu của lớp truyền tải. Hai SIMD được đề xuất vào năm 2025 để giới thiệu định dạng v1 mới. SIMD-0296 nâng kích thước tối đa của giao dịch v1 lên 4.096 byte, xấp xỉ 3,3 lần giới hạn trước đó, trong khi SIMD-0385 định nghĩa một định dạng truyền tải hoàn toàn mới, được thiết kế dựa trên không gian bổ sung đó và khả năng tiếp nhận hiệu quả hơn cho validator.

Không gian bổ sung cho phép v1 loại bỏ hoàn toàn ALT. Giới hạn 64 tài khoản với địa chỉ 32 byte chỉ cần tối đa 2.048 byte, nên toàn bộ danh sách tài khoản có thể được đưa trực tiếp vào giao dịch.

Phân tích của Solana Foundation cho thấy tác động của việc đưa toàn bộ địa chỉ trực tiếp vào giao dịch là vừa phải khi nâng cấp phần lớn giao dịch v0 hiện có: 50% tăng dưới 420 byte và 90% tăng dưới 1.400 byte. Ngay cả các giao dịch sử dụng ALT nhiều vẫn còn dư đáng kể trong giới hạn 4.096 byte của v1.

Quan trọng hơn, v1 không chỉ đơn thuần là một giao dịch v0 lớn hơn. Nó tổ chức lại đáng kể định dạng truyền tải: chữ ký được chuyển xuống cuối, cấu hình tài nguyên được đưa ra khỏi các chỉ thị Compute Budget và chuyển vào phần cấu hình giao dịch, còn tải trọng chỉ thị có độ dài biến đổi được tách khỏi các header có độ rộng cố định. Những thay đổi này giúp validator phân tích và ưu tiên giao dịch với chi phí thấp hơn và quy trình đơn giản hơn.

Giới hạn 4.096 byte lớn hơn cũng mở ra những khối lượng công việc mà chỉ riêng việc nén địa chỉ không bao giờ có thể hỗ trợ. Bằng chứng không tiết lộ, multisig lồng nhau, chữ ký Winternitz không cắt ngắn, chữ ký BLS và các phép toán mật mã khác có thể cần hàng trăm hoặc hàng nghìn byte dữ liệu chỉ thị. Ví dụ, Số dư bảo mật Token-2022 giờ đây có thể được xây dựng thành một giao dịch v1 nguyên tử duy nhất thay vì chia thành nhiều giao dịch.

Đáng chú ý, định dạng v1 ban đầu không nâng các giới hạn về tính toán, chữ ký, số lượng chỉ thị hay 64 tài khoản của Solana; mục tiêu chính là loại bỏ nút thắt kích thước và thiết kế lại cách biểu diễn giao dịch khi truyền qua mạng.

SIMD-0596 do Anza đề xuất sẽ nâng giới hạn khóa tài khoản của v1 từ 64 lên 96, bao gồm mọi tài khoản được giao dịch tham chiếu, như người ký, ID chương trình cùng các tài khoản có thể ghi và chỉ đọc. Tại thời điểm viết bài, đề xuất này vẫn đang được xem xét. Giao dịch legacy và v0 sẽ tiếp tục bị giới hạn ở 64.

Đặc tả và so sánh định dạng

Giới hạnLegacyv0v1
Kích thước tối đa1.232 byte1.232 byte4.096 byte
Địa chỉ tài khoản~32, bị giới hạn bởi kích thước64, qua bảng tra cứu64, trực tiếp
Bảng tra cứu địa chỉKhông hỗ trợCó hỗ trợKhông hỗ trợ
Địa chỉ trùng lặpđược phépđược phépbị từ chối
Tiền tốKhông có0x800x81
Phí ưu tiênChỉ thị SetComputeUnitPrice, micro-lamport trên mỗi CUChỉ thị SetComputeUnitPrice, micro-lamport trên mỗi CUconfig.priorityFeeLamports, tổng số lamport
Giới hạn đơn vị tính toánChỉ thị SetComputeUnitLimitChỉ thị SetComputeUnitLimitconfig.computeUnitLimit
Kích thước heapChỉ thị RequestHeapFrameChỉ thị RequestHeapFrameconfig.heapSize
Giới hạn tài khoản được nạpChỉ thị SetLoadedAccountsDataSizeLimitChỉ thị SetLoadedAccountsDataSizeLimitconfig.loadedAccountsDataSizeLimit

Đặc tả giao dịch legacy

Một giao dịch legacy đã tuần tự hóa bắt đầu bằng số lượng chữ ký compact-u16, tiếp theo là các chữ ký Ed25519 dài 64 byte.

Thông điệp nằm ngay sau đó và chứa header ba byte, danh sách tài khoản có tiền tố độ dài compact, recent blockhash 32 byte và mảng chỉ thị đã biên dịch có tiền tố độ dài compact.

Giao dịch legacy không có tiền tố phiên bản.

Mã
NumSignatures (compact-u16)

Signatures [[u8; 64]]
  -- Length = NumSignatures

MessageHeader (u8, u8, u8)
  -- (NumRequiredSignatures,
      NumReadonlySignedAccounts,
      NumReadonlyUnsignedAccounts)

NumAccountKeys (compact-u16)

AccountKeys [[u8; 32]]
  -- Length = NumAccountKeys

RecentBlockhash [u8; 32]

NumInstructions (compact-u16)

Instructions [CompiledInstruction]
  -- Length = NumInstructions

CompiledInstruction:
  ProgramIdIndex (u8)

  NumInstructionAccounts (compact-u16)

  InstructionAccountIndexes [u8]
    -- Length = NumInstructionAccounts

  InstructionDataLength (compact-u16)

  InstructionData [u8]
    -- Length = InstructionDataLength

Một đặc điểm quan trọng là mỗi CompiledInstruction được tuần tự hóa đầy đủ trước khi chỉ thị tiếp theo bắt đầu.

Các mảng chỉ mục tài khoản và dữ liệu có độ dài biến đổi, với tiền tố compact-u16 xác định kích thước của chúng.

Đặc tả giao dịch v0

Giao dịch v0 giữ lại gần như toàn bộ định dạng truyền tải legacy. Giao dịch vẫn bắt đầu bằng số lượng chữ ký và các chữ ký, nhưng thông điệp bắt đầu bằng tiền tố phiên bản 0x80.

Sau đó, thông điệp sử dụng cùng header ba byte, danh sách tài khoản tĩnh, blockhash và định dạng chỉ thị đã biên dịch như legacy, rồi mới nối thêm phần Address Lookup Table.

Đây là cơ chế cho phép giao dịch v0 nạp thêm tài khoản thông qua ALT mà vẫn nằm trong giới hạn giao dịch 1.232 byte.

Mã
NumSignatures (compact-u16)

Signatures [[u8; 64]]
  -- Length = NumSignatures

VersionByte (u8)
  -- 0x80

MessageHeader (u8, u8, u8)

NumStaticAccountKeys (compact-u16)

StaticAccountKeys [[u8; 32]]
  -- Length = NumStaticAccountKeys

RecentBlockhash [u8; 32]

NumInstructions (compact-u16)

Instructions [CompiledInstruction]
  -- Same encoding as legacy

NumAddressTableLookups (compact-u16)

AddressTableLookups [MessageAddressTableLookup]
  -- Length = NumAddressTableLookups

MessageAddressTableLookup:
  AccountKey [u8; 32]
    -- Address of the lookup table account

  NumWritableIndexes (compact-u16)

  WritableIndexes [u8]
    -- Indices into the lookup table

  NumReadonlyIndexes (compact-u16)

  ReadonlyIndexes [u8]
    -- Indices into the lookup table

Sự khác biệt giữa khóa tài khoản tĩnh và địa chỉ đã nạp rất quan trọng. Chỉ các khóa tĩnh được tuần tự hóa trực tiếp vào thông điệp; các địa chỉ được tham chiếu qua ALT sẽ được phân giải trong runtime và nối vào danh sách tài khoản hiệu dụng.

Với một giao dịch v0 sử dụng ALT, trước tiên validator phải nạp từng bảng tra cứu được tham chiếu từ Bank và AccountsDB, xác minh tài khoản đó là một Address Lookup Table hợp lệ, giải tuần tự trạng thái, phân giải các chỉ mục được yêu cầu thành địa chỉ đầy đủ 32 byte, rồi hợp nhất các địa chỉ đó với khóa tài khoản tĩnh của giao dịch. Chỉ sau bước phân giải này, validator mới có danh sách tài khoản đầy đủ cần thiết để xác định khóa đọc/ghi và xung đột với các giao dịch khác.

Đặc tả giao dịch v1

Một giao dịch v1 đã tuần tự hóa bắt đầu bằng byte phiên bản 0x81. Tiếp theo là header thông điệp ba byte theo kiểu legacy, mặt nạ cấu hình giao dịch 32 bit, bộ chỉ định thời hạn 32 byte, số lượng chỉ thị và địa chỉ, mảng đầy đủ các địa chỉ 32 byte, giá trị cấu hình, header chỉ thị có kích thước cố định, tải trọng chỉ thị liền kề và cuối cùng là các chữ ký.

Mã
VersionByte (u8)
  -- 0x81

LegacyHeader (u8, u8, u8)

TransactionConfigMask (u32)
  -- Bitmask describing which configuration values are present

LifetimeSpecifier [u8; 32]

NumInstructions (u8)

NumAddresses (u8)

Addresses [[u8; 32]]
  -- Length = NumAddresses

ConfigValues [[u8; 4]]
  -- Length = popcount(TransactionConfigMask)
  -- Multi-word values, such as priority fee, consume multiple entries

InstructionHeaders [(u8, u8, u16)]
  -- Length = NumInstructions
  -- (ProgramAccountIndex,
      NumInstructionAccounts,
      NumInstructionDataBytes)

InstructionPayloads [InstructionPayload]
  -- Length = NumInstructions

InstructionPayload:
  InstructionAccountIndexes [u8]
    -- Length = NumInstructionAccounts

  InstructionData [u8]
    -- Length = NumInstructionDataBytes

Signatures [[u8; 64]]
  -- Length = LegacyHeader.NumRequiredSignatures

Do đó, v1 khác các định dạng trước ở một số điểm nền tảng. Mã nhận dạng phiên bản nằm tại byte 0, chữ ký được chuyển xuống cuối và không còn cần tiền tố độ dài riêng, số lượng tài khoản và chỉ thị trở thành các giá trị u8 có độ rộng cố định, cấu hình tài nguyên được mã hóa trực tiếp trong giao dịch và header chỉ thị có kích thước cố định được tách khỏi tải trọng có độ dài biến đổi. Không giống legacy và v0, v1 không sử dụng Address Lookup Tables.

Giao dịch v1 thay thế các chỉ thị cấu hình của Compute Budget Program bằng các trường trong header giao dịch. TransactionConfigMask ban đầu có thể khai báo:

  • tổng phí ưu tiên tính bằng lamport
  • giới hạn đơn vị tính toán
  • giới hạn kích thước dữ liệu tài khoản được nạp
  • kích thước heap được yêu cầu

Mỗi bit được đặt xác định một giá trị cấu hình bốn byte đi kèm, trong đó phí ưu tiên 64 bit chiếm hai vị trí trên mặt nạ. Mặt nạ được thiết kế để có thể mở rộng trong các phiên bản giao dịch tương lai.

Giao dịch mẫu

Để làm rõ sự khác biệt giữa các định dạng giao dịch của Solana, chúng ta sẽ xem xét ví dụ hữu ích đơn giản nhất: chuyển SOL từ địa chỉ này sang địa chỉ khác.

Giao dịch mẫu có một người ký duy nhất (tức người gửi) và gọi System Program một lần để chuyển 1.000 lamport cho người nhận. Giao dịch tham chiếu ba địa chỉ: người gửi, người nhận và System Program.

Giao dịch legacy và v0

Giao dịch legacy và v0 sử dụng bố cục cấp cao gần như giống nhau. Cả hai đều bắt đầu bằng số lượng chữ ký, ngay sau đó là chính các chữ ký. Thông điệp của giao dịch nằm tiếp theo. Với giao dịch chuyển có một người ký, byte đầu tiên là 01, chỉ định một chữ ký, tiếp theo là chữ ký Ed25519 dài 64 byte của người gửi.

Thông điệp chứa header ba byte, địa chỉ tài khoản, một recent blockhash (bộ chỉ định thời hạn) và các chỉ thị đã biên dịch.

Người gửi là địa chỉ 0, người nhận là địa chỉ 1 và System Program là địa chỉ 2. Chỉ thị chuyển tham chiếu chương trình tại chỉ mục 2 và truyền các chỉ mục tài khoản 00 01 cho chương trình.

Định dạng legacy và v0 chỉ khác nhau đôi chút:

  • Thông điệp legacy bắt đầu trực tiếp bằng header thông điệp ba byte, còn thông điệp v0 bắt đầu bằng byte phiên bản 0x80, sau đó mới đến header.
  • v0 cũng nối thêm phần Address Lookup Table sau các chỉ thị. Ví dụ đơn giản này không sử dụng bảng tra cứu, vì vậy phần này chỉ gồm một byte 00 cho biết không có lượt tra cứu nào.

Do đó, giao dịch chuyển SOL mẫu có kích thước 215 byte ở định dạng legacy và 217 byte ở định dạng v0. v0 thêm 1 byte cho tiền tố phiên bản và 1 byte cho mảng bảng tra cứu trống. Phần còn lại của giao dịch giống hệt nhau.

Người gửi chỉ ký thông điệp. Trong ví dụ legacy, chữ ký bao phủ các byte 65–214; với v0, chữ ký bao phủ các byte 65–216, bắt đầu bằng tiền tố phiên bản thông điệp 0x80.

Bảng dưới đây trình bày chi tiết bố cục byte của giao dịch chuyển SOL mẫu giữa hai địa chỉ bằng định dạng giao dịch v0.

Vị tríKích thướcTrườngGiá trị mẫuMô tả
01 BSố lượng chữ ký01Một chữ ký; compact-u16
1–6464 BChữ ký 0<Ed25519 signature>Chữ ký của người gửi
651 BTiền tố phiên bản80Thông điệp có phiên bản, phiên bản 0
66–683 BHeader thông điệp01 00 011 người ký bắt buộc, 0 tài khoản đã ký chỉ đọc, 1 tài khoản chưa ký chỉ đọc
691 BSố lượng tài khoản tĩnh03Ba tài khoản trực tiếp
70–10132 BTài khoản 0<sender pubkey>Người gửi/người trả phí; người ký có thể ghi
102–13332 BTài khoản 1<recipient pubkey>Người nhận; tài khoản chưa ký có thể ghi
134–16532 BTài khoản 211111111111111111111111111111111System Program; chưa ký, chỉ đọc
166–19732 BRecent blockhash<recent blockhash>Thời hạn giao dịch
1981 BSố lượng chỉ thị01Một chỉ thị
1991 BChỉ mục ID chương trình02System Program
2001 BSố lượng tài khoản của chỉ thị02Hai tài khoản chỉ thị
201–2022 BChỉ mục tài khoản00 01Người gửi, người nhận
2031 BĐộ dài dữ liệu0C12 byte
204–2074 BBộ phân biệt chuyển tiền02 00 00 00SystemInstruction::Transfer
208–2158 BLamportE8 03 00 00 00 00 00 001.000 lamport
2161 BSố lượng lượt tra cứu bảng địa chỉ00Không có lượt tra cứu ALT
Tổng217 B

Cấu hình tài nguyên

Trong giao dịch legacy và v0, cấu hình tài nguyên được biểu diễn dưới dạng chỉ thị gửi đến Compute Budget Program. Các chỉ thị phổ biến gồm SetComputeUnitLimit và SetComputeUnitPrice. SetLoadedAccountsDataSizeLimit và RequestHeapFrame cũng được sử dụng khi cần.

Trong ví dụ giao dịch tối giản này, các chỉ thị đó không xuất hiện. Thay vào đó, runtime cung cấp các giá trị mặc định.

Không có giá đơn vị tính toán đồng nghĩa không có phí ưu tiên, còn giới hạn dữ liệu tài khoản được nạp mặc định là mức tối đa của runtime.

Việc validator phải quét danh sách chỉ thị để tìm các chỉ thị Compute Budget trong quá trình tiếp nhận giao dịch là một trong những động lực thúc đẩy định dạng v1 mới, nơi thông tin này được chuyển vào TransactionConfigMask và ConfigValues.

Ngay từ đầu, việc biểu diễn cấu hình cấp giao dịch dưới dạng chỉ thị cũng tạo ra một lượng dữ liệu phụ trợ cố hữu. Legacy và v0 không có trường riêng cho mức tính toán hoặc phí ưu tiên được yêu cầu, nên các thiết lập này được bổ sung thông qua Compute Budget Program: giao dịch phải tham chiếu ID chương trình của nó, mỗi thiết lập chiếm không gian trong danh sách chỉ thị và bản thân lệnh gọi chương trình không thực hiện công việc ứng dụng nào nhưng vẫn tiêu tốn tài nguyên tính toán.

Thay vào đó, v1 dành cho các giá trị này một vị trí riêng trong định dạng truyền tải, tránh chi phí chỉ thị bổ sung và giúp validator kiểm tra cấu hình tài nguyên dễ dàng hơn với chi phí thấp hơn.

Giao dịch v1

Thay vì bắt đầu bằng số lượng chữ ký và các chữ ký, giao dịch v1 bắt đầu trực tiếp bằng byte phiên bản 0x81.

Tiếp theo là header ba byte, một TransactionConfigMask bốn byte mới, bộ chỉ định thời hạn (thường là blockhash nhưng cũng có thể là nonce), số lượng chỉ thị và địa chỉ, địa chỉ tài khoản, giá trị cấu hình, chỉ thị và cuối cùng là các chữ ký.

Vị tríKích thướcTrườngGiá trị mẫuMô tả
01 BByte phiên bản81Giao dịch v1
1–33 BHeader legacy01 00 011 chữ ký bắt buộc, 0 tài khoản đã ký chỉ đọc, 1 tài khoản chưa ký chỉ đọc
4–74 BMặt nạ cấu hình giao dịch0C 00 00 000x0000000C: bit 2 và 3 được đặt, chỉ định hai giá trị cấu hình 4 byte
8–3932 BBộ chỉ định thời hạn<recent blockhash>Recent blockhash (hoặc nonce)
401 BSố lượng chỉ thị011 chỉ thị System Program
411 BSố lượng địa chỉ03Người gửi, người nhận, System Program
42–7332 BĐịa chỉ 0<sender pubkey>Người gửi, người trả phí, người ký có thể ghi
74–10532 BĐịa chỉ 1<recipient pubkey>Người nhận, tài khoản chưa ký có thể ghi
106–13732 BĐịa chỉ 211111111111111111111111111111111System Program, chỉ đọc, chưa ký
138–1414 BGiá trị cấu hình: Giới hạn đơn vị tính toán10 27 00 0010.000 CU dưới dạng u32 little-endian (tương ứng với bit 2 của mặt nạ)
142–1454 BGiá trị cấu hình: Giới hạn kích thước dữ liệu tài khoản được nạp00 00 01 0065.536 byte / 64 KiB dưới dạng u32 little-endian (tương ứng với bit 3 của mặt nạ)
146–1494 BChỉ thị: Header02 02 0C 00Chỉ mục chương trình 2, 2 tài khoản, 12 byte dữ liệu
150–1512 BChỉ thị: Chỉ mục tài khoản00 01Địa chỉ 0 = người gửi, Địa chỉ 1 = người nhận
152–1554 BChỉ thị: Bộ phân biệt chuyển tiền02 00 00 00SystemInstruction::Transfer
156–1638 BChỉ thị: Lamportví dụ E8 03 00 00 00 00 00 001.000 lamport dưới dạng u64 little-endian
164–22764 BChữ ký 0<Ed25519 signature>Chữ ký của người gửi trên các byte 0–155
Tổng228 B

Xác minh chữ ký

Xác minh chữ ký là một trong những thao tác đầu tiên được thực hiện khi giao dịch đến validator. Các giao dịch có chữ ký không hợp lệ cần được lọc và loại bỏ trước khi đến bộ lập lịch. Việc đặt chữ ký sau một thông điệp có độ dài biến đổi có vẻ sẽ khiến việc truy cập khó khăn hơn, nhưng trên thực tế không phải vậy.

Trước khi thực hiện bước xác minh Ed25519 tốn kém, validator chỉ cần xác định vị trí bắt đầu và kết thúc của từng phần trong giao dịch. Định dạng v1 được thiết kế để thao tác này có chi phí thấp và mang tính tất định.

Byte đầu tiên, 0x81, ngay lập tức xác định giao dịch là v1. Header theo sau chứa num_required_signatures, vì vậy ngay từ đầu validator đã biết cần tìm bao nhiêu chữ ký 64 byte.

Sau đó, trình phân tích TransactionView của Agave duyệt tiến qua giao dịch và ghi lại các vị trí. Trình phân tích đọc các trường có kích thước cố định và sử dụng NumAddresses để bỏ qua mảng địa chỉ.

Nó sử dụng mặt nạ cấu hình để xác định kích thước phần cấu hình và đọc từng header chỉ thị 4 byte để biết kích thước tải trọng chỉ thị tương ứng.

Khi trình phân tích đã đi qua tải trọng chỉ thị cuối cùng, vị trí hiện tại được ghi lại làm vị trí chữ ký. Kể từ vị trí đó, Agave yêu cầu chính xác num_required_signatures × 64 byte.

Phần triển khai lưu một SignatureFrame chứa số lượng chữ ký và vị trí byte của chữ ký đầu tiên trong gói. Thông điệp đã ký của giao dịch là dải byte từ đầu thông điệp v1 đến vị trí chữ ký đã ghi. Nhờ đó, validator có thể thực hiện bước xác minh Ed25519 tốn kém mà không cần thực thi giao dịch hoặc nạp tài khoản.

v1 cũng cấm các byte nằm sau mảng chữ ký. Khi trình phân tích đến phần chữ ký, các byte còn lại có kích thước rõ ràng được xác định bởi số lượng chữ ký. SIMD-0385 yêu cầu chính xác một chữ ký 64 byte cho mỗi người ký bắt buộc và không có dữ liệu nào sau chữ ký cuối cùng.

Cải thiện khả năng phân tích chỉ thị

Bố cục của giao dịch v1 giúp phân tích chỉ thị dễ dàng hơn. Để xác định vị trí một chỉ thị ở phía sau trong giao dịch legacy và v0, trình phân tích phải duyệt qua các chỉ thị trước đó, giải mã độ dài và bỏ qua từng tải trọng có độ dài biến đổi.

v1 tách header chỉ thị có độ rộng cố định khỏi tải trọng có độ dài biến đổi. Trước tiên, mỗi chỉ thị đóng góp một header bốn byte chứa chỉ mục tài khoản chương trình, số lượng tài khoản chỉ thị và độ dài dữ liệu chỉ thị. Các header này được nhóm lại trước phần tải trọng chỉ mục tài khoản và dữ liệu. Cách này cung cấp trước một mô tả gọn nhẹ về mọi chỉ thị. Nó giúp việc xác định khung và bỏ qua phần chỉ thị ít tốn kém hơn, đồng thời giúp xác định vị trí của mảng chữ ký phía sau mà không cần phân tích dữ liệu chỉ thị.

Mặt nạ cấu hình giao dịch

Phần bổ sung quan trọng còn lại của định dạng v1 là TransactionConfigMask bốn byte.

Giao dịch legacy và v0 cấu hình tài nguyên thông qua các chỉ thị gửi đến Compute Budget Program. Ví dụ, một giao dịch có thể chứa các chỉ thị SetComputeUnitLimit, SetComputeUnitPrice hoặc SetLoadedAccountsDataSizeLimit. Một validator quan tâm đến yêu cầu tài nguyên hoặc mức ưu tiên của giao dịch phải tìm và diễn giải các chỉ thị này. Giao dịch v1 chuyển thông tin này ra khỏi luồng chỉ thị và đưa vào chính định dạng giao dịch.

Mặt nạ là một trường bit little-endian 32 bit. Mỗi bit được đặt tương ứng với một từ bốn byte trong phần ConfigValues nằm sau đó trong giao dịch:

  • Bit 0 và 1: tổng phí ưu tiên tính bằng lamport (được mã hóa dưới dạng u64 little-endian 8 byte)
  • Bit 2: giới hạn đơn vị tính toán (một u32 4 byte)
  • Bit 3: giới hạn kích thước dữ liệu tài khoản được nạp (một u32 4 byte)
  • Bit 4: kích thước heap được yêu cầu (một u32 4 byte)

Lưu ý: Đặc tả v1 ban đầu chỉ gán ý nghĩa cho các bit 0–4. Các bit còn lại hiện chưa được gán, để dành không gian cho các trường cấu hình cấp giao dịch trong tương lai.

Mặt nạ hoạt động như một lược đồ gọn nhẹ, cho trình phân tích biết cả những trường nào tồn tại và cần chờ bao nhiêu byte. Ví dụ, giao dịch chuyển SOL đơn giản của chúng ta cần giới hạn đơn vị tính toán và giới hạn kích thước dữ liệu tài khoản được nạp, nhưng không cần phí ưu tiên hoặc kích thước heap tùy chỉnh.

Vì hai bit này được đặt, chính xác hai giá trị cấu hình 4 byte nằm sau mảng địa chỉ của giao dịch. Trong trường hợp này, chúng yêu cầu giới hạn 20.000 CU và giới hạn dữ liệu tài khoản được nạp là 64 KiB.

Mặt nạ cho validator biết cấu hình 4 byte đầu tiên thuộc bit 2 (giới hạn đơn vị tính toán), còn cấu hình thứ hai thuộc bit 3 (giới hạn dữ liệu tài khoản được nạp).

Trong giao dịch legacy và v0, việc bỏ qua chỉ thị giới hạn đơn vị tính toán sẽ cung cấp cho giao dịch một ngân sách tính toán ngầm định. v1 không sử dụng cùng các giá trị mặc định đó. Giới hạn đơn vị tính toán chưa đặt sẽ được phân giải thành 0, giới hạn kích thước dữ liệu tài khoản được nạp chưa đặt cũng vậy; chỉ heap giữ giá trị mặc định 32 KiB. Do đó, giao dịch v1 phải yêu cầu rõ ràng các tài nguyên cần thiết.

Việc chuyển các thiết lập này vào một khu vực cấu hình được xác định rõ giúp validator truy cập trực tiếp thông tin cần thiết trong quá trình tiếp nhận giao dịch, thay vì phải tìm kiếm trong các chỉ thị. Điều này cũng có nghĩa là các chỉ thị Compute Budget Program không còn cấu hình giao dịch v1. Nếu được đưa vào, chúng sẽ bị bỏ qua và được xử lý như các chỉ thị no-op nhưng vẫn tiêu tốn đơn vị tính toán.

Điều này cũng mang lại lợi ích bổ sung về không gian. Trong giao dịch legacy/v0, khi thêm chỉ thị Compute Budget, nhìn chung bạn cần cả địa chỉ Compute Budget Program dài 32 byte trong danh sách tài khoản lẫn chính các chỉ thị đã tuần tự hóa.

Kết luận

Ba định dạng giao dịch của Solana phản ánh quá trình phát triển của mạng. Legacy thiết lập mô hình ban đầu, v0 mở rộng mô hình này bằng ALT để hỗ trợ tập hợp tài khoản lớn hơn trong giới hạn 1.232 byte, còn v1 tư duy lại định dạng truyền tải ở cấp độ nền tảng hơn xoay quanh giao dịch lớn hơn, phân tích đơn giản hơn, địa chỉ trực tiếp và cấu hình tài nguyên tích hợp.

Cả ba vẫn hợp lệ, nhưng mỗi định dạng đại diện cho một giai đoạn khác nhau trong quá trình phát triển của Solana. Khi xem xét cùng nhau, chúng cho thấy định dạng giao dịch đã thích ứng như thế nào khi ứng dụng, thị trường phí và yêu cầu đối với validator của mạng liên tục phát triển.

Tài nguyên khác

Đăng ký nhận tin từ Helius

Luôn cập nhật những thông tin mới nhất về phát triển Solana và nhận thông báo khi chúng tôi đăng bài

Hình ảnh phóng to