Мерклізація SVM на SOON

Розширений1/27/2025, 12:53:10 AM
SOON Network вводить структуру дерева Меркла в межах віртуальної машини Solana (SVM), щоб вирішити проблему відсутності коренів глобального стану. Це покращення посилює можливості SVM у підтвердженні цілісності, доказах шахрайства та міжшарових операціях у системі агрегації. Зануривши корінь стану безпосередньо в блокчейн SVM, SOON покращує безпеку та масштабованість, забезпечуючи міцну підтримку для агрегації SVM.

Віртуальна машина Solana (SVM) стає широко використовуваною як шар виконання для різних рішень Layer-2 (L2). Однак ключовим обмеженням у початковому дизайні SVM є невизначеність його глобального кореня стану. Це створює значні виклики для систем rollup, де глобальні корені стану є критичними для забезпечення цілісності, підтримки доказів шахрайства та підтримки операцій міжшарового рівня.

У роллапі пропонент періодично надсилає кореневий стан L2 (корінь Меркла) на рівень-1 (L1), встановлюючи контрольні точки для ланцюга L2. Ці контрольні точки дозволяють докази включення для будь-якого облікового стану, забезпечуючи безстанційне виконання від однієї контрольної точки до іншої. Докази шахрайства ґрунтуються на цьому механізмі, оскільки учасники можуть надавати докази включення для перевірки дійсних вхідних даних під час суперечок. Крім того, дерева Меркла підвищують безпеку канонічних мостів, дозволяючи користувачам генерувати докази включення для транзакцій виведення, забезпечуючи бездовіркові взаємодії між L2 та L1.

Для вирішення цих викликів, SOON Networkвводить дерева Меркла в виконавчий шар SVM, що дозволяє клієнтам надавати докази включення. Незабаром інтегрується з Доказом-про-історію, використовуючи унікальні записи для вбудовування коренів стану безпосередньо в ланцюги блоків на основі SVM. З цим інноваційним рішенням стек SOON може підтримувати нові ролапи на основі SVM з підвищеною безпекою, масштабованістю та корисністю.

Проблема мерклізації Солани

Solana завжди була спроектована з високою пропускною здатністю як основним завданням, що вимагало обдуманих компромісів у дизайні — особливо під час свого раннього розвитку — для досягнення нової продуктивності. Один з найвпливовіших рішень серед цих компромісів стосувався того, як і коли Солана мерклізує свій стан.

У кінцевому підсумку це рішення створило значні виклики для клієнтів у доведенні глобального стану, а також включення транзакцій та простої перевірки оплати (SPV). Відсутність постійно-хешованого кореня стану, що представляє merklized SVM state, утруднює значно проекти, такі як легкі клієнти та rollups.

Давайте розглянемо, як виконується мерклізація на інших ланцюгах, а потім визначимо виклики, що виникають внаслідок архітектури протоколу Solana.

Дерева Меркла на Біткойні

На Bitcoin транзакції зберігаються в блоках за допомогою Merkle дерево, чиє коріння зберігається в заголовок блокуПротокол Bitcoin буде хешувати входи та виходи транзакції (а також деяку іншу метадані) вІдентифікатор транзакції(TxID). Для підтвердження стану на Bitcoin користувач може просто обчислити доказ Меркла, щоб перевірити TxID відносно кореня Меркла блоку.

Цей процес верифікації також підтверджує стан, оскільки ідентифікатор транзакції є унікальним для певного набору входів та виходів, обидва з яких відображають зміни стану адреси. Зауважте, що транзакції Bitcoin також можуть містити Сценарії Taproot, які створюють вихідні транзакції, які можна перевірити під час перевірки, часто за допомогою повторного запуску сценарію за допомогою вхідних даних транзакції та свідчень сценарію та перевірки на відповідність її вихідним даним.

Merkle Trees на Ethereum

Подібно до Bitcoin, Ethereum зберігає транзакції за допомогою спеціальної структури даних (походить від дерева Меркля), яку називаютьMerkle Patricia Trie(MPT). Ця структура даних розроблена для швидких оновлень та оптимізації великих наборів даних. Це відбувається через те, що в Ethereum значно більше входів та виходів для управління, ніж у Bitcoin.

Ethereum Віртуальна Машина(EVM) виступає як глобальна машина стану. EVM суттєво є великою розподіленою обчислювальною середовища, яка підтримує виконуванийсмарт-контракти, кожен з яких резервує власний адресний простір у глобальній пам'яті. В результаті клієнти, які бажають перевірити стан на Ethereum, повинні враховувати не лише результат транзакції (журнали, код повернення і т.д.), а також зміни глобального стану в результаті транзакції.

На щастя, EVM розумно використовує три важливі структури триєв, які зберігають свої корені в кожному заголовку блоку.

  • Становий трие: Гігантське сховище ключ-значення всього стану на Ethereum, включаючи кожну адресу Ethereum та дані, збережені в кожному обліковому записі. Для смарт-контрактів ці облікові записи зберігають ще один триєм, який називається Сховище trie, який є ще однією картою ключ-значення всіх даних розумного контракту для його адресного простору.
  • Дерево транзакцій: Ключово-значення зберігання всіх транзакцій в блоках, де ключ - це ідентифікатор транзакції, а значення - це дані транзакції.
  • Дерево чеків: Trie, що містить квитанції (стан, події) з кожної транзакції в блоку, зхешовані за індексом кожної транзакції в блоку. Кожен квитанція містить інформацію про виконання транзакції, включаючи хеш післястану транзакції в дереві стану.

З урахуванням транзакції клієнт може довести її включення в блок, оцінивши кореневий хеш дерева транзакцій (як у Bitcoin), її результат, оцінивши хеш квитанції, та зміни глобального стану, оцінивши хеш стану.

Дерева Меркла на Solana

Однією з причин високої пропускної здатності Solana є те, що у неї немає багаторівневої структури, яку має Ethereum. Лідери Solana дійсно обчислюють дерева Меркля при створенні блоків, але вони мають іншу структуру, ніж ті, що є в EVM. Нажаль, ось де пояснюється проблема для розширень на основі SVM.

Solana мерклізує транзакції в те, що називається записами, і в одному слоті може бути кілька записів; отже, кілька коренів транзакцій на блок. Крім того, Solana обчислює корінь Меркла стану рахунку лише один раз за епоху (близько 2,5 днів), і цей корінь недоступний в реєстрі.

Фактично заголовки блоків Solana не містять жодних коренів Меркла взагалі. Замість цього вони містять попередній та поточнийблокхеш, яке обчислюється через Solana’s Доказ історіїАлгоритм Proof of History (PoH). PoH вимагає від валідаторів безперервно реєструвати «тики», рекурсивно хешуючи записи блоків, які можуть бути порожніми або містити пакети транзакцій. Останній тік (хеш) алгоритму PoH - це блоковий хеш цього блоку.

Проблема з доказом історії полягає в тому, що дуже важко довести стан з blockhash. Solana розроблена для трансляції хешів PoH для збереження свого поняття пройденого часу. Коренева транзакція доступна лише для кроку PoH, який містив запис з транзакціями, а не для всього блоку, і жодний корінь стану не зберігається в жодному записі.

Однак існує інший хеш, який клієнти можуть використовувати: банківський хеш. Іноді його називають слот-хешем, банківські хеші доступні вSlotHashes sysvarобліковий запис, який може бути запитаний клієнтом. Хеш банку створюється для кожного блоку (слоту) з кількох входів:

  • Попередній хеш банку.
  • Хеш зміни стану облікового запису.
  • Кількість підписів транзакцій в банку, в байтах.
  • Хеш-блок цього банку.
  • Лише один раз на епоху, хеш всіх рахунків у базі даних рахунків.
  • Лише коли кластер перезапуститься, хеш будь-яких хардфорків, спричинених перезапуском кластера.

Як можна побачити, хеш банку перевантажений кількома входами хешу, що ускладнює клієнтам спроби доведення інформації про транзакції або стан. Крім того, тільки хеш банку для банку, який виконав "хеш епохи облікового запису" - хеш всіх облікових записів один раз за епоху - матиме цей певний корінь у ньому. Крім того, обліковий запис SlotHashes sysvar обрізаний до останніх 512 хешів банку.

Рішення Merklization компанії SOON

МЕРЕЖА SOON - це SVM L2 на вершині Ethereum. Під час інтеграції merklization у НЕДОВГО, ми надали перевагу використанню перевірених та добре встановлених рішень на користь стабільності, а не винаходити колесо заново. При вирішенні, яку структуру даних або хеш-алгоритми використовувати, ми врахували їх сумісність з L1 контрактами Стек оптимізму, їх здатність інтегруватися безперешкодно в архітектуру Solana, та чи вони зможуть досягти високої продуктивності в рамках облікової моделі Solana.

Ми виявили, що при збільшенні кількості облікових записів модель сховища Меркла-Патріції-Трі (MPT) на основіLSM-Деревоспричиняв більшу ампліфікацію читання/запису диска, що призводило до втрат продуктивності. У кінцевому підсумку ми вирішили інтегрувати Erigon MPTпобудовавши на відмінній роботі з Rust, виконаній rETHteam та додавання підтримки для моделі облікового запису Solana.

Архітектура

Як вже зазначалося, дерево стану SOON - це MPT, побудоване для підтримки облікових записів Solana. Таким чином, ми визначили тип облікового запису, сумісний з SVM, щоб служити даними кожного листового вузла.

struct TrieSolanaAccount {

lamports: u64,

дані: Vec,

виконуваний: логічний,

rent_epoch: u64,

власник: Pubkey,

}

Для того щоб модуль MPT міг підписуватися на останній стан облікових записів SVM в реальному часі, ми ввели сповіщення про обліковий запис. Під час Банківського Етапу сповіщення про обліковий запис повідомляє модуль MPT про зміни стану облікового запису, і MPT поетапно оновлює ці зміни в структурі триєв.

Важливо зауважити, що модуль MPT оновлює свої піддерева лише під час кожних 50 слотів і не обчислює корінь стану в кінці кожного слоту. Цей підхід прийнято з двох причин. По-перше, обчислення кореня стану для кожного слоту значно вплинуло б на продуктивність. По-друге, корінь стану потрібен лише тоді, коли пропонент подає outputRootна рівень L1. Тому його потрібно обчислювати періодично, на основі частоти подання пропонента.

outputRoot = keccak256(version, state_root, withdraw_root, l2_block_hash)

Модуль MPT SOON одночасно підтримує два типи дерев структур: дерево стану для глобального стану та дерево виведення для виведення транзакцій. Ініціатор періодично генерує вихідний корінь за допомогою кореня стану та кореня виведення, та подає його на L1.

Наразі SOON обчислює кореневий стан та кореневе вилучення один раз кожні 450 слотів і додає його до L2 блокчейну. У результаті можна забезпечити послідовність даних MPT на інших вузлах у мережі. Однак структура блоку Solana не містить заголовка блоку, що означає, що немає місця для зберігання кореня стану. Давайте уважно розглянемо базову структуру блокчейну Solana, а потім дослідимо, як SOON вводить UniqueEntry для зберігання кореня стану.

Блокчейн Solana складається з слотів, які генеруються модулем PoH. Слот містить кілька записів, кожен з яких містить такти і транзакції. На рівнях мережі та сховища слот зберігається та передається за допомогою шматкияк найменша одиниця. Фрагменти можуть бути конвертовані в записи та з них.

[похід (Серіалізувати, Десеріалізувати, Наладити, За умовчанням, Порівняння, Рівність, Клонувати)]

pub struct Entry {

Кількість хешів з моменту попереднього ID запису.

pub num_hashes: u64,

/// Хеш SHA-256num_hashesпісля попереднього ідентифікатора входу.

pub хеш: Хеш,

/// Невпорядкований список транзакцій, які були спостережені до того, як було зареєстровано ідентифікатор запису

/// згенеровано. Їх можуть було спостерігати до попереднього ID запису, але

/// pushed back into this list to ensure deterministic interpretation of the ledger.

публікації угод: Вектор ,

}

Ми використовували структуру блокчейну, згенеровану PoH, та зберігали структуру shred, що дозволило нам використовувати існуючий сховищний шар, мережевий шар та каркас RPC Solana. Щоб зберігати додаткові дані на L2 блокчейні, ми ввели унікальний запис. Ця властивість дозволяє нам настроювати навантаження запису та визначати незалежні правила перевірки для даних.

pub const UNIQUE_ENTRY_NUM_HASHES_FLAG: u64 = 0x8000_0000_0000_0000;

/// Унікальний запис - це спеціальний тип запису. Це корисно, коли нам потрібно зберегти деякі дані в

/// blockstore, але не хочу його перевіряти.

///

/// The layout of num_hashes є:

/// |…1 біт…|…63 біт…|

/// \ _ _/

/// \ \

Спеціальне поле прапорця

pub trait UniqueEntry: Sized {

fn encode_to_entries(&self) -> Vec;

fn декодувати_з_записів(

   записи: impl IntoIterator<Пункт = Вхід>,

) -> Результат;

}

pub fn unique_entry(custom_field: u64, hash: Hash) -> Entry {

Запис {

   num_hashes: num_hashes(custom_field),   hash,   transactions: vec![],

}

}

pub fn num_hashes(custom_field: u64) -> u64 {

assert!(custom_field < (1 << 63));

UNIQUE_ENTRY_NUM_HASHES_FLAG | custom_field

}

pub fn is_unique(entry: &Entry) -> bool {

entry.num_hashes & UNIQUE_ENTRY_NUM_HASHES_FLAG != 0

}

У UniqueEntry num_hashes використовується як розклад бітів, де перший бітовий прапор використовується для відмінності між Entry та Unique Entry, а наступні 63 біти використовуються для визначення типу полезної навантаження. Поле hash служить як полезне навантаження, що містить необхідні користувацькі дані.

Давайте розглянемо приклад використання трьох унікальних записів для збереження хешу слоту, кореня стану та кореня виведення.

Унікальний запис кореня MPT.

[derive(Default, Debug, Clone, PartialEq, Eq)]

pub struct MptRoot {

pub slot: Слот,

pub state_root: B256,

withdrawal_root пабу: B256,

}

impl UniqueEntry для 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]

}

fn decode_from_entries(
записи: impl IntoIterator,
) -> result {

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,   })

}
}

Оскільки UniqueEntry переозначає семантику num_hashes, його не можна обробляти під час етапу перевірки PoH. Тому на початку процесу перевірки ми спочатку фільтруємо унікальні записи та направляємо їх на спеціальний потік перевірки на основі типу їхнього навантаження. Решта звичайних записів продовжують проходити через оригінальний процес перевірки PoH.

Виведення та природне мостіння

Місцевий міст є важливою частиною інфраструктури для рішень на рівні 2, відповідальний за передачу повідомлень між L1 та L2. Повідомлення з L1 на L2 називаються транзакціями депозиту, тоді як повідомлення з L2 на L1 називаються транзакціями зняття.

Транзакції з депозитами зазвичай обробляються похідний конвеєрі потребують від користувача лише одну транзакцію на рівні L1. Однак транзакції на виведення коштів є складнішими і потребують від користувача відправити три транзакції для завершення процесу:

  1. Спочатку користувач повинен надіслати початкову транзакцію виведення на рівні L2.
  2. Як тільки вихідний корінь, що містить цю початкову транзакцію виведення, буде відправлений пропонентом до L1, користувачу потрібно відправити доказ про включення транзакції виведення до L1. Після успішної перевірки починається період виклику.
  3. Після закінчення періоду виклику користувач відправляє транзакцію на завершення, щоб завершити весь процес виведення.

Включення доказу транзакції виведення коштів гарантує, що виведення відбулося на L2, що значно підвищує безпеку канонічного мосту.

У стеку OP хеш транзакції виведення користувача зберігається в становій змінній, що відповідаєOptimismPortalУгода. Інтерфейс RPC eth_getProof потім використовується для надання користувачам доказу включення для конкретної транзакції зняття коштів.

На відміну від EVM, дані контракту SVM зберігаються в полі даних облікових записів, і всі види облікових записів існують на тому самому рівні ієрархії.

SOON запровадив програму місцевого моста: Bridge1111111111111111111111111111111111111. Кожного разу, коли користувач ініціює транзакцію зняття коштів, програма моста генерує глобально унікальний індекс для кожної транзакції зняття коштів і використовує цей індекс як початкові дані для створення нового Обліковий запис, отриманий в програмі(PDA) щоб зберегти відповідну операцію зняття коштів.

[derive(Clone, Copy, Debug, PartialEq)]

pub struct ВилученняТранзакція {

/// лічильник виведення

pub nonce: U256,

/// користувач, який хоче вивести

відправник: Pubkey,

/// адреса користувача в L1

публічна ціль: Адреса,

/// зняти суму в лампортах

pub value: U256,

/// ліміт газу в L1

pub газ_ліміт: U256,

/// виведення calldata в L1

публічні дані: L1WithdrawalCalldata,

}

Ми визначили структуру WithdrawalTransaction для зберігання операцій зняття коштів в полі даних PDA.

Ця конструкція працює аналогічно до OP Stack. Як тільки outputRoot, який містить транзакцію виведення, подається на L1, користувач може подати доказ включення для транзакції виведення на L1 для початку періоду виклику.

Докази несправностей

Після того, як пропонент надсилає outputRoot на L1, це означає, що стан L2 було врегульовано. Якщо викликач виявляє, що пропонент подав неправильний стан, вони можуть ініціювати виклик для захисту коштів на мосту.

Один з найважливіших аспектів побудови надійної системи полягає в тому, щоб забезпечити можливість блокчейну переходити зі стану S1 до стану S2 в безстандартний спосіб. Це забезпечує, що контракт арбітра на L1 може безстандартно відтворити інструкції програми для здійснення арбітражу.

Проте, на початку цього процесу викликач повинен довести, що всі початкові входи в стані S1 є дійсними. Ці початкові входи включають стани участь у рахунках (наприклад, лампорти, дані, власник тощо). На відміну від EVM, SVM природно відокремлює стан рахунку від обчислення. Однак, SVM API Anzaдозволяє передавати облікові записи в SVM через трейт TransactionProcessingCallback, як показано нижче.

pub трайт 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) {}

}

Таким чином, нам потрібно лише використовувати стан S1 разом з доказами включення вхідних рахунків, щоб перевірити правильність введених даних виклику програми.

Висновок

SOON відзначає ключову віху для розвитку екосистеми SVM. Інтегруючи мерклізацію, SOON вирішує проблему відсутності глобального кореня стану у Solana, що дозволяє використовувати важливі функції, такі як докази включення для доказів про несправність, безпечні виведення та безстатеве виконання.

Крім того, дизайн мерклізації в SOON у межах SVM може дозволити легким клієнтам на ланцюгах, що базуються на SVM, навіть якщо сама Solana наразі не підтримує легкі клієнти. Навіть можливо, що деякі елементи дизайну можуть допомогти введенню легких клієнтів на головний ланцюг також.

Використання дерев Меркла-Патріції (MPT) для управління станом, SOON вирівнюється з інфраструктурою Ethereum, покращуючи міжоперабельність та розвиваючи рішення на основі SVM L2. Ця інновація посилює екосистему SVM, покращуючи безпеку, масштабованість та сумісність, сприяючи при цьому росту децентралізованих додатків.

Застереження:

  1. Ця стаття перепечатана з [ Середній]. Усі авторські права належать оригінальному автору [@0xandrewz та @realbuffalojoe]. Якщо є заперечення щодо цього перевидання, будь ласка, зв'яжіться з Gate Learnкоманда, і вони швидко з цим впораються.
  2. Відповідальність за відмову: Погляди та думки, висловлені в цій статті, належать виключно автору і не становлять інвестиційні поради.
  3. Команда Gate Learn переклала статтю на інші мови. Копіювання, поширення або плагіат перекладених статей заборонені, якщо не зазначено інше.

Мерклізація SVM на SOON

Розширений1/27/2025, 12:53:10 AM
SOON Network вводить структуру дерева Меркла в межах віртуальної машини Solana (SVM), щоб вирішити проблему відсутності коренів глобального стану. Це покращення посилює можливості SVM у підтвердженні цілісності, доказах шахрайства та міжшарових операціях у системі агрегації. Зануривши корінь стану безпосередньо в блокчейн SVM, SOON покращує безпеку та масштабованість, забезпечуючи міцну підтримку для агрегації SVM.

Віртуальна машина Solana (SVM) стає широко використовуваною як шар виконання для різних рішень Layer-2 (L2). Однак ключовим обмеженням у початковому дизайні SVM є невизначеність його глобального кореня стану. Це створює значні виклики для систем rollup, де глобальні корені стану є критичними для забезпечення цілісності, підтримки доказів шахрайства та підтримки операцій міжшарового рівня.

У роллапі пропонент періодично надсилає кореневий стан L2 (корінь Меркла) на рівень-1 (L1), встановлюючи контрольні точки для ланцюга L2. Ці контрольні точки дозволяють докази включення для будь-якого облікового стану, забезпечуючи безстанційне виконання від однієї контрольної точки до іншої. Докази шахрайства ґрунтуються на цьому механізмі, оскільки учасники можуть надавати докази включення для перевірки дійсних вхідних даних під час суперечок. Крім того, дерева Меркла підвищують безпеку канонічних мостів, дозволяючи користувачам генерувати докази включення для транзакцій виведення, забезпечуючи бездовіркові взаємодії між L2 та L1.

Для вирішення цих викликів, SOON Networkвводить дерева Меркла в виконавчий шар SVM, що дозволяє клієнтам надавати докази включення. Незабаром інтегрується з Доказом-про-історію, використовуючи унікальні записи для вбудовування коренів стану безпосередньо в ланцюги блоків на основі SVM. З цим інноваційним рішенням стек SOON може підтримувати нові ролапи на основі SVM з підвищеною безпекою, масштабованістю та корисністю.

Проблема мерклізації Солани

Solana завжди була спроектована з високою пропускною здатністю як основним завданням, що вимагало обдуманих компромісів у дизайні — особливо під час свого раннього розвитку — для досягнення нової продуктивності. Один з найвпливовіших рішень серед цих компромісів стосувався того, як і коли Солана мерклізує свій стан.

У кінцевому підсумку це рішення створило значні виклики для клієнтів у доведенні глобального стану, а також включення транзакцій та простої перевірки оплати (SPV). Відсутність постійно-хешованого кореня стану, що представляє merklized SVM state, утруднює значно проекти, такі як легкі клієнти та rollups.

Давайте розглянемо, як виконується мерклізація на інших ланцюгах, а потім визначимо виклики, що виникають внаслідок архітектури протоколу Solana.

Дерева Меркла на Біткойні

На Bitcoin транзакції зберігаються в блоках за допомогою Merkle дерево, чиє коріння зберігається в заголовок блокуПротокол Bitcoin буде хешувати входи та виходи транзакції (а також деяку іншу метадані) вІдентифікатор транзакції(TxID). Для підтвердження стану на Bitcoin користувач може просто обчислити доказ Меркла, щоб перевірити TxID відносно кореня Меркла блоку.

Цей процес верифікації також підтверджує стан, оскільки ідентифікатор транзакції є унікальним для певного набору входів та виходів, обидва з яких відображають зміни стану адреси. Зауважте, що транзакції Bitcoin також можуть містити Сценарії Taproot, які створюють вихідні транзакції, які можна перевірити під час перевірки, часто за допомогою повторного запуску сценарію за допомогою вхідних даних транзакції та свідчень сценарію та перевірки на відповідність її вихідним даним.

Merkle Trees на Ethereum

Подібно до Bitcoin, Ethereum зберігає транзакції за допомогою спеціальної структури даних (походить від дерева Меркля), яку називаютьMerkle Patricia Trie(MPT). Ця структура даних розроблена для швидких оновлень та оптимізації великих наборів даних. Це відбувається через те, що в Ethereum значно більше входів та виходів для управління, ніж у Bitcoin.

Ethereum Віртуальна Машина(EVM) виступає як глобальна машина стану. EVM суттєво є великою розподіленою обчислювальною середовища, яка підтримує виконуванийсмарт-контракти, кожен з яких резервує власний адресний простір у глобальній пам'яті. В результаті клієнти, які бажають перевірити стан на Ethereum, повинні враховувати не лише результат транзакції (журнали, код повернення і т.д.), а також зміни глобального стану в результаті транзакції.

На щастя, EVM розумно використовує три важливі структури триєв, які зберігають свої корені в кожному заголовку блоку.

  • Становий трие: Гігантське сховище ключ-значення всього стану на Ethereum, включаючи кожну адресу Ethereum та дані, збережені в кожному обліковому записі. Для смарт-контрактів ці облікові записи зберігають ще один триєм, який називається Сховище trie, який є ще однією картою ключ-значення всіх даних розумного контракту для його адресного простору.
  • Дерево транзакцій: Ключово-значення зберігання всіх транзакцій в блоках, де ключ - це ідентифікатор транзакції, а значення - це дані транзакції.
  • Дерево чеків: Trie, що містить квитанції (стан, події) з кожної транзакції в блоку, зхешовані за індексом кожної транзакції в блоку. Кожен квитанція містить інформацію про виконання транзакції, включаючи хеш післястану транзакції в дереві стану.

З урахуванням транзакції клієнт може довести її включення в блок, оцінивши кореневий хеш дерева транзакцій (як у Bitcoin), її результат, оцінивши хеш квитанції, та зміни глобального стану, оцінивши хеш стану.

Дерева Меркла на Solana

Однією з причин високої пропускної здатності Solana є те, що у неї немає багаторівневої структури, яку має Ethereum. Лідери Solana дійсно обчислюють дерева Меркля при створенні блоків, але вони мають іншу структуру, ніж ті, що є в EVM. Нажаль, ось де пояснюється проблема для розширень на основі SVM.

Solana мерклізує транзакції в те, що називається записами, і в одному слоті може бути кілька записів; отже, кілька коренів транзакцій на блок. Крім того, Solana обчислює корінь Меркла стану рахунку лише один раз за епоху (близько 2,5 днів), і цей корінь недоступний в реєстрі.

Фактично заголовки блоків Solana не містять жодних коренів Меркла взагалі. Замість цього вони містять попередній та поточнийблокхеш, яке обчислюється через Solana’s Доказ історіїАлгоритм Proof of History (PoH). PoH вимагає від валідаторів безперервно реєструвати «тики», рекурсивно хешуючи записи блоків, які можуть бути порожніми або містити пакети транзакцій. Останній тік (хеш) алгоритму PoH - це блоковий хеш цього блоку.

Проблема з доказом історії полягає в тому, що дуже важко довести стан з blockhash. Solana розроблена для трансляції хешів PoH для збереження свого поняття пройденого часу. Коренева транзакція доступна лише для кроку PoH, який містив запис з транзакціями, а не для всього блоку, і жодний корінь стану не зберігається в жодному записі.

Однак існує інший хеш, який клієнти можуть використовувати: банківський хеш. Іноді його називають слот-хешем, банківські хеші доступні вSlotHashes sysvarобліковий запис, який може бути запитаний клієнтом. Хеш банку створюється для кожного блоку (слоту) з кількох входів:

  • Попередній хеш банку.
  • Хеш зміни стану облікового запису.
  • Кількість підписів транзакцій в банку, в байтах.
  • Хеш-блок цього банку.
  • Лише один раз на епоху, хеш всіх рахунків у базі даних рахунків.
  • Лише коли кластер перезапуститься, хеш будь-яких хардфорків, спричинених перезапуском кластера.

Як можна побачити, хеш банку перевантажений кількома входами хешу, що ускладнює клієнтам спроби доведення інформації про транзакції або стан. Крім того, тільки хеш банку для банку, який виконав "хеш епохи облікового запису" - хеш всіх облікових записів один раз за епоху - матиме цей певний корінь у ньому. Крім того, обліковий запис SlotHashes sysvar обрізаний до останніх 512 хешів банку.

Рішення Merklization компанії SOON

МЕРЕЖА SOON - це SVM L2 на вершині Ethereum. Під час інтеграції merklization у НЕДОВГО, ми надали перевагу використанню перевірених та добре встановлених рішень на користь стабільності, а не винаходити колесо заново. При вирішенні, яку структуру даних або хеш-алгоритми використовувати, ми врахували їх сумісність з L1 контрактами Стек оптимізму, їх здатність інтегруватися безперешкодно в архітектуру Solana, та чи вони зможуть досягти високої продуктивності в рамках облікової моделі Solana.

Ми виявили, що при збільшенні кількості облікових записів модель сховища Меркла-Патріції-Трі (MPT) на основіLSM-Деревоспричиняв більшу ампліфікацію читання/запису диска, що призводило до втрат продуктивності. У кінцевому підсумку ми вирішили інтегрувати Erigon MPTпобудовавши на відмінній роботі з Rust, виконаній rETHteam та додавання підтримки для моделі облікового запису Solana.

Архітектура

Як вже зазначалося, дерево стану SOON - це MPT, побудоване для підтримки облікових записів Solana. Таким чином, ми визначили тип облікового запису, сумісний з SVM, щоб служити даними кожного листового вузла.

struct TrieSolanaAccount {

lamports: u64,

дані: Vec,

виконуваний: логічний,

rent_epoch: u64,

власник: Pubkey,

}

Для того щоб модуль MPT міг підписуватися на останній стан облікових записів SVM в реальному часі, ми ввели сповіщення про обліковий запис. Під час Банківського Етапу сповіщення про обліковий запис повідомляє модуль MPT про зміни стану облікового запису, і MPT поетапно оновлює ці зміни в структурі триєв.

Важливо зауважити, що модуль MPT оновлює свої піддерева лише під час кожних 50 слотів і не обчислює корінь стану в кінці кожного слоту. Цей підхід прийнято з двох причин. По-перше, обчислення кореня стану для кожного слоту значно вплинуло б на продуктивність. По-друге, корінь стану потрібен лише тоді, коли пропонент подає outputRootна рівень L1. Тому його потрібно обчислювати періодично, на основі частоти подання пропонента.

outputRoot = keccak256(version, state_root, withdraw_root, l2_block_hash)

Модуль MPT SOON одночасно підтримує два типи дерев структур: дерево стану для глобального стану та дерево виведення для виведення транзакцій. Ініціатор періодично генерує вихідний корінь за допомогою кореня стану та кореня виведення, та подає його на L1.

Наразі SOON обчислює кореневий стан та кореневе вилучення один раз кожні 450 слотів і додає його до L2 блокчейну. У результаті можна забезпечити послідовність даних MPT на інших вузлах у мережі. Однак структура блоку Solana не містить заголовка блоку, що означає, що немає місця для зберігання кореня стану. Давайте уважно розглянемо базову структуру блокчейну Solana, а потім дослідимо, як SOON вводить UniqueEntry для зберігання кореня стану.

Блокчейн Solana складається з слотів, які генеруються модулем PoH. Слот містить кілька записів, кожен з яких містить такти і транзакції. На рівнях мережі та сховища слот зберігається та передається за допомогою шматкияк найменша одиниця. Фрагменти можуть бути конвертовані в записи та з них.

[похід (Серіалізувати, Десеріалізувати, Наладити, За умовчанням, Порівняння, Рівність, Клонувати)]

pub struct Entry {

Кількість хешів з моменту попереднього ID запису.

pub num_hashes: u64,

/// Хеш SHA-256num_hashesпісля попереднього ідентифікатора входу.

pub хеш: Хеш,

/// Невпорядкований список транзакцій, які були спостережені до того, як було зареєстровано ідентифікатор запису

/// згенеровано. Їх можуть було спостерігати до попереднього ID запису, але

/// pushed back into this list to ensure deterministic interpretation of the ledger.

публікації угод: Вектор ,

}

Ми використовували структуру блокчейну, згенеровану PoH, та зберігали структуру shred, що дозволило нам використовувати існуючий сховищний шар, мережевий шар та каркас RPC Solana. Щоб зберігати додаткові дані на L2 блокчейні, ми ввели унікальний запис. Ця властивість дозволяє нам настроювати навантаження запису та визначати незалежні правила перевірки для даних.

pub const UNIQUE_ENTRY_NUM_HASHES_FLAG: u64 = 0x8000_0000_0000_0000;

/// Унікальний запис - це спеціальний тип запису. Це корисно, коли нам потрібно зберегти деякі дані в

/// blockstore, але не хочу його перевіряти.

///

/// The layout of num_hashes є:

/// |…1 біт…|…63 біт…|

/// \ _ _/

/// \ \

Спеціальне поле прапорця

pub trait UniqueEntry: Sized {

fn encode_to_entries(&self) -> Vec;

fn декодувати_з_записів(

   записи: impl IntoIterator<Пункт = Вхід>,

) -> Результат;

}

pub fn unique_entry(custom_field: u64, hash: Hash) -> Entry {

Запис {

   num_hashes: num_hashes(custom_field),   hash,   transactions: vec![],

}

}

pub fn num_hashes(custom_field: u64) -> u64 {

assert!(custom_field < (1 << 63));

UNIQUE_ENTRY_NUM_HASHES_FLAG | custom_field

}

pub fn is_unique(entry: &Entry) -> bool {

entry.num_hashes & UNIQUE_ENTRY_NUM_HASHES_FLAG != 0

}

У UniqueEntry num_hashes використовується як розклад бітів, де перший бітовий прапор використовується для відмінності між Entry та Unique Entry, а наступні 63 біти використовуються для визначення типу полезної навантаження. Поле hash служить як полезне навантаження, що містить необхідні користувацькі дані.

Давайте розглянемо приклад використання трьох унікальних записів для збереження хешу слоту, кореня стану та кореня виведення.

Унікальний запис кореня MPT.

[derive(Default, Debug, Clone, PartialEq, Eq)]

pub struct MptRoot {

pub slot: Слот,

pub state_root: B256,

withdrawal_root пабу: B256,

}

impl UniqueEntry для 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]

}

fn decode_from_entries(
записи: impl IntoIterator,
) -> result {

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,   })

}
}

Оскільки UniqueEntry переозначає семантику num_hashes, його не можна обробляти під час етапу перевірки PoH. Тому на початку процесу перевірки ми спочатку фільтруємо унікальні записи та направляємо їх на спеціальний потік перевірки на основі типу їхнього навантаження. Решта звичайних записів продовжують проходити через оригінальний процес перевірки PoH.

Виведення та природне мостіння

Місцевий міст є важливою частиною інфраструктури для рішень на рівні 2, відповідальний за передачу повідомлень між L1 та L2. Повідомлення з L1 на L2 називаються транзакціями депозиту, тоді як повідомлення з L2 на L1 називаються транзакціями зняття.

Транзакції з депозитами зазвичай обробляються похідний конвеєрі потребують від користувача лише одну транзакцію на рівні L1. Однак транзакції на виведення коштів є складнішими і потребують від користувача відправити три транзакції для завершення процесу:

  1. Спочатку користувач повинен надіслати початкову транзакцію виведення на рівні L2.
  2. Як тільки вихідний корінь, що містить цю початкову транзакцію виведення, буде відправлений пропонентом до L1, користувачу потрібно відправити доказ про включення транзакції виведення до L1. Після успішної перевірки починається період виклику.
  3. Після закінчення періоду виклику користувач відправляє транзакцію на завершення, щоб завершити весь процес виведення.

Включення доказу транзакції виведення коштів гарантує, що виведення відбулося на L2, що значно підвищує безпеку канонічного мосту.

У стеку OP хеш транзакції виведення користувача зберігається в становій змінній, що відповідаєOptimismPortalУгода. Інтерфейс RPC eth_getProof потім використовується для надання користувачам доказу включення для конкретної транзакції зняття коштів.

На відміну від EVM, дані контракту SVM зберігаються в полі даних облікових записів, і всі види облікових записів існують на тому самому рівні ієрархії.

SOON запровадив програму місцевого моста: Bridge1111111111111111111111111111111111111. Кожного разу, коли користувач ініціює транзакцію зняття коштів, програма моста генерує глобально унікальний індекс для кожної транзакції зняття коштів і використовує цей індекс як початкові дані для створення нового Обліковий запис, отриманий в програмі(PDA) щоб зберегти відповідну операцію зняття коштів.

[derive(Clone, Copy, Debug, PartialEq)]

pub struct ВилученняТранзакція {

/// лічильник виведення

pub nonce: U256,

/// користувач, який хоче вивести

відправник: Pubkey,

/// адреса користувача в L1

публічна ціль: Адреса,

/// зняти суму в лампортах

pub value: U256,

/// ліміт газу в L1

pub газ_ліміт: U256,

/// виведення calldata в L1

публічні дані: L1WithdrawalCalldata,

}

Ми визначили структуру WithdrawalTransaction для зберігання операцій зняття коштів в полі даних PDA.

Ця конструкція працює аналогічно до OP Stack. Як тільки outputRoot, який містить транзакцію виведення, подається на L1, користувач може подати доказ включення для транзакції виведення на L1 для початку періоду виклику.

Докази несправностей

Після того, як пропонент надсилає outputRoot на L1, це означає, що стан L2 було врегульовано. Якщо викликач виявляє, що пропонент подав неправильний стан, вони можуть ініціювати виклик для захисту коштів на мосту.

Один з найважливіших аспектів побудови надійної системи полягає в тому, щоб забезпечити можливість блокчейну переходити зі стану S1 до стану S2 в безстандартний спосіб. Це забезпечує, що контракт арбітра на L1 може безстандартно відтворити інструкції програми для здійснення арбітражу.

Проте, на початку цього процесу викликач повинен довести, що всі початкові входи в стані S1 є дійсними. Ці початкові входи включають стани участь у рахунках (наприклад, лампорти, дані, власник тощо). На відміну від EVM, SVM природно відокремлює стан рахунку від обчислення. Однак, SVM API Anzaдозволяє передавати облікові записи в SVM через трейт TransactionProcessingCallback, як показано нижче.

pub трайт 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) {}

}

Таким чином, нам потрібно лише використовувати стан S1 разом з доказами включення вхідних рахунків, щоб перевірити правильність введених даних виклику програми.

Висновок

SOON відзначає ключову віху для розвитку екосистеми SVM. Інтегруючи мерклізацію, SOON вирішує проблему відсутності глобального кореня стану у Solana, що дозволяє використовувати важливі функції, такі як докази включення для доказів про несправність, безпечні виведення та безстатеве виконання.

Крім того, дизайн мерклізації в SOON у межах SVM може дозволити легким клієнтам на ланцюгах, що базуються на SVM, навіть якщо сама Solana наразі не підтримує легкі клієнти. Навіть можливо, що деякі елементи дизайну можуть допомогти введенню легких клієнтів на головний ланцюг також.

Використання дерев Меркла-Патріції (MPT) для управління станом, SOON вирівнюється з інфраструктурою Ethereum, покращуючи міжоперабельність та розвиваючи рішення на основі SVM L2. Ця інновація посилює екосистему SVM, покращуючи безпеку, масштабованість та сумісність, сприяючи при цьому росту децентралізованих додатків.

Застереження:

  1. Ця стаття перепечатана з [ Середній]. Усі авторські права належать оригінальному автору [@0xandrewz та @realbuffalojoe]. Якщо є заперечення щодо цього перевидання, будь ласка, зв'яжіться з Gate Learnкоманда, і вони швидко з цим впораються.
  2. Відповідальність за відмову: Погляди та думки, висловлені в цій статті, належать виключно автору і не становлять інвестиційні поради.
  3. Команда Gate Learn переклала статтю на інші мови. Копіювання, поширення або плагіат перекладених статей заборонені, якщо не зазначено інше.
Bắt đầu giao dịch
Đăng ký và giao dịch để nhận phần thưởng USDTEST trị giá
$100
$5500