Буквально вчора сталася шокуюча подія: Linea, Ethereum Рівень 2 рішення, розроблене Consensys, материнською компанією Metamask, було завчасно закрито. Офіційна причина полягала в тому, щоб пом'якшити наслідки хакерського інциденту Velocore. Цей інцидент неминуче нагадує попередній випадок, коли ланцюжок BSC (BNB Chain) також був закритий за офіційної координації, щоб мінімізувати втрати від злому. Ці події часто змушують людей ставити під сумнів децентралізовані цінності, які відстоює Web3.
Основна причина вищезгаданих подій криється в недосконалості інфраструктури, зокрема в її недостатній децентралізації. Якби блокчейн був достатньо децентралізованим, він не зміг би так легко закритися. Завдяки унікальній структурі Ethereum Рівень 2 більшість Рівень 2 рішень покладаються на централізовані секвенсори. Незважаючи на зростаючий дискурс про децентралізовані секвенсери в останні роки, з огляду на призначення і структуру Рівень 2, можна припустити, що Рівень 2 секвенсери навряд чи досягнуть високого рівня децентралізації. Насправді, вони можуть виявитися менш децентралізованими, ніж ланцюжок BSC. Якщо це так, то що робити? Для Рівень 2 найбезпосереднішими ризиками недецентралізованих секвенсерів є брак З спротивом до цензури та жвавості. Якщо є лише кілька суб'єктів, які обробляють транзакції (секвенсери), вони мають абсолютну владу вирішувати, обслуговувати вас чи ні: вони можуть відхилити ваші транзакції за власним бажанням, залишивши вас без права регресу. Вирішення питання З спротивом до цензури в Рівень 2 році, безумовно, є важливою темою. За останні кілька років різні Ethereum Рівень 2 рішення запропонували різні підходи до вирішення цієї проблеми. Наприклад, Loopring, Degate і StarkEx запровадили функції примусового виведення та евакуаційного люка, а Arbitrum та інші Optimistic Rollups впровадили функції Force Inclusion. Ці механізми можуть накладати перевірки на секвенсори, щоб запобігти довільній відмові від транзакцій користувача. У сьогоднішній статті NIC Lin з Тайбейської асоціації Ethereum ділиться власним досвідом, експериментуючи зі стійкими до цензури функціями транзакцій чотирьох основних Rollups і надаючи глибокий аналіз механізму Force Inclusion, зосереджуючись на робочому процесі та операційних методах. Цей аналіз особливо цінний для Ethereum спільноти та великих власників активів.
Цензура спротив в транзакціях має вирішальне значення для будь-якого блокчейну. Якщо блокчейн може довільно цензурувати та відхиляти транзакції користувачів, він нічим не відрізняється від сервера Web2. Транзакційний З спротивом до цензури Ethereum в даний час забезпечується його численними валідатори. Якщо хтось хоче цензурувати транзакцію Боба і запобігти її включенню в блокчейн, йому доведеться або підкупити більшу частину валідатори мережі, або спамити мережу сміттєвими транзакціями, які мають вищі комісії, ніж у Боба, таким чином займаючи простір блоку. Обидва способи надзвичайно затратні.
Примітка: У поточній архітектурі Ethereum Proposer-Builder Separation (PBS) вартість цензури транзакцій значно знижується. Наприклад, ви можете подивитися на частку блоків, які відповідають цензурі OFAC щодо транзакцій Tornado Cash. Поточна З спротивом до цензури спирається на незалежні валідатори та ретранслятори, які знаходяться поза юрисдикцією OFAC та інших державних установ.
А як щодо Rollups? Роллапи не вимагають великої кількості валідатори для забезпечення безпеки. Навіть якщо Rollup має лише одну централізовану сутність (секвенсор), яка виробляє блоки, вона залишається такою ж безпечною, як і рівень 1 (L1). Однак безпека та З спротивом до цензури – це різні речі. Зведення, незважаючи на те, що воно таке ж безпечне, як і Ethereum, все одно може цензурувати транзакцію будь-якого користувача, якщо воно має лише один централізований секвенсор.
Секвенсер може відмовити в обробці транзакції користувача, в результаті чого кошти користувача будуть заблоковані і він не зможе покинути Rollup.
Замість того, щоб вимагати від зведених послідовників великої кількості децентралізованих секвенсорів, ефективніше безпосередньо використовувати З спротивом до цензури рівня 1 (L1):
Оскільки секвенсеру потрібно упаковувати дані про транзакції та надсилати їх до Rollup контракту на L1, ми можемо додати в контракт функцію, яка дозволяє користувачам самостійно вставляти свої транзакції в Rollup-контракт. Цей механізм відомий як «примусове включення». Так само, лонг секвенсор не може цензурувати користувачів на рівні L1, він не може перешкодити користувачам примусово вставляти транзакції на рівні L1. Таким чином, зведення може успадкувати З спротивом до цензури L1.
Секвенсер не може переглядати транзакції L1 користувача, не сплачуючи високу ціну
Якщо транзакції дозволено безпосередньо вписувати в Rollup-контракт за допомогою Force Inclusion (тобто вони набувають чинності негайно), стан Rollup миттєво зміниться. Наприклад, якщо Боб використовує механізм примусового включення, щоб вставити транзакцію, яка переводить Керол 1000 DAI, і транзакція вступає в силу негайно, баланс Боба зменшиться на 1000 DAI, а баланс Керол збільшиться на 1000 DAI в оновленому стані.
Якщо примусове включення дозволяє безпосередньо записувати транзакції в Rollup-контракт і набувати чинності негайно, стан Rollup миттєво зміниться. Якщо секвенсер одночасно збирає поза блокчейном транзакції та готується відправити наступну партію до Rollup контракту, він може бути порушений примусово вставленою транзакцією Боба, яка набуває негайного ефекту. Щоб уникнути цієї проблеми, зведення зазвичай не дозволяють транзакціям примусового включення набути чинності негайно. Замість цього користувачі спочатку вставляють свої транзакції в чергу очікування на L1, де вони переходять в стан «підготовки». Коли секвенсер пакує поза блокчейном транзакції для надсилання до зведеного контракту, він може вибрати, чи включати ці транзакції в чергу. Якщо секвенсер постійно ігнорує транзакції в стані "підготовки", після закінчення періоду вікна користувачі можуть примусово вставити ці транзакції в контракт Rollup. Секвенсер може вирішувати, коли «випадково включати» транзакції з черги очікування, але він все одно може відмовити в їх обробці. Якщо секвенсер послідовно відмовляється, через певний проміжок часу будь-хто може скористатися функцією Force Inclusion для примусової вставки транзакцій у Rollup-контракт. Далі ми представимо реалізацію механізму Force Inclusion у чотирьох відомих Rollups: Optimism, Arbitrum, StarkNet та zkSync.
Секвенсер може вибирати, коли отримувати транзакції з черги очікування.
Секвенсери, як і раніше, можуть відмовлятися обробляти транзакції в черзі очікування.
Якщо секвенсер послідовно відмовляється обробляти транзакції, через певний проміжок часу будь-хто може скористатися функцією Force Inclusion для примусової вставки транзакцій в Rollup-контракт. Далі ми розповімо, як механізм Force Inclusion реалізований у чотирьох відомих ролапах: Optimism, Arbitrum, StarkNet та zkSync.
По-перше, давайте обговоримо процес Optimism's Deposit. Цей процес депозиту включає в себе не тільки переказ коштів в Optimism, але і відправку «повідомлень користувача на L2». Коли вузол L2 отримує щойно депоноване повідомлення, він перетворює повідомлення на транзакцію L2 і виконує його, доставляючи вказаному одержувачу.
Повідомлення користувачів, розміщені з L1 до L2
Контракт L1CrossDomainMessenger
Коли користувач хоче депозит ETH або ERC-20 токени в Optimism, він взаємодіє з контрактом L1StandardBridge на L1 через веб-сторінку, вказуючи суму до депозит та адресу L2, на яку будуть отримані ці активи. Потім контракт L1StandardBridge пересилає повідомлення контракту L1CrossDomainMessenger, який діє як основний міст зв'язку між L1 і L2. L1StandardBridge використовує цей компонент зв'язку для взаємодії з L2StandardBridge на L2, визначаючи, хто може мінт токени на L2 або розблокувати токени з L1. Розробники, яким потрібно створювати контракти, що взаємодіють і синхронізують стани між L1 і L2, можуть створювати їх поверх контракту L1CrossDomainMessenger.
Повідомлення користувачів, що передаються з L1 до L2 через CrossDomainMessenger Contract
Примітка: На деяких зображеннях у цій статті CrossDomainMessenger записаний як CrossChainMessenger.
Контракт з OptimismPortal
Потім контракт L1CrossDomainMessenger пересилає повідомлення на найнижчий рівень, контракт OptimismPortal. Після обробки повідомлення контракт OptimismPortal видає подію під назвою TransactionDeposited, яка включає такі параметри, як «відправник», «одержувач» та інші відповідні деталі виконання. Вузли Optimism на L2 прослуховують цю подію TransactionDeposited з контракту OptimismPortal і конвертують параметри події в транзакцію L2. Ініціатором цієї транзакції буде «відправник», вказаний у події, одержувачем буде «одержувач», згаданий у події, а інші деталі транзакції також будуть отримані з параметрів події.
L2 вузли перетворюють параметри події Transaction Deposited, випромінюваної OptimismPortal, в транзакцію L2.
Наприклад, коли користувач вносить 0,01 ETH через контракт L1StandardBridge, повідомлення та ETH передаються контракту OptimismPortal (адреса 0xbEb5... 06Ed). Через кілька хвилин це перетворюється на транзакцію L2: відправник повідомлення — контракт L1CrossDomainMessenger, одержувач — контракт L2CrossDomainMessenger на L2, а вміст повідомлення вказує на те, що L1StandardBridge отримав від Боба 0,01 ETH депозит. Потім запускаються додаткові процеси, такі як мінтинг 0.01 ETH для L2StandardBridge, який згодом передає його Бобу.
Як його запустити
Якщо ви хочете примусово включити транзакцію в зведений контракт Optimism, ваша мета полягає в тому, щоб гарантувати, що транзакція, «ініційована та виконана з вашої L2-адреси на L2», може бути успішно виконана. Щоб досягти цього, вам слід надіслати повідомлення безпосередньо до контракту OptimismPortal, використовуючи свою адресу L2 (зверніть увагу, що контракт OptimismPortal насправді знаходиться на L1, але формат адреси OP збігається з форматом адреси L1, тому ви можете викликати цей контракт за допомогою L1 рахунок з тією ж адресою, що й ваш L2 рахунок). "Відправником" транзакції L2, отриманої в результаті події Transaction Deposited, емітованої цим контрактом, буде ваш L2 рахунок, а формат транзакції буде відповідати стандартній транзакції L2.
У транзакції L2, отриманої з події Transaction Deposited, сам Боб буде ініціатором; одержувачем буде контракт Uniswap; і він буде включати вказаний ETH, так ніби Боб сам ініціює транзакцію L2.
Щоб скористатися функцією Force Inclusion від Optimism, вам потрібно безпосередньо викликати функцію depositTransaction контракту OptimismPortal і ввести параметри транзакції, яку ви хочете виконати на L2. Я провів простий експеримент Force Inclusion. Мета цієї транзакції полягала в тому, щоб здійснити самостійний переказ на L2 за допомогою моєї адреси (0xeDc1... 6909) і включити повідомлення «Примусове включення». Це транзакція L1, яку я виконав, викликавши функцію depositTransaction через контракт OptimismPortal. Як видно з події Transaction Deposited, яку вона випустила, і відправник, і одержувач є мною.
Решта значень у стовпці непрозорих даних кодують таку інформацію, як "скільки ETH приєднано особу, яка викликає функцію depositTransaction", "скільки ETH ініціатор транзакції L2 хоче відправити одержувачу", "транзакція L2 GasLimit" та "Дані для приймача L2". Після розшифровки цієї інформації ви отримаєте наступні реквізити: "скільки ETH прикріплена особа, що викликає депозитТранзакція": 0, тому що я не вношу ETH з L1 до L2; «скільки ETH ініціатор L2-транзакції хоче відправити одержувачу»: 5566 (wei); "L2 транзакція GasLimit": 50000; "Дані для приймача L2": 0x666f72636520696e636c7573696f6e, що є шістнадцятковим кодуванням рядка "примусове включення". Незабаром після цього з'явилася конвертована транзакція L2: транзакція L2, де я передаю собі 5566 wei, з полем Data, що містить рядок "force inclusion". Крім того, в передостанньому рядку розділу «Інші атрибути» TxnType (тип транзакції) відображається як системна транзакція 126 (Система), що вказує на те, що ця транзакція не була ініційована мною на L2, а була конвертована з події Deposited транзакції L1.
Конвертована транзакція L2
Якщо ви хочете викликати L2-контракт через Force Inclusion і відправити різні дані, вам просто потрібно заповнити параметри у функції depositTransaction. Просто не забудьте використовувати ту саму L1-адресу, що й L2-рахунок під час виклику функції depositTransaction. Таким чином, коли депонована подія конвертується в транзакцію L2, ініціатором буде ваш L2 рахунок. Вікно секвенсера Вузол L2 Optimism, який перетворює подію Transaction Deposited на транзакцію L2, насправді є секвенсором. Оскільки це включає в себе порядок транзакцій, тільки секвенсер може вирішити, коли конвертувати подію в транзакцію L2. Коли секвенсер слухає подію TransactionDeposited, він не обов'язково відразу перетворює подію на транзакцію L2; Може бути затримка. Максимальна тривалість цієї затримки називається вікном секвенсера Sequencer Window. Наразі вікно секвенсера в основній мережі Optimism становить 24 години. Це означає, що коли користувач вносить гроші з L1 або використовує Force Inclusion для транзакції, в гіршому випадку вони будуть включені в історію транзакцій L2 через 24 години.
В Optimism, операція L1 депозит запускає подію Transaction Deposited, а потім залишається лише дочекатися, поки секвенсер включить цю операцію. Однак в Arbitrum операції на L1 (такі як внесення коштів або надсилання повідомлень на L2) зберігаються в черзі на L1, а не просто видають подію. Секвенсер має певний період для включення цих транзакцій у чергу в історію транзакцій L2. Якщо секвенсер не зробить цього протягом цього періоду часу, будь-хто може втрутитися, щоб завершити включення від імені секвенсера.
Arbitrum підтримує чергу в контракті L1. Якщо секвенсер не обробляє транзакції в Черзі протягом певного періоду, будь-хто може примусово включити ці транзакції в історію транзакцій L2. Згідно з конструкцією Arbitrum, операції на L1, такі як депозити, повинні проходити через контракт Delayed Inbox, де, як випливає з назви, ці операції будуть відкладені до набуття чинності. Інший контракт, Sequencer Inbox, є місцем, де Секвенсер безпосередньо завантажує транзакції L2 на L1. Кожного разу, коли секвенсер завантажує транзакції L2, він також може приймати деякі транзакції, що очікують на розгляд, з папки «Відкладені вхідні» та включати їх в історію транзакцій.
Коли секвенсер пише нові транзакції, він також може включати транзакції з DelayedInbox.
Складний дизайн і відсутність довідкових матеріалів
Якщо ви звернетеся до офіційної документації Arbitrum щодо секвенсера та примусового включення, ви знайдете загальне пояснення того, як працює Force Inclusion, а також деякі назви параметрів та функцій: Користувачі спочатку викликають функцію sendUnsignedTransaction у контракті DelayedInbox. Якщо секвенсер не включає його протягом приблизно 24 годин, користувачі можуть викликати функцію forceInclusion у контракті SequencerInbox. Однак офіційна документація не містить посилань на ці функції, тому вам доведеться шукати їх у коді контракту самостійно. Коли ви знаходите функцію sendUnsignedTransaction, ви розумієте, що вам потрібно самостійно заповнити значення nonce і значення maxFeePerGas. Чий це nonce? У якій мережі maxFeePerGas? Як правильно його заповнити? Немає жодних довідкових документів, навіть NatSpec. Ви також знайдете багато подібних функцій у контракті Arbitrum: sendL1FundedUnsignedTransaction, sendUnsignedTransactionToFork, sendContractTransaction, sendL1FundedContractTransaction. Немає жодних документів, які б пояснювали різницю між цими функціями, як ними користуватися або як заповнювати параметри, навіть NatSpec.
Ви намагаєтеся заповнити параметри та надіслати транзакцію методом проб і помилок, сподіваючись знайти правильне застосування. Однак ви виявляєте, що всі ці функції застосовуються Адреса накладення на вашу адресу L1, в результаті чого відправник транзакції на L2 має зовсім іншу адресу, залишаючи вашу адресу L2 неактивною. Пізніше ви випадково натрапили на результат пошуку Google, який показав, що Arbitrum має бібліотеку Tutorial зі скриптами, що демонструють, як надсилати транзакції L2 з L1 (по суті, Force Inclusion). У посібнику перелічено функцію, про яку раніше не згадувалося: sendL2Message. Дивно, але необхідний параметр message насправді є підписаною транзакцією L2 з використанням L2 рахунок. Хто б міг знати, що «повідомлення, надіслане L2 через Force Inclusion» насправді є «підписаною транзакцією L2»? Крім того, немає жодних документів чи NatSpec, які б пояснювали, коли і як використовувати цю функцію.
Висновок: Вручну згенерувати примусову транзакцію на Arbitrum досить складно. Рекомендується слідувати офіційному посібнику та використовувати Arbitrum SDK. На відміну від інших Rollups, Arbitrum не має чіткої документації для розробників та анотацій коду. Багатьом функціям не вистачає пояснень щодо їх цілей і параметрів, через що розробники витрачають набагато більше часу, ніж очікувалося, на їх інтеграцію та використання. Я також звернувся за допомогою в Arbitrum Discord, але не отримав задовільних відповідей. Коли я запитав у Discord, вони лише порадили мені подивитися на sendL2Message і не пояснили функції інших методів (включно з тими, що згадуються в документації Force Inclusion, як-от sendUnsignedTransaction), їх призначення, як їх використовувати або коли їх використовувати.
На жаль, StarkNet наразі не має механізму Force Inclusion. На офіційному форумі є лише дві статті, в яких обговорюються цензура та силова інклюзія. Причина неможливості довести невдалі транзакції полягає в тому, що система доказів з нульовим розголошенням StarkNet не може довести невдалу транзакцію, тому примусове включення не може бути дозволено. Якщо хтось зловмисно (або ненавмисно) примусово включив невдалу, недоведену транзакцію, StarkNet застрягне: тому що після примусового включення транзакції Організатор повинен довести невдалу транзакцію, але він не може. Очікується, що StarkNet представить можливість доведення невдалих транзакцій у версії v0.15.0, після чого механізм Force Inclusion повинен бути додатково реалізований.
Механізм zkSync для передавання повідомлень L1->L2 і примусового включення обробляється за допомогою функції requestL2Transaction контракту MailBox. Користувачі вказують L2-адресу, calldata, кількість ETH для прикріплення, значення L2GasLimit та інші деталі. Функція requestL2Transaction об'єднує ці параметри в транзакцію L2 і поміщає її в PriorityQueue. Коли секвенсер пакує транзакції та завантажує їх до L1 (за допомогою функції commitBatches), він вказує, скільки транзакцій потрібно взяти з PriorityQueue для включення до записів транзакцій L2. З точки зору примусового включення, zkSync схожий на Optimism, де адреса L2 ініціатора (така ж, як адреса L1) використовується для виклику відповідних функцій і заповнення необхідних даних (callee, calldata і т.д.), а не як Arbitrum, який вимагає підписаної транзакції L2. Однак за конструкцією він схожий на Arbitrum, оскільки обидва підтримують чергу на L1, а секвенсер бере відкладені транзакції, безпосередньо надіслані користувачами з черги, і записує їх в історію транзакцій.
Якщо ви депозит ETH через офіційну міст zkSync, як ця транзакція, вона викликає функцію requestL2Transaction контракту MailBox. Ця функція поміщає транзакцію Deposit ETH L2 в PriorityQueue і видає подію NewPriorityRequest. Оскільки контракт кодує дані транзакції L2 у рядок байтів, його не так легко прочитати. Однак, якщо ви подивитеся на параметри цієї L1-транзакції, то побачите, що одержувач L2 також є ініціатором транзакції (оскільки це депозит самому собі). Через деякий час, коли секвенсер виведе цю транзакцію L2 з PriorityQueue і включить її в історію транзакцій, вона буде перетворена в транзакцію L2, яку ви перенесете собі. Сума переказу становитиме суму ETH, додану ініціатором в транзакції L1 Deposit ETH. У транзакції L1 Deposit і ініціатор, і одержувач 0xeDc1... 6909, сума становить 0,03 ETH, а calldata немає. На L2 буде транзакція, де 0xeDc1... 6909 переходить до себе. Тип транзакції (TxnType) - 255, що вказує на системну транзакцію. Потім, так само, як я експериментував з функцією примусової транзакції на Optimism, я викликав функцію запитуL2Transaction від zkSync і ініціював транзакцію самопередачі: ETH не було прикріплено, а calldata містив HEX-кодування рядка «примусове включення». Потім це було перетворено на транзакцію L2, яку я передаю собі, з calldata, що містить шістнадцятковий рядок для "примусового включення": 0x666f72636520696e636c7573696f6e. Коли секвенсер бере транзакції з PriorityQueue та записує їх в історію транзакцій, вони конвертуються у відповідні транзакції L2. Використовуючи функцію requestL2Transaction, користувачі можуть надсилати дані про L1 з тим самим L1 рахунок, що й їхня адреса L2, вказуючи одержувача L2, кількість ETH для прикріплення та дані виклику. Якщо користувачі хочуть викликати інші контракти або включити інші Дані, їм просто потрібно заповнити параметри у функції requestL2Transaction. Функції примусового включення для користувачів поки що немає Незважаючи на те, що транзакція L2, поміщена в PriorityQueue, матиме розрахований період очікування для включення секвенсором, поточна конструкція zkSync не має функції примусового включення, яка дозволяє користувачам примусово застосовувати її. Це означає, що це лише часткове рішення. Незважаючи на те, що існує «період очікування включення», він в кінцевому підсумку залежить від того, чи вирішить секвенсер включити його: секвенсер може включити його після закінчення періоду або ніколи не включати будь-які транзакції з PriorityQueue. У майбутньому zkSync має додати функції, що дозволяють користувачам примусово включати транзакції в історію транзакцій L2, якщо вони не були включені секвенсором після періоду очікування. Це був би дійсно ефективний механізм включення сил. Підведення підсумків
L1 покладається на велику кількість валідатори для забезпечення "безпеки" та "З спротивом до цензури" мережі." Роллапи, однак, мають слабші З спротивом до цензури, оскільки транзакції записуються кількома або навіть одним секвенсором. Таким чином, Rollups потрібен механізм Force Inclusion, який дозволить користувачам обійти Секвенсер і записувати транзакції в історію, запобігаючи цензурі з боку Секвенсера, щоб зробити Rollup непридатним для використання, і не дозволяючи користувачам виводити кошти. Примусове включення дозволяє користувачам примусово записувати транзакції в історію, але дизайн повинен вибрати, чи можна «транзакції бути негайно вставлені в історію і негайно вступити в силу». Якщо дозволити негайний ефект, це негативно вплине на секвенсор, оскільки на незавершені транзакції на L2 можуть вплинути примусово включені транзакції з L1. Таким чином, поточні механізми примусового включення в Rollups спочатку поміщають транзакції, вставлені з L1, в стан очікування і дають секвенсеру часове вікно для реакції і прийняття рішення про включення цих транзакцій, що очікують на розгляд. zkSync і Arbitrum підтримують чергу на L1 для керування транзакціями L2 або повідомленнями, надісланими з L1 на L2. Arbitrum називає його DelayedInbox; zkSync називає його PriorityQueue. Однак метод відправки транзакцій L2 zkSync більше схожий на Optimism, де повідомлення надсилаються з L1 за допомогою L2-адреси, так що при перетворенні в транзакцію L2 ініціатором є адреса L2. Функція відправки L2-транзакцій в Optimism називається depositTransaction; в zkSync вона називається requestL2Transaction. Навпаки, Arbitrum генерує повну транзакцію L2 і підписує її, а потім відправляє через функцію sendL2Message. На L2 Arbitrum використовує підпис для відновлення підписувача як ініціатора транзакції L2. В даний час StarkNet не має механізму Force Inclusion; zkSync має наполовину реалізований механізм Force Inclusion — у нього є PriorityQueue, і кожна транзакція L2 в Черзі має термін дії включення, але цей термін дії наразі лише для галочки. На практиці секвенсер може не включати будь-які транзакції L2 з PriorityQueue.
Ця стаття пересилається з: [Geek Web3], оригінальна назва "Теорія та практика: як ініціювати транзакції, стійкі до цензури, у Ethereum Rollup?", авторські права належать оригінальному автору [NIC Lin, Head of Taipei Ethereum Meetup], якщо у вас є будь-які заперечення щодо передруку, будь ласка, зв'яжіться з нами Gate Learn Team, команда впорається з цим якомога швидше згідно з відповідними процедурами.
Відмова від відповідальності: Погляди та думки, висловлені в цій статті, відображають лише особисті погляди автора та не є будь-якою інвестиційною порадою.
Інші мовні версії статті перекладені командою Gate Learn. Без посилання Gate.io копіювання, розповсюдження або плагіат перекладених статей заборонено.
Буквально вчора сталася шокуюча подія: Linea, Ethereum Рівень 2 рішення, розроблене Consensys, материнською компанією Metamask, було завчасно закрито. Офіційна причина полягала в тому, щоб пом'якшити наслідки хакерського інциденту Velocore. Цей інцидент неминуче нагадує попередній випадок, коли ланцюжок BSC (BNB Chain) також був закритий за офіційної координації, щоб мінімізувати втрати від злому. Ці події часто змушують людей ставити під сумнів децентралізовані цінності, які відстоює Web3.
Основна причина вищезгаданих подій криється в недосконалості інфраструктури, зокрема в її недостатній децентралізації. Якби блокчейн був достатньо децентралізованим, він не зміг би так легко закритися. Завдяки унікальній структурі Ethereum Рівень 2 більшість Рівень 2 рішень покладаються на централізовані секвенсори. Незважаючи на зростаючий дискурс про децентралізовані секвенсери в останні роки, з огляду на призначення і структуру Рівень 2, можна припустити, що Рівень 2 секвенсери навряд чи досягнуть високого рівня децентралізації. Насправді, вони можуть виявитися менш децентралізованими, ніж ланцюжок BSC. Якщо це так, то що робити? Для Рівень 2 найбезпосереднішими ризиками недецентралізованих секвенсерів є брак З спротивом до цензури та жвавості. Якщо є лише кілька суб'єктів, які обробляють транзакції (секвенсери), вони мають абсолютну владу вирішувати, обслуговувати вас чи ні: вони можуть відхилити ваші транзакції за власним бажанням, залишивши вас без права регресу. Вирішення питання З спротивом до цензури в Рівень 2 році, безумовно, є важливою темою. За останні кілька років різні Ethereum Рівень 2 рішення запропонували різні підходи до вирішення цієї проблеми. Наприклад, Loopring, Degate і StarkEx запровадили функції примусового виведення та евакуаційного люка, а Arbitrum та інші Optimistic Rollups впровадили функції Force Inclusion. Ці механізми можуть накладати перевірки на секвенсори, щоб запобігти довільній відмові від транзакцій користувача. У сьогоднішній статті NIC Lin з Тайбейської асоціації Ethereum ділиться власним досвідом, експериментуючи зі стійкими до цензури функціями транзакцій чотирьох основних Rollups і надаючи глибокий аналіз механізму Force Inclusion, зосереджуючись на робочому процесі та операційних методах. Цей аналіз особливо цінний для Ethereum спільноти та великих власників активів.
Цензура спротив в транзакціях має вирішальне значення для будь-якого блокчейну. Якщо блокчейн може довільно цензурувати та відхиляти транзакції користувачів, він нічим не відрізняється від сервера Web2. Транзакційний З спротивом до цензури Ethereum в даний час забезпечується його численними валідатори. Якщо хтось хоче цензурувати транзакцію Боба і запобігти її включенню в блокчейн, йому доведеться або підкупити більшу частину валідатори мережі, або спамити мережу сміттєвими транзакціями, які мають вищі комісії, ніж у Боба, таким чином займаючи простір блоку. Обидва способи надзвичайно затратні.
Примітка: У поточній архітектурі Ethereum Proposer-Builder Separation (PBS) вартість цензури транзакцій значно знижується. Наприклад, ви можете подивитися на частку блоків, які відповідають цензурі OFAC щодо транзакцій Tornado Cash. Поточна З спротивом до цензури спирається на незалежні валідатори та ретранслятори, які знаходяться поза юрисдикцією OFAC та інших державних установ.
А як щодо Rollups? Роллапи не вимагають великої кількості валідатори для забезпечення безпеки. Навіть якщо Rollup має лише одну централізовану сутність (секвенсор), яка виробляє блоки, вона залишається такою ж безпечною, як і рівень 1 (L1). Однак безпека та З спротивом до цензури – це різні речі. Зведення, незважаючи на те, що воно таке ж безпечне, як і Ethereum, все одно може цензурувати транзакцію будь-якого користувача, якщо воно має лише один централізований секвенсор.
Секвенсер може відмовити в обробці транзакції користувача, в результаті чого кошти користувача будуть заблоковані і він не зможе покинути Rollup.
Замість того, щоб вимагати від зведених послідовників великої кількості децентралізованих секвенсорів, ефективніше безпосередньо використовувати З спротивом до цензури рівня 1 (L1):
Оскільки секвенсеру потрібно упаковувати дані про транзакції та надсилати їх до Rollup контракту на L1, ми можемо додати в контракт функцію, яка дозволяє користувачам самостійно вставляти свої транзакції в Rollup-контракт. Цей механізм відомий як «примусове включення». Так само, лонг секвенсор не може цензурувати користувачів на рівні L1, він не може перешкодити користувачам примусово вставляти транзакції на рівні L1. Таким чином, зведення може успадкувати З спротивом до цензури L1.
Секвенсер не може переглядати транзакції L1 користувача, не сплачуючи високу ціну
Якщо транзакції дозволено безпосередньо вписувати в Rollup-контракт за допомогою Force Inclusion (тобто вони набувають чинності негайно), стан Rollup миттєво зміниться. Наприклад, якщо Боб використовує механізм примусового включення, щоб вставити транзакцію, яка переводить Керол 1000 DAI, і транзакція вступає в силу негайно, баланс Боба зменшиться на 1000 DAI, а баланс Керол збільшиться на 1000 DAI в оновленому стані.
Якщо примусове включення дозволяє безпосередньо записувати транзакції в Rollup-контракт і набувати чинності негайно, стан Rollup миттєво зміниться. Якщо секвенсер одночасно збирає поза блокчейном транзакції та готується відправити наступну партію до Rollup контракту, він може бути порушений примусово вставленою транзакцією Боба, яка набуває негайного ефекту. Щоб уникнути цієї проблеми, зведення зазвичай не дозволяють транзакціям примусового включення набути чинності негайно. Замість цього користувачі спочатку вставляють свої транзакції в чергу очікування на L1, де вони переходять в стан «підготовки». Коли секвенсер пакує поза блокчейном транзакції для надсилання до зведеного контракту, він може вибрати, чи включати ці транзакції в чергу. Якщо секвенсер постійно ігнорує транзакції в стані "підготовки", після закінчення періоду вікна користувачі можуть примусово вставити ці транзакції в контракт Rollup. Секвенсер може вирішувати, коли «випадково включати» транзакції з черги очікування, але він все одно може відмовити в їх обробці. Якщо секвенсер послідовно відмовляється, через певний проміжок часу будь-хто може скористатися функцією Force Inclusion для примусової вставки транзакцій у Rollup-контракт. Далі ми представимо реалізацію механізму Force Inclusion у чотирьох відомих Rollups: Optimism, Arbitrum, StarkNet та zkSync.
Секвенсер може вибирати, коли отримувати транзакції з черги очікування.
Секвенсери, як і раніше, можуть відмовлятися обробляти транзакції в черзі очікування.
Якщо секвенсер послідовно відмовляється обробляти транзакції, через певний проміжок часу будь-хто може скористатися функцією Force Inclusion для примусової вставки транзакцій в Rollup-контракт. Далі ми розповімо, як механізм Force Inclusion реалізований у чотирьох відомих ролапах: Optimism, Arbitrum, StarkNet та zkSync.
По-перше, давайте обговоримо процес Optimism's Deposit. Цей процес депозиту включає в себе не тільки переказ коштів в Optimism, але і відправку «повідомлень користувача на L2». Коли вузол L2 отримує щойно депоноване повідомлення, він перетворює повідомлення на транзакцію L2 і виконує його, доставляючи вказаному одержувачу.
Повідомлення користувачів, розміщені з L1 до L2
Контракт L1CrossDomainMessenger
Коли користувач хоче депозит ETH або ERC-20 токени в Optimism, він взаємодіє з контрактом L1StandardBridge на L1 через веб-сторінку, вказуючи суму до депозит та адресу L2, на яку будуть отримані ці активи. Потім контракт L1StandardBridge пересилає повідомлення контракту L1CrossDomainMessenger, який діє як основний міст зв'язку між L1 і L2. L1StandardBridge використовує цей компонент зв'язку для взаємодії з L2StandardBridge на L2, визначаючи, хто може мінт токени на L2 або розблокувати токени з L1. Розробники, яким потрібно створювати контракти, що взаємодіють і синхронізують стани між L1 і L2, можуть створювати їх поверх контракту L1CrossDomainMessenger.
Повідомлення користувачів, що передаються з L1 до L2 через CrossDomainMessenger Contract
Примітка: На деяких зображеннях у цій статті CrossDomainMessenger записаний як CrossChainMessenger.
Контракт з OptimismPortal
Потім контракт L1CrossDomainMessenger пересилає повідомлення на найнижчий рівень, контракт OptimismPortal. Після обробки повідомлення контракт OptimismPortal видає подію під назвою TransactionDeposited, яка включає такі параметри, як «відправник», «одержувач» та інші відповідні деталі виконання. Вузли Optimism на L2 прослуховують цю подію TransactionDeposited з контракту OptimismPortal і конвертують параметри події в транзакцію L2. Ініціатором цієї транзакції буде «відправник», вказаний у події, одержувачем буде «одержувач», згаданий у події, а інші деталі транзакції також будуть отримані з параметрів події.
L2 вузли перетворюють параметри події Transaction Deposited, випромінюваної OptimismPortal, в транзакцію L2.
Наприклад, коли користувач вносить 0,01 ETH через контракт L1StandardBridge, повідомлення та ETH передаються контракту OptimismPortal (адреса 0xbEb5... 06Ed). Через кілька хвилин це перетворюється на транзакцію L2: відправник повідомлення — контракт L1CrossDomainMessenger, одержувач — контракт L2CrossDomainMessenger на L2, а вміст повідомлення вказує на те, що L1StandardBridge отримав від Боба 0,01 ETH депозит. Потім запускаються додаткові процеси, такі як мінтинг 0.01 ETH для L2StandardBridge, який згодом передає його Бобу.
Як його запустити
Якщо ви хочете примусово включити транзакцію в зведений контракт Optimism, ваша мета полягає в тому, щоб гарантувати, що транзакція, «ініційована та виконана з вашої L2-адреси на L2», може бути успішно виконана. Щоб досягти цього, вам слід надіслати повідомлення безпосередньо до контракту OptimismPortal, використовуючи свою адресу L2 (зверніть увагу, що контракт OptimismPortal насправді знаходиться на L1, але формат адреси OP збігається з форматом адреси L1, тому ви можете викликати цей контракт за допомогою L1 рахунок з тією ж адресою, що й ваш L2 рахунок). "Відправником" транзакції L2, отриманої в результаті події Transaction Deposited, емітованої цим контрактом, буде ваш L2 рахунок, а формат транзакції буде відповідати стандартній транзакції L2.
У транзакції L2, отриманої з події Transaction Deposited, сам Боб буде ініціатором; одержувачем буде контракт Uniswap; і він буде включати вказаний ETH, так ніби Боб сам ініціює транзакцію L2.
Щоб скористатися функцією Force Inclusion від Optimism, вам потрібно безпосередньо викликати функцію depositTransaction контракту OptimismPortal і ввести параметри транзакції, яку ви хочете виконати на L2. Я провів простий експеримент Force Inclusion. Мета цієї транзакції полягала в тому, щоб здійснити самостійний переказ на L2 за допомогою моєї адреси (0xeDc1... 6909) і включити повідомлення «Примусове включення». Це транзакція L1, яку я виконав, викликавши функцію depositTransaction через контракт OptimismPortal. Як видно з події Transaction Deposited, яку вона випустила, і відправник, і одержувач є мною.
Решта значень у стовпці непрозорих даних кодують таку інформацію, як "скільки ETH приєднано особу, яка викликає функцію depositTransaction", "скільки ETH ініціатор транзакції L2 хоче відправити одержувачу", "транзакція L2 GasLimit" та "Дані для приймача L2". Після розшифровки цієї інформації ви отримаєте наступні реквізити: "скільки ETH прикріплена особа, що викликає депозитТранзакція": 0, тому що я не вношу ETH з L1 до L2; «скільки ETH ініціатор L2-транзакції хоче відправити одержувачу»: 5566 (wei); "L2 транзакція GasLimit": 50000; "Дані для приймача L2": 0x666f72636520696e636c7573696f6e, що є шістнадцятковим кодуванням рядка "примусове включення". Незабаром після цього з'явилася конвертована транзакція L2: транзакція L2, де я передаю собі 5566 wei, з полем Data, що містить рядок "force inclusion". Крім того, в передостанньому рядку розділу «Інші атрибути» TxnType (тип транзакції) відображається як системна транзакція 126 (Система), що вказує на те, що ця транзакція не була ініційована мною на L2, а була конвертована з події Deposited транзакції L1.
Конвертована транзакція L2
Якщо ви хочете викликати L2-контракт через Force Inclusion і відправити різні дані, вам просто потрібно заповнити параметри у функції depositTransaction. Просто не забудьте використовувати ту саму L1-адресу, що й L2-рахунок під час виклику функції depositTransaction. Таким чином, коли депонована подія конвертується в транзакцію L2, ініціатором буде ваш L2 рахунок. Вікно секвенсера Вузол L2 Optimism, який перетворює подію Transaction Deposited на транзакцію L2, насправді є секвенсором. Оскільки це включає в себе порядок транзакцій, тільки секвенсер може вирішити, коли конвертувати подію в транзакцію L2. Коли секвенсер слухає подію TransactionDeposited, він не обов'язково відразу перетворює подію на транзакцію L2; Може бути затримка. Максимальна тривалість цієї затримки називається вікном секвенсера Sequencer Window. Наразі вікно секвенсера в основній мережі Optimism становить 24 години. Це означає, що коли користувач вносить гроші з L1 або використовує Force Inclusion для транзакції, в гіршому випадку вони будуть включені в історію транзакцій L2 через 24 години.
В Optimism, операція L1 депозит запускає подію Transaction Deposited, а потім залишається лише дочекатися, поки секвенсер включить цю операцію. Однак в Arbitrum операції на L1 (такі як внесення коштів або надсилання повідомлень на L2) зберігаються в черзі на L1, а не просто видають подію. Секвенсер має певний період для включення цих транзакцій у чергу в історію транзакцій L2. Якщо секвенсер не зробить цього протягом цього періоду часу, будь-хто може втрутитися, щоб завершити включення від імені секвенсера.
Arbitrum підтримує чергу в контракті L1. Якщо секвенсер не обробляє транзакції в Черзі протягом певного періоду, будь-хто може примусово включити ці транзакції в історію транзакцій L2. Згідно з конструкцією Arbitrum, операції на L1, такі як депозити, повинні проходити через контракт Delayed Inbox, де, як випливає з назви, ці операції будуть відкладені до набуття чинності. Інший контракт, Sequencer Inbox, є місцем, де Секвенсер безпосередньо завантажує транзакції L2 на L1. Кожного разу, коли секвенсер завантажує транзакції L2, він також може приймати деякі транзакції, що очікують на розгляд, з папки «Відкладені вхідні» та включати їх в історію транзакцій.
Коли секвенсер пише нові транзакції, він також може включати транзакції з DelayedInbox.
Складний дизайн і відсутність довідкових матеріалів
Якщо ви звернетеся до офіційної документації Arbitrum щодо секвенсера та примусового включення, ви знайдете загальне пояснення того, як працює Force Inclusion, а також деякі назви параметрів та функцій: Користувачі спочатку викликають функцію sendUnsignedTransaction у контракті DelayedInbox. Якщо секвенсер не включає його протягом приблизно 24 годин, користувачі можуть викликати функцію forceInclusion у контракті SequencerInbox. Однак офіційна документація не містить посилань на ці функції, тому вам доведеться шукати їх у коді контракту самостійно. Коли ви знаходите функцію sendUnsignedTransaction, ви розумієте, що вам потрібно самостійно заповнити значення nonce і значення maxFeePerGas. Чий це nonce? У якій мережі maxFeePerGas? Як правильно його заповнити? Немає жодних довідкових документів, навіть NatSpec. Ви також знайдете багато подібних функцій у контракті Arbitrum: sendL1FundedUnsignedTransaction, sendUnsignedTransactionToFork, sendContractTransaction, sendL1FundedContractTransaction. Немає жодних документів, які б пояснювали різницю між цими функціями, як ними користуватися або як заповнювати параметри, навіть NatSpec.
Ви намагаєтеся заповнити параметри та надіслати транзакцію методом проб і помилок, сподіваючись знайти правильне застосування. Однак ви виявляєте, що всі ці функції застосовуються Адреса накладення на вашу адресу L1, в результаті чого відправник транзакції на L2 має зовсім іншу адресу, залишаючи вашу адресу L2 неактивною. Пізніше ви випадково натрапили на результат пошуку Google, який показав, що Arbitrum має бібліотеку Tutorial зі скриптами, що демонструють, як надсилати транзакції L2 з L1 (по суті, Force Inclusion). У посібнику перелічено функцію, про яку раніше не згадувалося: sendL2Message. Дивно, але необхідний параметр message насправді є підписаною транзакцією L2 з використанням L2 рахунок. Хто б міг знати, що «повідомлення, надіслане L2 через Force Inclusion» насправді є «підписаною транзакцією L2»? Крім того, немає жодних документів чи NatSpec, які б пояснювали, коли і як використовувати цю функцію.
Висновок: Вручну згенерувати примусову транзакцію на Arbitrum досить складно. Рекомендується слідувати офіційному посібнику та використовувати Arbitrum SDK. На відміну від інших Rollups, Arbitrum не має чіткої документації для розробників та анотацій коду. Багатьом функціям не вистачає пояснень щодо їх цілей і параметрів, через що розробники витрачають набагато більше часу, ніж очікувалося, на їх інтеграцію та використання. Я також звернувся за допомогою в Arbitrum Discord, але не отримав задовільних відповідей. Коли я запитав у Discord, вони лише порадили мені подивитися на sendL2Message і не пояснили функції інших методів (включно з тими, що згадуються в документації Force Inclusion, як-от sendUnsignedTransaction), їх призначення, як їх використовувати або коли їх використовувати.
На жаль, StarkNet наразі не має механізму Force Inclusion. На офіційному форумі є лише дві статті, в яких обговорюються цензура та силова інклюзія. Причина неможливості довести невдалі транзакції полягає в тому, що система доказів з нульовим розголошенням StarkNet не може довести невдалу транзакцію, тому примусове включення не може бути дозволено. Якщо хтось зловмисно (або ненавмисно) примусово включив невдалу, недоведену транзакцію, StarkNet застрягне: тому що після примусового включення транзакції Організатор повинен довести невдалу транзакцію, але він не може. Очікується, що StarkNet представить можливість доведення невдалих транзакцій у версії v0.15.0, після чого механізм Force Inclusion повинен бути додатково реалізований.
Механізм zkSync для передавання повідомлень L1->L2 і примусового включення обробляється за допомогою функції requestL2Transaction контракту MailBox. Користувачі вказують L2-адресу, calldata, кількість ETH для прикріплення, значення L2GasLimit та інші деталі. Функція requestL2Transaction об'єднує ці параметри в транзакцію L2 і поміщає її в PriorityQueue. Коли секвенсер пакує транзакції та завантажує їх до L1 (за допомогою функції commitBatches), він вказує, скільки транзакцій потрібно взяти з PriorityQueue для включення до записів транзакцій L2. З точки зору примусового включення, zkSync схожий на Optimism, де адреса L2 ініціатора (така ж, як адреса L1) використовується для виклику відповідних функцій і заповнення необхідних даних (callee, calldata і т.д.), а не як Arbitrum, який вимагає підписаної транзакції L2. Однак за конструкцією він схожий на Arbitrum, оскільки обидва підтримують чергу на L1, а секвенсер бере відкладені транзакції, безпосередньо надіслані користувачами з черги, і записує їх в історію транзакцій.
Якщо ви депозит ETH через офіційну міст zkSync, як ця транзакція, вона викликає функцію requestL2Transaction контракту MailBox. Ця функція поміщає транзакцію Deposit ETH L2 в PriorityQueue і видає подію NewPriorityRequest. Оскільки контракт кодує дані транзакції L2 у рядок байтів, його не так легко прочитати. Однак, якщо ви подивитеся на параметри цієї L1-транзакції, то побачите, що одержувач L2 також є ініціатором транзакції (оскільки це депозит самому собі). Через деякий час, коли секвенсер виведе цю транзакцію L2 з PriorityQueue і включить її в історію транзакцій, вона буде перетворена в транзакцію L2, яку ви перенесете собі. Сума переказу становитиме суму ETH, додану ініціатором в транзакції L1 Deposit ETH. У транзакції L1 Deposit і ініціатор, і одержувач 0xeDc1... 6909, сума становить 0,03 ETH, а calldata немає. На L2 буде транзакція, де 0xeDc1... 6909 переходить до себе. Тип транзакції (TxnType) - 255, що вказує на системну транзакцію. Потім, так само, як я експериментував з функцією примусової транзакції на Optimism, я викликав функцію запитуL2Transaction від zkSync і ініціював транзакцію самопередачі: ETH не було прикріплено, а calldata містив HEX-кодування рядка «примусове включення». Потім це було перетворено на транзакцію L2, яку я передаю собі, з calldata, що містить шістнадцятковий рядок для "примусового включення": 0x666f72636520696e636c7573696f6e. Коли секвенсер бере транзакції з PriorityQueue та записує їх в історію транзакцій, вони конвертуються у відповідні транзакції L2. Використовуючи функцію requestL2Transaction, користувачі можуть надсилати дані про L1 з тим самим L1 рахунок, що й їхня адреса L2, вказуючи одержувача L2, кількість ETH для прикріплення та дані виклику. Якщо користувачі хочуть викликати інші контракти або включити інші Дані, їм просто потрібно заповнити параметри у функції requestL2Transaction. Функції примусового включення для користувачів поки що немає Незважаючи на те, що транзакція L2, поміщена в PriorityQueue, матиме розрахований період очікування для включення секвенсором, поточна конструкція zkSync не має функції примусового включення, яка дозволяє користувачам примусово застосовувати її. Це означає, що це лише часткове рішення. Незважаючи на те, що існує «період очікування включення», він в кінцевому підсумку залежить від того, чи вирішить секвенсер включити його: секвенсер може включити його після закінчення періоду або ніколи не включати будь-які транзакції з PriorityQueue. У майбутньому zkSync має додати функції, що дозволяють користувачам примусово включати транзакції в історію транзакцій L2, якщо вони не були включені секвенсором після періоду очікування. Це був би дійсно ефективний механізм включення сил. Підведення підсумків
L1 покладається на велику кількість валідатори для забезпечення "безпеки" та "З спротивом до цензури" мережі." Роллапи, однак, мають слабші З спротивом до цензури, оскільки транзакції записуються кількома або навіть одним секвенсором. Таким чином, Rollups потрібен механізм Force Inclusion, який дозволить користувачам обійти Секвенсер і записувати транзакції в історію, запобігаючи цензурі з боку Секвенсера, щоб зробити Rollup непридатним для використання, і не дозволяючи користувачам виводити кошти. Примусове включення дозволяє користувачам примусово записувати транзакції в історію, але дизайн повинен вибрати, чи можна «транзакції бути негайно вставлені в історію і негайно вступити в силу». Якщо дозволити негайний ефект, це негативно вплине на секвенсор, оскільки на незавершені транзакції на L2 можуть вплинути примусово включені транзакції з L1. Таким чином, поточні механізми примусового включення в Rollups спочатку поміщають транзакції, вставлені з L1, в стан очікування і дають секвенсеру часове вікно для реакції і прийняття рішення про включення цих транзакцій, що очікують на розгляд. zkSync і Arbitrum підтримують чергу на L1 для керування транзакціями L2 або повідомленнями, надісланими з L1 на L2. Arbitrum називає його DelayedInbox; zkSync називає його PriorityQueue. Однак метод відправки транзакцій L2 zkSync більше схожий на Optimism, де повідомлення надсилаються з L1 за допомогою L2-адреси, так що при перетворенні в транзакцію L2 ініціатором є адреса L2. Функція відправки L2-транзакцій в Optimism називається depositTransaction; в zkSync вона називається requestL2Transaction. Навпаки, Arbitrum генерує повну транзакцію L2 і підписує її, а потім відправляє через функцію sendL2Message. На L2 Arbitrum використовує підпис для відновлення підписувача як ініціатора транзакції L2. В даний час StarkNet не має механізму Force Inclusion; zkSync має наполовину реалізований механізм Force Inclusion — у нього є PriorityQueue, і кожна транзакція L2 в Черзі має термін дії включення, але цей термін дії наразі лише для галочки. На практиці секвенсер може не включати будь-які транзакції L2 з PriorityQueue.
Ця стаття пересилається з: [Geek Web3], оригінальна назва "Теорія та практика: як ініціювати транзакції, стійкі до цензури, у Ethereum Rollup?", авторські права належать оригінальному автору [NIC Lin, Head of Taipei Ethereum Meetup], якщо у вас є будь-які заперечення щодо передруку, будь ласка, зв'яжіться з нами Gate Learn Team, команда впорається з цим якомога швидше згідно з відповідними процедурами.
Відмова від відповідальності: Погляди та думки, висловлені в цій статті, відображають лише особисті погляди автора та не є будь-якою інвестиційною порадою.
Інші мовні версії статті перекладені командою Gate Learn. Без посилання Gate.io копіювання, розповсюдження або плагіат перекладених статей заборонено.