Máy ảo Solana (SVM) đang được sử dụng rộng rãi như một lớp thực thi cho các giải pháp Layer-2 (L2) khác nhau. Tuy nhiên, một hạn chế chính trong thiết kế ban đầu của SVM là tính mờ mịt của gốc trạng thái toàn cầu. Điều này gây ra những thách thức đáng kể đối với các hệ thống rollup, nơi gốc trạng thái toàn cầu là quan trọng để đảm bảo tính toàn vẹn, cho phép chứng minh gian lận và hỗ trợ các hoạt động qua các lớp.
Trong rollup, người đề xuất gửi L2 state root (Merkle root) đến Layer-1 (L1) theo định kỳ, thiết lập các điểm kiểm tra cho chuỗi L2. Những điểm kiểm tra này cho phép chứng minh sự bao gồm cho bất kỳ trạng thái tài khoản nào, giúp thực hiện không có trạng thái từ một điểm kiểm tra đến điểm kiểm tra khác. Chứng minh gian lận dựa trên cơ chế này, vì các bên tham gia có thể cung cấp chứng minh sự bao gồm để xác minh đầu vào hợp lệ trong khi tranh chấp. Ngoài ra, cây Merkle cải thiện sự an toàn của các cầu nối chuẩn bằng cách cho phép người dùng tạo chứng minh sự bao gồm cho các giao dịch rút tiền, đảm bảo giao互信互动作L2 và L1.
Để giải quyết những thách thức này, Mạng SOONgiới thiệu cây Merkle vào lớp thực thi SVM, cho phép khách hàng cung cấp chứng minh bao gồm. SOON tích hợp với Proof-of-History bằng cách sử dụng các mục nhập duy nhất để nhúng các gốc trạng thái trực tiếp vào các blockchain dựa trên SVM. Với sự đổi mới này, SOON stack có thể hỗ trợ các rollup mới dựa trên SVM với tính bảo mật, khả năng mở rộng và tiện ích nâng cao.
Solana luôn được thiết kế với khả năng xử lý cao như mục tiêu chính, đòi hỏi phải có sự thương thảo thiết kế cẩn thận - đặc biệt là trong giai đoạn phát triển ban đầu - để đạt được hiệu suất đột phá của nó. Trong số những sự thương thảo này, một trong những quyết định có ảnh hưởng nhất liên quan đến cách thức và thời điểm Solana sẽ merklize trạng thái của mình.
Cuối cùng, quyết định này đã tạo ra những thách thức đáng kể đối với khách hàng trong việc chứng minh trạng thái toàn cầu cũng như việc bao gồm giao dịch và xác minh thanh toán đơn giản (SPV). Sự thiếu hụt của một gốc trạng thái được băm một cách nhất quán đại diện cho trạng thái SVM theo hình thức merkle gây ra khó khăn đáng kể đối với các dự án như khách hàng nhẹ và rollups.
Hãy xem cách thực hiện merklization trên các chuỗi khác và sau đó xác định các thách thức được đưa ra bởi kiến trúc giao thức của Solana.
Trên Bitcoin, các giao dịch được lưu trữ trong một khối sử dụng một Cây Merkle, whose root is stored in the tiêu đề khối. Giao thức Bitcoin sẽ băm các đầu vào và đầu ra của giao dịch (cũng như một số dữ liệu khác) thành một ID giao dịch (TxID). Để chứng minh trạng thái trên Bitcoin, người dùng có thể đơn giản tính toán một chứng minh Merkle để xác minh TxID so với Merkle root của block.
Quá trình xác minh này cũng xác minh trạng thái, vì Tx ID là duy nhất cho một tập hợp các đầu vào và đầu ra, cả hai đều phản ánh thay đổi trạng thái địa chỉ. Lưu ý rằng giao dịch Bitcoin cũng có thể chứa Các kịch bản Taproot, các đầu ra giao dịch có thể được kiểm tra trong quá trình xác minh, thường bằng cách chạy lại kịch bản bằng cách sử dụng đầu vào của giao dịch và dữ liệu chứng kiến của kịch bản, và xác minh đối với đầu ra của nó.
Tương tự như Bitcoin, Ethereum lưu trữ giao dịch bằng cách sử dụng một cấu trúc dữ liệu tùy chỉnh (phát sinh từ cây Merkle) được gọi là gate.Merkle Patricia Trie(MPT). Cấu trúc dữ liệu này được thiết kế để cập nhật nhanh chóng và tối ưu hóa trên các tập dữ liệu lớn. Tự nhiên, điều này là bởi vì Ethereum có đáng kể nhiều đầu vào và đầu ra hơn để quản lý so với Bitcoin.
Cổng Máy ảo Ethereum(EVM) hoạt động như một máy trạng thái toàn cầu. EVM bản chất là một môi trường tính toán phân tán khổng lồ hỗ trợ thực thi.hợp đồng thông minh, mỗi người đều dành riêng cho không gian địa chỉ của họ trong bộ nhớ toàn cầu. Do đó, các khách hàng muốn xác minh trạng thái trên Ethereum phải tính đến không chỉ kết quả của một giao dịch (logs, mã trả về, v.v.) mà còn sự thay đổi của trạng thái toàn cầu do giao dịch.
May mắn thay, EVM sử dụng một cách thông minh ba cấu trúc trie quan trọng, lưu trữ gốc của chúng trong mỗi tiêu đề khối.
Dựa vào một giao dịch, một khách hàng có thể chứng minh sự bao gồm của nó trong một khối bằng cách đánh giá gốc cây giao dịch (giống như Bitcoin), kết quả của nó bằng cách đánh giá gốc biên nhận, và sự thay đổi của trạng thái toàn cầu bằng cách đánh giá gốc trạng thái.
Một trong những lý do khiến Solana có khả năng xử lý cao là vì nó không có cấu trúc đa cây như Ethereum. Các nhà lãnh đạo Solana thực hiện tính toán cây Merkle khi tạo khối, nhưng chúng được cấu trúc khác so với EVM. Thật không may, vấn đề nằm ở đây cho các rollups dựa trên SVM.
Solana merklizes giao dịch thành những mục được gọi là entries và có thể có nhiều entries trong mỗi slot; do đó, có nhiều gốc giao dịch trong mỗi khối. Hơn nữa, Solana tính toán một Merkle root của trạng thái tài khoản chỉ một lần trong mỗi epoch (khoảng 2,5 ngày) và root này không có sẵn trên ledger.
Trên thực tế, tiêu đề khối Solana không chứa bất kỳ Merkle roots nào. Thay vào đó, chúng chứa thông tin về khối trước và khối hiện tại blockhash, được tính toán thông qua Solana của Chứng minh về Lịch sửThuật toán (PoH). PoH yêu cầu các nhà xác thực liên tục đăng ký các “tick” bằng cách đệ quy băm các mục khối, có thể trống hoặc chứa các lô giao dịch. Tick cuối cùng (băm) của thuật toán PoH là blockhash của khối đó.
Vấn đề với Proof of History là nó làm cho việc chứng minh trạng thái rất khó khăn từ một blockhash. Solana được thiết kế để phát sóng các băm PoH để duy trì khái niệm về thời gian trôi qua. Gốc giao dịch chỉ có sẵn cho một PoH tick chứa một mục có giao dịch, không phải toàn bộ khối, và không có gốc trạng thái được lưu trữ trong bất kỳ mục nào.
Tuy nhiên, còn tồn tại một loại mã băm khác mà khách hàng có thể sử dụng: mã băm ngân hàng. Đôi khi được gọi là mã băm khe, mã băm ngân hàng có sẵn trong SlotHashes sysvartài khoản, mà có thể được truy vấn bởi một khách hàng. Một hash ngân hàng được tạo ra cho mỗi khối (khe) từ một số lượng ít nguồn:
Như mọi người có thể thấy, hash ngân hàng bị quá tải với nhiều đầu vào hash, điều này làm tăng độ phức tạp cho khách hàng cố gắng chứng minh thông tin về giao dịch hoặc trạng thái. Ngoài ra, chỉ có một hash ngân hàng cho một ngân hàng đã thực hiện một “epoch accounts hash” - hash của tất cả các tài khoản một lần mỗi epoch - mới có thể bao gồm root cụ thể đó. Hơn nữa, tài khoản SlotHashes sysvar được cắt ngắn thành 512 hash ngân hàng cuối cùng.
mạng SOONlà một SVM L2 trên Ethereum. Trong quá trình tích hợp merklization vào SOON, chúng tôi ưu tiên sử dụng các giải pháp đã được chứng minh và được xác định tốt để đảm bảo tính ổn định, thay vì phải phát minh lại bánh xe. Trong việc quyết định sử dụng cấu trúc dữ liệu hoặc thuật toán băm nào, chúng tôi đã xem xét tính tương thích của chúng với các hợp đồng L1 của Ngăn xếp Lạc Quan, khả năng tích hợp một cách mượt mà vào kiến trúc Solana, và liệu họ có thể đạt hiệu suất cao trong mô hình tài khoản của Solana hay không.
Chúng tôi đã phát hiện rằng khi số lượng tài khoản tăng lên, mô hình lưu trữ Merkle Patricia Trie (MPT) dựa trên cơ sở của [gate] có xu hướng trở nên chậm hơn.LSM-Treesẽ tạo ra nhiều tỷ lệ tăng cường đọc/ghi đĩa hơn, dẫn đến mất hiệu suất. Cuối cùng, chúng tôi quyết định tích hợp Erigon MPTbằng cách xây dựng dựa trên công việc Rust tuyệt vời được thực hiện bởi rETHđội và hỗ trợ thêm cho mô hình tài khoản Solana.
Như đã đề cập trước đó, cây trạng thái của SOON là một MPT được xây dựng để hỗ trợ tài khoản Solana. Do đó, chúng tôi đã định nghĩa một loại tài khoản tương thích với SVM để phục vụ cho dữ liệu của mỗi nút lá.
struct TrieSolanaAccount {
lamports: u64,
data: Vec
thực thi được: bool,
rent_epoch: u64,
chủ sở hữu: Pubkey,
}
Để cho mô-đun MPT có thể đăng ký nhận thông tin trạng thái mới nhất của các tài khoản SVM trong thời gian thực, chúng tôi giới thiệu một thông báo tài khoản. Trong giai đoạn Ngân hàng, thông báo tài khoản thông báo cho mô-đun MPT về thay đổi trạng thái tài khoản và MPT cập nhật những thay đổi này theo cấu trúc cây trie một cách tăng dần.
Lưu ý rằng mô-đun MPT chỉ cập nhật các cây con của nó trong suốt 50 slot và không tính toán state root vào cuối mỗi slot. Tiếp cận này được thực hiện với hai lý do. Thứ nhất, tính toán state root cho mỗi slot sẽ ảnh hưởng đáng kể đến hiệu suất. Thứ hai, state root chỉ cần khi người đề xuất gửi.outputRootđến L1. Do đó, chỉ cần tính toán theo chu kỳ, dựa trên tần suất nộp đề xuất của người đề xuất.
outputRoot = keccak256(version, state_root, withdraw_root, l2_block_hash)
Mô-đun SOON MPT duy trì hai loại cấu trúc trie đồng thời: State Trie cho trạng thái toàn cầu và Withdraw Trie cho giao dịch rút tiền. Người đề xuất định kỳ tạo ra một outputRoot bằng cách sử dụng state root và withdraw root, và nộp nó cho L1.
Hiện tại, SOON tính toán trạng thái gốc và trạng thái rút tiền mỗi 450 khe và thêm nó vào chuỗi khối L2. Nhờ đó, tính nhất quán của dữ liệu MPT trên các nút khác trong mạng có thể được đảm bảo. Tuy nhiên, cấu trúc khối Solana không bao gồm tiêu đề khối, có nghĩa là không có nơi để lưu trữ trạng thái gốc. Hãy xem xét kỹ cấu trúc cơ bản của blockchain Solana và sau đó khám phá cách SOON giới thiệu UniqueEntry để lưu trữ trạng thái gốc.
Blockchain Solana bao gồm các khe, được tạo ra bởi mô-đun PoH. Mỗi khe chứa nhiều mục, mỗi mục bao gồm ticks và giao dịch. Tại các lớp mạng và lưu trữ, một khe được lưu trữ và truyền bằng cách sử dụng shredsnhư là đơn vị nhỏ nhất. Shreds có thể được chuyển đổi từ và sang các mục nhập.
pub struct Entry {
/// Số lượng băm kể từ ID Nhập trước đó.
pub num_hashes: u64,
/// Băm SHA-256num_hashes
sau ID Đăng nhập trước đó.
pub hash: Hash,
/// Một danh sách không theo thứ tự các giao dịch được quan sát trước khi mã ID nhập
/// được tạo ra. Chúng có thể đã được quan sát trước một Entry ID trước đó nhưng đã được
/// pushed back into this list to ensure deterministic interpretation of the ledger.
pub transactions: Vec
}
Chúng tôi đã theo dõi cấu trúc blockchain được tạo ra bởi PoH và giữ cấu trúc shred, cho phép chúng tôi tái sử dụng lớp lưu trữ hiện tại của Solana, lớp mạng, và khung công việc RPC. Để lưu trữ dữ liệu bổ sung trên blockchain L2, chúng tôi đã giới thiệu UniqueEntry. Đặc điểm này cho phép chúng tôi tùy chỉnh dữ liệu đầu vào và xác định các quy tắc xác thực độc lập cho dữ liệu.
pub const UNIQUE_ENTRY_NUM_HASHES_FLAG: u64 = 0x8000_0000_0000_0000;
/// Unique entry là một loại mục nhập đặc biệt. Đây là một lựa chọn hữu ích khi chúng ta cần lưu trữ một số dữ liệu trong
/// blockstore nhưng không muốn xác minh nó.
///
/// Cấu trúc của số lượng hashes
là:
/// |…1 bit…|…63 bit…|
/// \ _ _/
/// \ \
/// cờ trường tùy chỉnh
pub trait UniqueEntry: Sized {
fn encode_to_entries(&self) -> Vec
fn giải mã từ các mục nhập,
mục nhập: impl IntoIterator<Mục = Nhập khẩu>,
) -> Kết quả
}
pub fn unique_entry(custom_field: u64, hash: Hash) -> Entry {
Entry {
num_hashes: num_hashes(custom_field), hash, transactions: vec! [],
}
pub fn num_hashes(custom_field: u64) -> u64 {
assert!(custom_field
UNIQUE_ENTRY_NUM_HASHES_FLAG | custom_field
}
pub fn is_unique(entry: &Entry) -> bool {
entry.num_hashes & UNIQUE_ENTRY_NUM_HASHES_FLAG != 0
}
Trong UniqueEntry, num_hashes được sử dụng như một bố cục bit, trong đó cờ bit đầu tiên được sử dụng để phân biệt giữa một Entry và một Unique Entry, và 63 bit tiếp theo được sử dụng để xác định loại dữ liệu. Trường hash được sử dụng như payload, chứa dữ liệu tùy chỉnh yêu cầu.
Hãy xem một ví dụ về việc sử dụng ba mục nhập duy nhất để lưu trữ slot hash, state root và withdraw root.
/// MPT root unique entry.
pub struct MptRoot {
pub slot: Khe,
pub state_root: B256,
pub withdrawal_root: B256,
}
impl UniqueEntry cho MptRoot {
fn encode_to_entries(&self) -> Vec
let slot_entry = unique_entry(0, slot_to_hash(self.slot)); let state_root_entry = unique_entry(1, self.state_root.0.into()); let withdrawal_root_entry = unique_entry(2, self.withdrawal_root.0.into()); vec![slot_entry, state_root_entry, withdrawal_root_entry]
Không thể dịch văn bản. Vui lòng cung cấp văn bản hợp lệ để dịch.
fn giải mã từ các mục nhập,
entries: impl IntoIterator
) -> Kết quả
let mut entries = entries.into_iter(); let entry = entries.next().ok_or(UniqueEntryError::NoMoreEntries)?; let slot = hash_to_slot(entry.hash); let entry = entries.next().ok_or(UniqueEntryError::NoMoreEntries)?; let state_root = B256::from(entry.hash.to_bytes()); let entry = entries.next().ok_or(UniqueEntryError::NoMoreEntries)?; let withdrawal_root = B256::from(entry.hash.to_bytes()); Ok(MptRoot { slot, state_root, withdrawal_root, })
}
}
Vì UniqueEntry định nghĩa lại ngữ nghĩa của num_hashes, nó không thể được xử lý trong giai đoạn xác minh PoH. Do đó, ở đầu quá trình xác minh, chúng tôi trước tiên lọc ra các mục nhập duy nhất và chuyển chúng vào một luồng xác minh tùy chỉnh dựa trên loại dữ liệu của chúng. Các mục nhập thông thường còn lại tiếp tục qua quá trình xác minh PoH ban đầu.
Cầu nối bản địa là một phần quan trọng của cơ sở hạ tầng cho các giải pháp Layer 2, chịu trách nhiệm về truyền thông tin giữa L1 và L2. Tin nhắn từ L1 đến L2 được gọi là giao dịch gửi tiền, trong khi tin nhắn từ L2 đến L1 được gọi là giao dịch rút tiền.
Các giao dịch nạp tiền thường được xử lý bởi gateđường ống tạo ravà chỉ yêu cầu người dùng gửi một giao dịch duy nhất trên L1. Tuy nhiên, giao dịch rút tiền lại phức tạp hơn và yêu cầu người dùng gửi ba giao dịch để hoàn thành quy trình:
Bằng chứng bao gồm của giao dịch rút tiền đảm bảo rút tiền đã xảy ra trên L2, tăng cường đáng kể bảo mật của cầu nối chuẩn.
Trong OP Stack, băm giao dịch rút tiền của người dùng được lưu trữ trong biến trạng thái tương ứng vớiOptimismPortal contract. Giao diện RPC eth_getProof sau đó được sử dụng để cung cấp cho người dùng một chứng minh bao gồm giao dịch rút tiền cụ thể.
Khác với EVM, dữ liệu hợp đồng SVM được lưu trữ trong trường dữ liệu của tài khoản, và tất cả các loại tài khoản tồn tại ở cùng một cấp độ thứ bậc.
SOON đã giới thiệu một chương trình cầu nối native: Cầu1111111111111111111111111111111111111. Khi một người dùng khởi tạo giao dịch rút tiền, chương trình cầu nối tạo ra một chỉ số duy nhất toàn cầu cho mỗi giao dịch rút tiền và sử dụng chỉ số này như một hạt giống để tạo ra một mớiTài khoản Phát sinh Chương trìnhđể lưu trữ giao dịch rút tương ứng (PDA).
pub struct WithdrawalTransaction {
/// quầy rút tiền
pub nonce: U256,
/// người dùng muốn rút tiền
pub sender: Pubkey,
/// địa chỉ người dùng trong L1
pub target: Địa chỉ,
/// rút số tiền trong lamports
giá trị pub: U256,
/// giới hạn gas trong L1
pub gas_limit: U256,
/// thông tin rút tiền trong L1
dữ liệu pub: L1WithdrawalCalldata,
}
Chúng tôi đã xác định cấu trúc WithdrawalTransaction để lưu trữ giao dịch rút tiền trong trường dữ liệu của PDA.
Thiết kế này hoạt động tương tự như OP Stack. Khi outputRoot chứa giao dịch rút tiền được gửi đến L1, người dùng có thể gửi một chứng minh bao gồm cho giao dịch rút tiền đến L1 để bắt đầu giai đoạn thách thức.
Sau khi người đề xuất gửi outputRoot đến L1, điều này có nghĩa là trạng thái của L2 đã được giải quyết. Nếu một người thách thức phát hiện ra rằng người đề xuất đã gửi một trạng thái không chính xác, họ có thể khởi tạo một thách thức để bảo vệ quỹ trong cầu.
Một trong những khía cạnh quan trọng nhất của việc xây dựng một hệ thống chống lỗi là cho phép blockchain chuyển từ trạng thái S1 sang trạng thái S2 một cách không có trạng thái. Điều này đảm bảo rằng hợp đồng trọng tài trên L1 có thể phát lại các chỉ thị của chương trình một cách không có trạng thái để thực hiện trọng tài.
Tuy nhiên, ở đầu quá trình này, thử thách phải chứng minh rằng tất cả các đầu vào ban đầu trong trạng thái S1 là hợp lệ. Các đầu vào ban đầu này bao gồm trạng thái của các tài khoản tham gia (ví dụ: lamports, dữ liệu, chủ sở hữu, v.v.). Khác với EVM, SVM tự nhiên tách biệt trạng thái tài khoản và tính toán. Tuy nhiên, API SVM của Anzacho phép tài khoản được chuyển vào SVM thông qua TransactionProcessingCallback trait, như được hiển thị dưới đây.
pub trait TransactionProcessingCallback {
fn account_matches_owners(&self, account: &Pubkey, owners: &[Pubkey]) -> Option
fn get_account_shared_data(&self, pubkey: &Pubkey) -> Option;
fn add_builtin_account(&self, _name: &str, _program_id: &Pubkey) {}
}
Do đó, chúng ta chỉ cần sử dụng trạng thái S1 cùng với các chứng minh sự bao gồm của các tài khoản đầu vào để xác minh tính hợp lệ của đầu vào của chương trình thử thách.
SOON đang đánh dấu một mốc quan trọng cho sự phát triển của hệ sinh thái SVM. Bằng cách tích hợp merklization, SOON giải quyết vấn đề thiếu gốc trạng thái toàn cầu của Solana, cho phép các tính năng cần thiết như chứng minh sự bao gồm cho chứng minh lỗi, rút tiền an toàn và thực thi không trạng thái.
Ngoài ra, thiết kế merklization của SOON trong SVM có thể cho phép các máy khách nhẹ trên các chuỗi dựa trên SVM, mặc dù Solana hiện tại không hỗ trợ máy khách nhẹ. Có thể thậm chí một số phần của thiết kế có thể hỗ trợ mang máy khách nhẹ đến chuỗi chính cũng được.
Sử dụng Merkle Patricia Tries (MPT) cho quản lý trạng thái, SOON phù hợp với cơ sở hạ tầng của Ethereum, nâng cao khả năng tương tác và tiến bộ các giải pháp SVM dựa trên L2. Đổi mới này tăng cường hệ sinh thái SVM bằng cách cải thiện bảo mật, khả năng mở rộng và tương thích, đồng thời thúc đẩy sự phát triển của các ứng dụng phi tập trung.
Mời người khác bỏ phiếu
Máy ảo Solana (SVM) đang được sử dụng rộng rãi như một lớp thực thi cho các giải pháp Layer-2 (L2) khác nhau. Tuy nhiên, một hạn chế chính trong thiết kế ban đầu của SVM là tính mờ mịt của gốc trạng thái toàn cầu. Điều này gây ra những thách thức đáng kể đối với các hệ thống rollup, nơi gốc trạng thái toàn cầu là quan trọng để đảm bảo tính toàn vẹn, cho phép chứng minh gian lận và hỗ trợ các hoạt động qua các lớp.
Trong rollup, người đề xuất gửi L2 state root (Merkle root) đến Layer-1 (L1) theo định kỳ, thiết lập các điểm kiểm tra cho chuỗi L2. Những điểm kiểm tra này cho phép chứng minh sự bao gồm cho bất kỳ trạng thái tài khoản nào, giúp thực hiện không có trạng thái từ một điểm kiểm tra đến điểm kiểm tra khác. Chứng minh gian lận dựa trên cơ chế này, vì các bên tham gia có thể cung cấp chứng minh sự bao gồm để xác minh đầu vào hợp lệ trong khi tranh chấp. Ngoài ra, cây Merkle cải thiện sự an toàn của các cầu nối chuẩn bằng cách cho phép người dùng tạo chứng minh sự bao gồm cho các giao dịch rút tiền, đảm bảo giao互信互动作L2 và L1.
Để giải quyết những thách thức này, Mạng SOONgiới thiệu cây Merkle vào lớp thực thi SVM, cho phép khách hàng cung cấp chứng minh bao gồm. SOON tích hợp với Proof-of-History bằng cách sử dụng các mục nhập duy nhất để nhúng các gốc trạng thái trực tiếp vào các blockchain dựa trên SVM. Với sự đổi mới này, SOON stack có thể hỗ trợ các rollup mới dựa trên SVM với tính bảo mật, khả năng mở rộng và tiện ích nâng cao.
Solana luôn được thiết kế với khả năng xử lý cao như mục tiêu chính, đòi hỏi phải có sự thương thảo thiết kế cẩn thận - đặc biệt là trong giai đoạn phát triển ban đầu - để đạt được hiệu suất đột phá của nó. Trong số những sự thương thảo này, một trong những quyết định có ảnh hưởng nhất liên quan đến cách thức và thời điểm Solana sẽ merklize trạng thái của mình.
Cuối cùng, quyết định này đã tạo ra những thách thức đáng kể đối với khách hàng trong việc chứng minh trạng thái toàn cầu cũng như việc bao gồm giao dịch và xác minh thanh toán đơn giản (SPV). Sự thiếu hụt của một gốc trạng thái được băm một cách nhất quán đại diện cho trạng thái SVM theo hình thức merkle gây ra khó khăn đáng kể đối với các dự án như khách hàng nhẹ và rollups.
Hãy xem cách thực hiện merklization trên các chuỗi khác và sau đó xác định các thách thức được đưa ra bởi kiến trúc giao thức của Solana.
Trên Bitcoin, các giao dịch được lưu trữ trong một khối sử dụng một Cây Merkle, whose root is stored in the tiêu đề khối. Giao thức Bitcoin sẽ băm các đầu vào và đầu ra của giao dịch (cũng như một số dữ liệu khác) thành một ID giao dịch (TxID). Để chứng minh trạng thái trên Bitcoin, người dùng có thể đơn giản tính toán một chứng minh Merkle để xác minh TxID so với Merkle root của block.
Quá trình xác minh này cũng xác minh trạng thái, vì Tx ID là duy nhất cho một tập hợp các đầu vào và đầu ra, cả hai đều phản ánh thay đổi trạng thái địa chỉ. Lưu ý rằng giao dịch Bitcoin cũng có thể chứa Các kịch bản Taproot, các đầu ra giao dịch có thể được kiểm tra trong quá trình xác minh, thường bằng cách chạy lại kịch bản bằng cách sử dụng đầu vào của giao dịch và dữ liệu chứng kiến của kịch bản, và xác minh đối với đầu ra của nó.
Tương tự như Bitcoin, Ethereum lưu trữ giao dịch bằng cách sử dụng một cấu trúc dữ liệu tùy chỉnh (phát sinh từ cây Merkle) được gọi là gate.Merkle Patricia Trie(MPT). Cấu trúc dữ liệu này được thiết kế để cập nhật nhanh chóng và tối ưu hóa trên các tập dữ liệu lớn. Tự nhiên, điều này là bởi vì Ethereum có đáng kể nhiều đầu vào và đầu ra hơn để quản lý so với Bitcoin.
Cổng Máy ảo Ethereum(EVM) hoạt động như một máy trạng thái toàn cầu. EVM bản chất là một môi trường tính toán phân tán khổng lồ hỗ trợ thực thi.hợp đồng thông minh, mỗi người đều dành riêng cho không gian địa chỉ của họ trong bộ nhớ toàn cầu. Do đó, các khách hàng muốn xác minh trạng thái trên Ethereum phải tính đến không chỉ kết quả của một giao dịch (logs, mã trả về, v.v.) mà còn sự thay đổi của trạng thái toàn cầu do giao dịch.
May mắn thay, EVM sử dụng một cách thông minh ba cấu trúc trie quan trọng, lưu trữ gốc của chúng trong mỗi tiêu đề khối.
Dựa vào một giao dịch, một khách hàng có thể chứng minh sự bao gồm của nó trong một khối bằng cách đánh giá gốc cây giao dịch (giống như Bitcoin), kết quả của nó bằng cách đánh giá gốc biên nhận, và sự thay đổi của trạng thái toàn cầu bằng cách đánh giá gốc trạng thái.
Một trong những lý do khiến Solana có khả năng xử lý cao là vì nó không có cấu trúc đa cây như Ethereum. Các nhà lãnh đạo Solana thực hiện tính toán cây Merkle khi tạo khối, nhưng chúng được cấu trúc khác so với EVM. Thật không may, vấn đề nằm ở đây cho các rollups dựa trên SVM.
Solana merklizes giao dịch thành những mục được gọi là entries và có thể có nhiều entries trong mỗi slot; do đó, có nhiều gốc giao dịch trong mỗi khối. Hơn nữa, Solana tính toán một Merkle root của trạng thái tài khoản chỉ một lần trong mỗi epoch (khoảng 2,5 ngày) và root này không có sẵn trên ledger.
Trên thực tế, tiêu đề khối Solana không chứa bất kỳ Merkle roots nào. Thay vào đó, chúng chứa thông tin về khối trước và khối hiện tại blockhash, được tính toán thông qua Solana của Chứng minh về Lịch sửThuật toán (PoH). PoH yêu cầu các nhà xác thực liên tục đăng ký các “tick” bằng cách đệ quy băm các mục khối, có thể trống hoặc chứa các lô giao dịch. Tick cuối cùng (băm) của thuật toán PoH là blockhash của khối đó.
Vấn đề với Proof of History là nó làm cho việc chứng minh trạng thái rất khó khăn từ một blockhash. Solana được thiết kế để phát sóng các băm PoH để duy trì khái niệm về thời gian trôi qua. Gốc giao dịch chỉ có sẵn cho một PoH tick chứa một mục có giao dịch, không phải toàn bộ khối, và không có gốc trạng thái được lưu trữ trong bất kỳ mục nào.
Tuy nhiên, còn tồn tại một loại mã băm khác mà khách hàng có thể sử dụng: mã băm ngân hàng. Đôi khi được gọi là mã băm khe, mã băm ngân hàng có sẵn trong SlotHashes sysvartài khoản, mà có thể được truy vấn bởi một khách hàng. Một hash ngân hàng được tạo ra cho mỗi khối (khe) từ một số lượng ít nguồn:
Như mọi người có thể thấy, hash ngân hàng bị quá tải với nhiều đầu vào hash, điều này làm tăng độ phức tạp cho khách hàng cố gắng chứng minh thông tin về giao dịch hoặc trạng thái. Ngoài ra, chỉ có một hash ngân hàng cho một ngân hàng đã thực hiện một “epoch accounts hash” - hash của tất cả các tài khoản một lần mỗi epoch - mới có thể bao gồm root cụ thể đó. Hơn nữa, tài khoản SlotHashes sysvar được cắt ngắn thành 512 hash ngân hàng cuối cùng.
mạng SOONlà một SVM L2 trên Ethereum. Trong quá trình tích hợp merklization vào SOON, chúng tôi ưu tiên sử dụng các giải pháp đã được chứng minh và được xác định tốt để đảm bảo tính ổn định, thay vì phải phát minh lại bánh xe. Trong việc quyết định sử dụng cấu trúc dữ liệu hoặc thuật toán băm nào, chúng tôi đã xem xét tính tương thích của chúng với các hợp đồng L1 của Ngăn xếp Lạc Quan, khả năng tích hợp một cách mượt mà vào kiến trúc Solana, và liệu họ có thể đạt hiệu suất cao trong mô hình tài khoản của Solana hay không.
Chúng tôi đã phát hiện rằng khi số lượng tài khoản tăng lên, mô hình lưu trữ Merkle Patricia Trie (MPT) dựa trên cơ sở của [gate] có xu hướng trở nên chậm hơn.LSM-Treesẽ tạo ra nhiều tỷ lệ tăng cường đọc/ghi đĩa hơn, dẫn đến mất hiệu suất. Cuối cùng, chúng tôi quyết định tích hợp Erigon MPTbằng cách xây dựng dựa trên công việc Rust tuyệt vời được thực hiện bởi rETHđội và hỗ trợ thêm cho mô hình tài khoản Solana.
Như đã đề cập trước đó, cây trạng thái của SOON là một MPT được xây dựng để hỗ trợ tài khoản Solana. Do đó, chúng tôi đã định nghĩa một loại tài khoản tương thích với SVM để phục vụ cho dữ liệu của mỗi nút lá.
struct TrieSolanaAccount {
lamports: u64,
data: Vec
thực thi được: bool,
rent_epoch: u64,
chủ sở hữu: Pubkey,
}
Để cho mô-đun MPT có thể đăng ký nhận thông tin trạng thái mới nhất của các tài khoản SVM trong thời gian thực, chúng tôi giới thiệu một thông báo tài khoản. Trong giai đoạn Ngân hàng, thông báo tài khoản thông báo cho mô-đun MPT về thay đổi trạng thái tài khoản và MPT cập nhật những thay đổi này theo cấu trúc cây trie một cách tăng dần.
Lưu ý rằng mô-đun MPT chỉ cập nhật các cây con của nó trong suốt 50 slot và không tính toán state root vào cuối mỗi slot. Tiếp cận này được thực hiện với hai lý do. Thứ nhất, tính toán state root cho mỗi slot sẽ ảnh hưởng đáng kể đến hiệu suất. Thứ hai, state root chỉ cần khi người đề xuất gửi.outputRootđến L1. Do đó, chỉ cần tính toán theo chu kỳ, dựa trên tần suất nộp đề xuất của người đề xuất.
outputRoot = keccak256(version, state_root, withdraw_root, l2_block_hash)
Mô-đun SOON MPT duy trì hai loại cấu trúc trie đồng thời: State Trie cho trạng thái toàn cầu và Withdraw Trie cho giao dịch rút tiền. Người đề xuất định kỳ tạo ra một outputRoot bằng cách sử dụng state root và withdraw root, và nộp nó cho L1.
Hiện tại, SOON tính toán trạng thái gốc và trạng thái rút tiền mỗi 450 khe và thêm nó vào chuỗi khối L2. Nhờ đó, tính nhất quán của dữ liệu MPT trên các nút khác trong mạng có thể được đảm bảo. Tuy nhiên, cấu trúc khối Solana không bao gồm tiêu đề khối, có nghĩa là không có nơi để lưu trữ trạng thái gốc. Hãy xem xét kỹ cấu trúc cơ bản của blockchain Solana và sau đó khám phá cách SOON giới thiệu UniqueEntry để lưu trữ trạng thái gốc.
Blockchain Solana bao gồm các khe, được tạo ra bởi mô-đun PoH. Mỗi khe chứa nhiều mục, mỗi mục bao gồm ticks và giao dịch. Tại các lớp mạng và lưu trữ, một khe được lưu trữ và truyền bằng cách sử dụng shredsnhư là đơn vị nhỏ nhất. Shreds có thể được chuyển đổi từ và sang các mục nhập.
pub struct Entry {
/// Số lượng băm kể từ ID Nhập trước đó.
pub num_hashes: u64,
/// Băm SHA-256num_hashes
sau ID Đăng nhập trước đó.
pub hash: Hash,
/// Một danh sách không theo thứ tự các giao dịch được quan sát trước khi mã ID nhập
/// được tạo ra. Chúng có thể đã được quan sát trước một Entry ID trước đó nhưng đã được
/// pushed back into this list to ensure deterministic interpretation of the ledger.
pub transactions: Vec
}
Chúng tôi đã theo dõi cấu trúc blockchain được tạo ra bởi PoH và giữ cấu trúc shred, cho phép chúng tôi tái sử dụng lớp lưu trữ hiện tại của Solana, lớp mạng, và khung công việc RPC. Để lưu trữ dữ liệu bổ sung trên blockchain L2, chúng tôi đã giới thiệu UniqueEntry. Đặc điểm này cho phép chúng tôi tùy chỉnh dữ liệu đầu vào và xác định các quy tắc xác thực độc lập cho dữ liệu.
pub const UNIQUE_ENTRY_NUM_HASHES_FLAG: u64 = 0x8000_0000_0000_0000;
/// Unique entry là một loại mục nhập đặc biệt. Đây là một lựa chọn hữu ích khi chúng ta cần lưu trữ một số dữ liệu trong
/// blockstore nhưng không muốn xác minh nó.
///
/// Cấu trúc của số lượng hashes
là:
/// |…1 bit…|…63 bit…|
/// \ _ _/
/// \ \
/// cờ trường tùy chỉnh
pub trait UniqueEntry: Sized {
fn encode_to_entries(&self) -> Vec
fn giải mã từ các mục nhập,
mục nhập: impl IntoIterator<Mục = Nhập khẩu>,
) -> Kết quả
}
pub fn unique_entry(custom_field: u64, hash: Hash) -> Entry {
Entry {
num_hashes: num_hashes(custom_field), hash, transactions: vec! [],
}
pub fn num_hashes(custom_field: u64) -> u64 {
assert!(custom_field
UNIQUE_ENTRY_NUM_HASHES_FLAG | custom_field
}
pub fn is_unique(entry: &Entry) -> bool {
entry.num_hashes & UNIQUE_ENTRY_NUM_HASHES_FLAG != 0
}
Trong UniqueEntry, num_hashes được sử dụng như một bố cục bit, trong đó cờ bit đầu tiên được sử dụng để phân biệt giữa một Entry và một Unique Entry, và 63 bit tiếp theo được sử dụng để xác định loại dữ liệu. Trường hash được sử dụng như payload, chứa dữ liệu tùy chỉnh yêu cầu.
Hãy xem một ví dụ về việc sử dụng ba mục nhập duy nhất để lưu trữ slot hash, state root và withdraw root.
/// MPT root unique entry.
pub struct MptRoot {
pub slot: Khe,
pub state_root: B256,
pub withdrawal_root: B256,
}
impl UniqueEntry cho MptRoot {
fn encode_to_entries(&self) -> Vec
let slot_entry = unique_entry(0, slot_to_hash(self.slot)); let state_root_entry = unique_entry(1, self.state_root.0.into()); let withdrawal_root_entry = unique_entry(2, self.withdrawal_root.0.into()); vec![slot_entry, state_root_entry, withdrawal_root_entry]
Không thể dịch văn bản. Vui lòng cung cấp văn bản hợp lệ để dịch.
fn giải mã từ các mục nhập,
entries: impl IntoIterator
) -> Kết quả
let mut entries = entries.into_iter(); let entry = entries.next().ok_or(UniqueEntryError::NoMoreEntries)?; let slot = hash_to_slot(entry.hash); let entry = entries.next().ok_or(UniqueEntryError::NoMoreEntries)?; let state_root = B256::from(entry.hash.to_bytes()); let entry = entries.next().ok_or(UniqueEntryError::NoMoreEntries)?; let withdrawal_root = B256::from(entry.hash.to_bytes()); Ok(MptRoot { slot, state_root, withdrawal_root, })
}
}
Vì UniqueEntry định nghĩa lại ngữ nghĩa của num_hashes, nó không thể được xử lý trong giai đoạn xác minh PoH. Do đó, ở đầu quá trình xác minh, chúng tôi trước tiên lọc ra các mục nhập duy nhất và chuyển chúng vào một luồng xác minh tùy chỉnh dựa trên loại dữ liệu của chúng. Các mục nhập thông thường còn lại tiếp tục qua quá trình xác minh PoH ban đầu.
Cầu nối bản địa là một phần quan trọng của cơ sở hạ tầng cho các giải pháp Layer 2, chịu trách nhiệm về truyền thông tin giữa L1 và L2. Tin nhắn từ L1 đến L2 được gọi là giao dịch gửi tiền, trong khi tin nhắn từ L2 đến L1 được gọi là giao dịch rút tiền.
Các giao dịch nạp tiền thường được xử lý bởi gateđường ống tạo ravà chỉ yêu cầu người dùng gửi một giao dịch duy nhất trên L1. Tuy nhiên, giao dịch rút tiền lại phức tạp hơn và yêu cầu người dùng gửi ba giao dịch để hoàn thành quy trình:
Bằng chứng bao gồm của giao dịch rút tiền đảm bảo rút tiền đã xảy ra trên L2, tăng cường đáng kể bảo mật của cầu nối chuẩn.
Trong OP Stack, băm giao dịch rút tiền của người dùng được lưu trữ trong biến trạng thái tương ứng vớiOptimismPortal contract. Giao diện RPC eth_getProof sau đó được sử dụng để cung cấp cho người dùng một chứng minh bao gồm giao dịch rút tiền cụ thể.
Khác với EVM, dữ liệu hợp đồng SVM được lưu trữ trong trường dữ liệu của tài khoản, và tất cả các loại tài khoản tồn tại ở cùng một cấp độ thứ bậc.
SOON đã giới thiệu một chương trình cầu nối native: Cầu1111111111111111111111111111111111111. Khi một người dùng khởi tạo giao dịch rút tiền, chương trình cầu nối tạo ra một chỉ số duy nhất toàn cầu cho mỗi giao dịch rút tiền và sử dụng chỉ số này như một hạt giống để tạo ra một mớiTài khoản Phát sinh Chương trìnhđể lưu trữ giao dịch rút tương ứng (PDA).
pub struct WithdrawalTransaction {
/// quầy rút tiền
pub nonce: U256,
/// người dùng muốn rút tiền
pub sender: Pubkey,
/// địa chỉ người dùng trong L1
pub target: Địa chỉ,
/// rút số tiền trong lamports
giá trị pub: U256,
/// giới hạn gas trong L1
pub gas_limit: U256,
/// thông tin rút tiền trong L1
dữ liệu pub: L1WithdrawalCalldata,
}
Chúng tôi đã xác định cấu trúc WithdrawalTransaction để lưu trữ giao dịch rút tiền trong trường dữ liệu của PDA.
Thiết kế này hoạt động tương tự như OP Stack. Khi outputRoot chứa giao dịch rút tiền được gửi đến L1, người dùng có thể gửi một chứng minh bao gồm cho giao dịch rút tiền đến L1 để bắt đầu giai đoạn thách thức.
Sau khi người đề xuất gửi outputRoot đến L1, điều này có nghĩa là trạng thái của L2 đã được giải quyết. Nếu một người thách thức phát hiện ra rằng người đề xuất đã gửi một trạng thái không chính xác, họ có thể khởi tạo một thách thức để bảo vệ quỹ trong cầu.
Một trong những khía cạnh quan trọng nhất của việc xây dựng một hệ thống chống lỗi là cho phép blockchain chuyển từ trạng thái S1 sang trạng thái S2 một cách không có trạng thái. Điều này đảm bảo rằng hợp đồng trọng tài trên L1 có thể phát lại các chỉ thị của chương trình một cách không có trạng thái để thực hiện trọng tài.
Tuy nhiên, ở đầu quá trình này, thử thách phải chứng minh rằng tất cả các đầu vào ban đầu trong trạng thái S1 là hợp lệ. Các đầu vào ban đầu này bao gồm trạng thái của các tài khoản tham gia (ví dụ: lamports, dữ liệu, chủ sở hữu, v.v.). Khác với EVM, SVM tự nhiên tách biệt trạng thái tài khoản và tính toán. Tuy nhiên, API SVM của Anzacho phép tài khoản được chuyển vào SVM thông qua TransactionProcessingCallback trait, như được hiển thị dưới đây.
pub trait TransactionProcessingCallback {
fn account_matches_owners(&self, account: &Pubkey, owners: &[Pubkey]) -> Option
fn get_account_shared_data(&self, pubkey: &Pubkey) -> Option;
fn add_builtin_account(&self, _name: &str, _program_id: &Pubkey) {}
}
Do đó, chúng ta chỉ cần sử dụng trạng thái S1 cùng với các chứng minh sự bao gồm của các tài khoản đầu vào để xác minh tính hợp lệ của đầu vào của chương trình thử thách.
SOON đang đánh dấu một mốc quan trọng cho sự phát triển của hệ sinh thái SVM. Bằng cách tích hợp merklization, SOON giải quyết vấn đề thiếu gốc trạng thái toàn cầu của Solana, cho phép các tính năng cần thiết như chứng minh sự bao gồm cho chứng minh lỗi, rút tiền an toàn và thực thi không trạng thái.
Ngoài ra, thiết kế merklization của SOON trong SVM có thể cho phép các máy khách nhẹ trên các chuỗi dựa trên SVM, mặc dù Solana hiện tại không hỗ trợ máy khách nhẹ. Có thể thậm chí một số phần của thiết kế có thể hỗ trợ mang máy khách nhẹ đến chuỗi chính cũng được.
Sử dụng Merkle Patricia Tries (MPT) cho quản lý trạng thái, SOON phù hợp với cơ sở hạ tầng của Ethereum, nâng cao khả năng tương tác và tiến bộ các giải pháp SVM dựa trên L2. Đổi mới này tăng cường hệ sinh thái SVM bằng cách cải thiện bảo mật, khả năng mở rộng và tương thích, đồng thời thúc đẩy sự phát triển của các ứng dụng phi tập trung.