이론에서 실천으로: 이더리움 롤업의 검열 저항 거래 구현 메커니즘 분석
원문 제목:《Rollup의 Force Inclusion 메커니즘 소개》
저자:NIC Lin, 타이페이 이더리움 밋업 책임자
어제 수많은 사람들을 충격에 빠뜨린 사건이 발생했습니다: Metamask 모회사 Consensys가 출시한 이더리움 2층 Linea가 자발적으로 중단되었고, 공식적으로 이렇게 한 목적은 Velocore 해킹 사건의 영향을 줄이기 위함이라고 밝혔습니다. 이는 이전 BSC 체인(BNB Chain)이 해킹 공격으로 인한 손실을 줄이기 위해 공식적으로 중단한 사건을 떠올리게 합니다. 사람들이 이러한 사건에 대해 이야기할 때마다 Web3가 주장하는 탈중앙화 가치에 의문을 품게 됩니다.
물론, 위 사건이 발생한 핵심 원인은 인프라 자체의 불완전함, 즉 충분히 탈중앙화되지 않았기 때문입니다: 만약 한 체인이 충분히 탈중앙화되어 있다면, 중단한다고 해서 중단할 수는 없습니다. 이더리움 2층의 독특한 구조 때문에, 대부분의 Layer2는 중앙화된 Sequencer에 의존하고 있습니다. 최근 몇 년간 탈중앙화 정렬기의 주장이 늘어나고 있지만, 2층의 존재 목적과 구조를 고려할 때, Layer2의 정렬기는 대체로 탈중앙화되지 않을 가능성이 높으며, 결국 BSC 체인보다도 탈중앙화 정도가 낮을 수 있습니다. 만약 사실이 정말 그렇다면, 우리는 어떻게 해야 할까요?
사실 2층에 대해, 정렬기가 탈중앙화되지 않음으로 인해 발생하는 가장 직접적인 해악은 검열 저항성과 활성도입니다. 거래를 처리하는 실체(Sequencer)가 적다면, 그들은 당신에게 서비스를 제공할지 여부에 대해 절대적인 권력을 가집니다: 거부하고 싶으면 거부할 수 있으며, 당신은 방법이 없을 수 있습니다. Layer2의 검열 문제를 어떻게 해결할 것인가는 분명히 중요한 주제입니다.
지난 몇 년 동안, 여러 이더리움 2층은 검열 문제에 대한 다양한 해결책을 제시했습니다. 예를 들어 Loopring과 Degate, StarkEx의 강제 인출 및 탈출 기능, Arbitrum 및 기타 OP Rollup의 Force Inclusion 기능 등이 있습니다. 이러한 방법들은 특정 조건 하에 Sequencer에 대한 견제를 가능하게 하여, 그들이 임의로 사용자 거래 요청을 거부하는 것을 방지합니다.
오늘의 글에서는 타이페이 이더리움 협회의 NIC Lin이 직접 4개의 주요 Rollup의 검열 저항 거래 기능을 실험하고, 작업 흐름 및 운영 방법 등에서 Force Inclusion의 메커니즘 설계를 깊이 분석했습니다. 이는 이더리움 커뮤니티와 막대한 자산을 보유한 대규모 투자자에게 특히 참고 가치가 있습니다.
거래 검열과 Force Inclusion
거래의 검열 저항성(Censorship Resistance)은 블록체인에 매우 중요합니다. 만약 블록체인이 임의로 사용자 발의 거래를 검열하고 거부할 수 있다면, 그것은 Web2 서버와 다를 바 없습니다. 현재 이더리움의 거래 검열 저항 능력은 수많은 Validator에서 비롯됩니다. 만약 누군가 Bob의 거래를 검열하고 그의 거래를 블록체인에 올리지 않으려 한다면, 네트워크의 대부분 Validator를 매수하려 하거나, Bob보다 수수료가 더 높은 스팸 거래를 지속적으로 보내 블록 공간을 차지해야 합니다. 어떤 방식이든 비용은 매우 높습니다.
참고: 현재 Ethereum의 PBS 구조에서 거래 검열 비용은 상당히 낮아졌습니다. OFAC가 Tornado Cash 거래를 검열하는 블록 비율을 참고할 수 있습니다. 현재의 검열 저항 능력은 OFAC 및 정부 관할 범위 밖의 독립 검증자 및 Relay에 의존하고 있습니다.
하지만 Rollup은 어떨까요? Rollup은 안전성을 보장하기 위해 많은 Validator가 필요하지 않습니다. 심지어 Rollup에 중앙화된 역할(Sequencer)만 있어도 L1과 동일하게 안전합니다. 하지만 안전성과 검열 저항 능력은 별개의 문제입니다. Rollup이 이더리움과 동일하게 안전하더라도, 중앙화된 Sequencer만 있는 경우에는 어떤 사용자의 거래도 검열할 수 있습니다.
Sequencer는 사용자의 거래를 처리하는 것을 거부할 수 있으며, 이로 인해 사용자의 자금이 Rollup에서 인출되지 못하게 됩니다.
Force Inclusion 메커니즘
Rollup에 많은 탈중앙화된 Sequencer가 필요하다고 요구하기보다는 L1의 검열 저항 능력을 직접 활용하는 것이 더 낫습니다:
본래 Sequencer는 거래 데이터를 패키징하여 L1의 Rollup 계약으로 전송해야 하므로, 계약 내에 사용자가 거래를 Rollup 계약에 직접 삽입할 수 있는 설계를 추가하는 것이 좋습니다. 이 메커니즘을 "Force Inclusion"이라고 합니다. Sequencer가 L1 수준에서 사용자를 검열할 수 없다면, 사용자가 L1에서 거래를 강제로 삽입하는 것을 막을 수 없습니다. 이렇게 되면 Rollup은 L1의 검열 저항 능력을 상속받을 수 있습니다.
Sequencer는 사용자의 L1 거래를 검열할 수 없으며, 그렇지 않으면 매우 높은 비용을 지불해야 합니다.
강제 거래는 어떻게 효력을 발휘해야 할까요?
Force Inclusion을 통해 거래를 Rollup 계약에 직접 작성할 수 있도록 허용한다면(즉시 효력이 발생), Rollup의 상태는 즉시 변경됩니다. 예를 들어 Bob이 Force Inclusion 메커니즘을 통해 "Carol에게 1000 DAI 전송" 거래를 삽입하면, 거래가 즉시 효력이 발생할 경우 최신 상태에서 Bob의 잔액은 1000 DAI가 줄어들고 Carol의 잔액은 1000 DAI가 늘어납니다.
Force Inclusion이 거래를 Rollup 계약에 직접 작성하고 즉시 효력이 발생할 수 있다면, 상태는 즉시 변경됩니다.
이때 Sequencer가 체인 외부에서 거래를 수집하고 다음 배치의 거래를 Rollup 계약으로 전송하는 경우, Bob이 강제로 삽입하고 즉시 효력이 발생하는 거래에 영향을 받을 수 있습니다. 이러한 문제는 극력 피해야 하므로, Rollup은 일반적으로 Force Inclusion 거래가 즉시 효력이 발생하지 않도록 하며, 사용자가 거래를 L1의 대기열에 삽입하고 "준비 중" 상태로 두도록 합니다.
Sequencer가 체인 외부 거래를 패키징하여 Rollup 계약으로 전송할 때, 이전 거래를 거래 시퀀스에 삽입할지를 선택합니다. Sequencer가 "준비 중" 상태의 거래를 계속 무시하면, 창구 기간이 끝난 후 사용자는 이러한 거래를 Rollup 계약에 강제로 삽입할 수 있습니다.
Sequencer는 언제 "순간적으로 수입" 대기열의 거래를 수입할지를 결정할 수 있습니다.
Sequencer는 여전히 대기열의 거래를 처리하는 것을 거부할 수 있습니다.
Sequencer가 장기간 거부할 경우, 일정 시간이 지나면 누구나 Force Inclusion 기능을 통해 거래를 Rollup 계약에 강제로 삽입할 수 있습니다.
다음으로 Optimism, Arbitrum, StarkNet 및 zkSync와 같은 네 가지 유명한 Rollup의 Force Inclusion 메커니즘 구현을 순서대로 소개하겠습니다.
Optimism의 Force Inclusion 메커니즘
먼저 Optimism의 Deposit 프로세스를 소개합니다. 이 Deposit은 단순히 돈을 Optimism에 입금하는 것뿐만 아니라 "사용자가 L2로 전송하는 정보"를 L2로 보내는 것도 포함됩니다. L2 노드는 새로 입금된 메시지를 수신한 후, 메시지를 L2 거래로 변환하여 실행하고, 지정된 수신자에게 전송합니다.
사용자가 L1에서 L2로 Deposit하는 메시지
L1CrossDomainMessenger 계약
사용자가 ETH 또는 ERC-20 토큰을 Optimism에 입금하려고 할 때, 그는 프론트엔드 웹사이트와 L1의 L1StandardBridge 계약과 상호작용하여 얼마나 많은 금액을 입금할지 및 어떤 L2 주소가 이러한 자산을 수신할지를 지정합니다.
L1StandardBridge 계약은 메시지를 다음 단계인 L1CrossDomainMessenger 계약으로 전달합니다. 이 계약은 L1과 L2 간의 상호 통신을 위한 구성 요소로 작용하며, L1StandardBridge는 이 일반 통신 구성 요소를 통해 L2의 L2StandardBridge와 소통하여 누가 L2에서 토큰을 발행할 수 있는지 또는 누가 L1에서 토큰을 해제할 수 있는지를 결정합니다.
개발자가 L1과 L2 간에 상호 통신하고 상태를 동기화하는 계약을 개발해야 하는 경우, 그는 L1CrossDomainMessenger 계약 위에 구축할 수 있습니다.
사용자의 메시지는 CrossDomainMessenger 계약을 통해 L1에서 L2로 전달됩니다.
참고: 본문의 일부 이미지에서 CrossDomainMessager를 CrossChainMessager로 잘못 표기했습니다.
OptimismPortal 계약
L1CrossDomainMessenger 계약은 메시지를 최하위의 OptimismPortal 계약으로 전송합니다. OptimismPortal 계약이 처리를 마친 후, TransactionDeposited라는 이름의 이벤트를 발생시키며, 이 이벤트의 매개변수에는 "메시지를 발신한 사람", "메시지를 수신한 사람" 및 관련 실행 매개변수가 포함됩니다.
그 후 L2의 Optimism 노드는 OptimismPortal 계약에서 발생한 Transaction Deposited 이벤트를 청취하고, 이벤트의 매개변수를 L2 거래로 변환합니다. 이 거래의 발신자는 Transaction Deposited 이벤트 매개변수에서 지정된 "메시지를 발신한 사람"이 되고, 거래 수신자는 이벤트 매개변수의 "메시지를 수신한 사람"이 됩니다. 다른 거래 매개변수도 위의 이벤트에서 가져옵니다.
L2 노드는 OptimismPortal에서 발생한 Transaction Deposited 이벤트 매개변수를 L2 거래로 변환합니다.
예를 들어, 이는 사용자가 L1StandardBridge 계약을 통해 0.01ETH를 입금하는 거래입니다. 이 메시지와 ETH는 OptimismPortal 계약(주소: 0xbEb5…06Ed)으로 전송되며, 몇 분 후 L2 거래로 변환됩니다:
메시지 발신자는 L1CrossDomainMessenger 계약이고, 수신자는 L2의 L2CrossDomainMessenger 계약입니다. 메시지 내용은 L1StandardBridge가 Bob의 0.01ETH 입금을 수신했다는 것입니다. 이후에는 L2StandardBridge에 0.01ETH를 추가 발행하는 등의 프로세스가 발생합니다.
구체적으로 어떻게 촉발되는가
당신이 거래를 Optimism의 Rollup 계약에 강제로 수납하고자 할 때, 당신이 달성하고자 하는 효과는 "당신의 L2 주소에서 L2에서 발신되고 실행될 거래"가 원활하게 실행되는 것입니다. 이때 당신은 자신의 L2 주소를 사용하여 메시지를 OptimismPortal 계약에 직접 제출해야 합니다(주의: OptimismPortal 계약은 실제로 L1에 있지만, OP의 주소 형식은 L1 주소 형식과 일치하므로, 당신은 L2 계좌와 동일한 주소의 L1 계좌로 위 계약을 호출하면 됩니다).
그 후 해당 계약에서 발생한 Transaction Deposited 이벤트로 변환된 L2 거래의 "발신자"는 당신의 L2 계좌가 됩니다. 이때 거래 형식은 정상적인 L2 거래와 일치합니다.
Transaction Deposited 이벤트에서 변환된 L2 거래에서 발신자는 Bob 자신이며, 수신자는 Uniswap 계약입니다. 또한 지정된 ETH가 첨부되어 있으며, 마치 Bob이 L2 거래를 직접 발신한 것과 같습니다.
Optimism의 Force Inclusion 기능을 호출하려면, 당신은 OptimismPortal 계약의 depositTransaction 함수를 직접 호출하고, L2에서 실행하고자 하는 거래의 매개변수를 입력해야 합니다.
저는 간단한 Force Inclusion 실험을 수행했습니다. 이 거래는 다음과 같은 일을 달성하고자 합니다: 제 주소(0xeDc1…6909)에서 자가 송금하며, "force inclusion"이라는 텍스트 메시지를 첨부합니다.
이것은 제가 OptimismPortal 계약에서 depositTransaction 함수를 실행한 L1 거래입니다. 여기서 발생한 Transaction Deposited 이벤트에서 from과 to가 모두 저 자신임을 확인할 수 있습니다.
남은 opaque Data 항목의 값은 "deposit Transaction 함수를 호출한 사람이 얼마나 많은 ETH를 첨부했는지", "L2 거래 발신자가 수신자에게 얼마나 많은 ETH를 보내야 하는지", "L2 거래의 GasLimit" 및 "L2 수신자에게 전달할 Data" 등의 정보를 인코딩합니다.
위 정보를 디코딩하면 다음과 같은 결과를 얻습니다:
"deposit Transaction을 호출한 사람이 첨부한 ETH의 양": 0, 왜냐하면 저는 L1에서 L2로 ETH를 입금하지 않았기 때문입니다;
"L2 거래 발신자가 수신자에게 보내야 할 ETH의 양": 5566(wei)
"L2 거래의 GasLimit": 50000
"L2 수신자에게 전달할 Data": 0x666f72636520696e636c7573696f6e, 즉 "force inclusion"이라는 문자열의 16진수 인코딩입니다.
그 후 얼마 지나지 않아 변환된 L2 거래가 나타났습니다: 제가 자신에게 송금하는 L2 거래로, 금액은 5566 wei이며, Data는 "force inclusion" 문자열입니다. 또한 그림에서 두 번째 마지막 줄의 Other Attributes에서 TxnType(거래 유형)이 시스템 거래 126(System)으로 표시되어 있습니다. 이는 이 거래가 제가 L2에서 발신한 것이 아니라 L1 거래의 Deposited 이벤트에서 변환된 것임을 나타냅니다.
변환된 L2 거래
Force Inclusion을 통해 L2 계약을 호출하고 다른 Data를 전송하려면, 단순히 매개변수를 하나씩 앞의 deposit Transaction 함수에 입력하면 됩니다. 단, 자신의 L2 계좌와 동일한 L1 주소를 사용하여 deposit Transaction 함수를 호출해야 합니다. 이렇게 해야 Deposited Event가 L2 거래로 변환될 때 발신자가 당신의 L2 계좌가 됩니다.
SequencerWindow
앞서 언급한 Optimism L2 노드가 Transaction Deposited 이벤트를 L2 거래로 변환하는 것은 사실 Sequencer를 의미합니다. 거래 정렬과 관련이 있으므로, 오직 Sequencer만이 언제 해당 이벤트를 L2 거래로 변환할지를 결정할 수 있습니다.
Transaction Deposited 이벤트를 청취할 때, Sequencer는 반드시 즉시 이벤트를 L2 거래로 변환할 필요는 없으며, 약간의 지연이 있을 수 있습니다. 이 지연의 최대값을 SequencerWindow라고 합니다.
현재 Optimism 메인넷의 Sequencer Window는 24시간입니다. 즉, 사용자가 L1에서 돈을 입금하거나 Force Inclusion 거래를 제출할 경우, 최악의 경우 24시간 후에야 L2 거래 기록에 포함될 수 있습니다.
Arbitrum의 Force Inclusion 메커니즘
Optimism에서 L1의 Deposit 작업은 Transaction Deposited 이벤트를 발생시키고, 나머지는 Sequencer가 위 작업을 수록하기를 기다리는 것입니다. 그러나 Arbitrum에서는 L1에서 발생하는 작업(입금 또는 L2로 메시지 전송 등)이 단순히 이벤트를 발생시키는 것이 아니라 L1에 있는 큐에 저장됩니다.
Sequencer는 위 큐에 있는 거래를 L2 거래 기록에 포함시키기 위해 일정 시간을 부여받습니다. 만약 시간이 지나도 Sequencer가 아무런 조치를 취하지 않으면, 누구나 Sequencer를 대신하여 거래를 포함시킬 수 있습니다.
Arbitrum은 L1 계약에서 큐를 유지하며, Sequencer가 큐에 있는 거래를 적극적으로 처리하지 않으면, 시간이 지나면 누구나 큐의 거래를 L2 거래 기록에 강제로 포함시킬 수 있습니다.
Arbitrum의 설계에서 L1에서 발생하는 입금 등의 작업은 Delayed Inbox 계약을 통해 이루어지며, 이름에서 알 수 있듯이 이러한 작업은 지연되어 효력이 발생합니다. 또 다른 계약은 Sequencer Inbox로, Sequencer가 L2 거래를 L1에 업로드할 때의 직접적인 장소입니다. Sequencer가 L2 거래를 업로드할 때마다 Delayed Inbox에서 처리 대기 중인 거래를 함께 가져와 거래 기록에 작성할 수 있습니다.
Sequencer가 새로운 거래를 작성할 때 Delayed Inbox에서 거래를 함께 가져올 수 있습니다.
복잡한 설계 및 참고 자료
독자가 Arbitrum 공식 문서에서 Sequencer 및 Force Inclusion 섹션을 직접 참조하면, Force Inclusion이 대체로 어떻게 작동하는지와 일부 매개변수 및 함수 이름이 언급된 내용을 볼 수 있습니다:
사용자는 먼저 DelayedInbox 계약에서 sendUnsignedTransaction 함수를 호출해야 하며, 만약 Sequencer가 약 24시간 이내에 수록하지 않으면, 사용자는 SequencerInbox 계약의 forceInclusion 함수를 호출할 수 있습니다. 그러나 Arbitrum 공식 문서에는 함수 링크가 첨부되어 있지 않으며, 계약 코드에서 해당 함수들을 직접 찾아봐야 합니다.
sendUnsignedTransaction 함수를 찾으면, nonce 값과 maxFeePerGas 값을 직접 입력해야 한다는 것을 알게 됩니다. 어떤 주소의 nonce인가요? 어떤 네트워크의 maxFeePerGas인가요? 어떻게 입력해야 할까요? 문서 참조가 없고, Natpsec도 없습니다. 그런 다음 Arbitrum 계약에서 비슷한 함수들이 많이 발견됩니다:
sendL1FundedUnsignedTransaction, sendUnsignedTransactionToFork, sendContractTransaction, sendL1FundedContractTransaction 등, 이 함수들의 차이점이나 사용법, 매개변수 입력 방법에 대한 설명이 전혀 없습니다. Natpsec도 없습니다.
당신은 일단 시도해 보려는 마음으로 매개변수를 입력하고 거래를 제출하려고 하지만, 모든 함수가 당신의 L1 주소를 AddressAliasing하여 결국 L2에서 거래를 발신할 때의 Sender 주소가 전혀 다르게 되어버립니다. 그래서 당신의 L2 주소는 아무런 반응이 없습니다.
sendL2Message
그 후 우연히 Google 검색을 통해 Arbitrum에 자체적인 Tutorial 라이브러리가 있다는 것을 발견했습니다. 그 안에는 L1에서 L2 거래를 전송하는 방법(즉, Force Inclusion의 의미)을 보여주는 스크립트가 포함되어 있으며, 그곳에서 언급된 함수는 위에서 언급한 어떤 것도 아닌 sendL2Message라는 함수입니다. 그리고 message 매개변수는 L2 계좌로 서명된 거래를 포함해야 한다고 합니다.
누가 "Force Inclusion을 통해 L2에 전송할 메시지"가 "서명된 L2 거래"일 것이라고 알았겠습니까? 또한 이 함수의 사용 시점이나 방법에 대한 설명이 전혀 없습니다.
결론: Arbitrum의 강제 거래를 수동으로 생성하는 것은 상당히 번거롭습니다. 공식 Tutorial을 따라 Arbitrum SDK를 사용하는 것이 좋습니다. Arbitrum은 다른 Rollup과 달리 명확한 개발자 문서와 코드 주석이 없으며, 많은 함수의 용도와 매개변수에 대한 설명이 부족하여 개발자가 예상보다 더 많은 시간을 소모해야 합니다. 저도 Arbitrum Discord에서 Arbitrum 관계자에게 문의했지만 만족스러운 답변을 받지 못했습니다.
Discord에서 문의했을 때, 상대방은 저에게 sendL2Message를 보라고만 했지, 다른 함수의 기능(심지어 Force Inclusion 문서에서 언급된 sendUnsignedTransaction의 용도, 사용법, 시점 등)에 대해 설명해 주지 않았습니다.
StarkNet의 Force Inclusion 메커니즘
안타깝게도, StarkNet은 현재 Force Inclusion 메커니즘이 없습니다. 공식 포럼에서 검열 및 Force Inclusion에 대해 논의한 두 개의 글만 있습니다.
증명할 수 없는 실패한 거래
위의 이유는 사실 StarkNet의 제로 지식 증명 시스템이 실패한 거래를 증명할 수 없기 때문에 Force Inclusion을 허용할 수 없기 때문입니다. 만약 누군가 악의적(또는 무의식적으로)으로 실패한 거래를 강제로 포함시키면, StarkNet은 직접 멈추게 됩니다. 왜냐하면 거래가 강제로 포함된 후, Prover는 해당 실패 거래를 증명해야 하지만, 증명할 수 없기 때문입니다.
StarkNet은 v0.15.0 버전에서 실패한 거래를 증명하는 기능을 도입할 예정이며, 이후에는 Force Inclusion 메커니즘을 구현할 수 있을 것입니다.
zkSync의 Force Inclusion 메커니즘
zkSync의 L1->L2 메시지 전송 및 Force Inclusion 메커니즘은 MailBox 계약의 requestL2Transaction 함수를 통해 이루어집니다. 사용자는 L2 주소, calldata, 첨부할 ETH 양, L2 GasLimit 값 등을 지정하며, requestL2Transaction은 이러한 매개변수를 조합하여 L2 거래를 생성하고, 우선 순위 큐(PriorityQueue)에 넣습니다. Sequencer는 거래를 L1에 패키징하여 업로드할 때(commitBatches 함수 사용), 우선 순위 큐에서 얼마나 많은 거래를 함께 수록할지를 지정합니다.
zkSync의 Force Inclusion 형태는 Optimism과 매우 유사하며, 발신자의 L2 주소(및 L1 주소와 동일)를 사용하여 관련 함수를 호출하고 정보를 입력합니다(호출자, calldata 등). Arbitrum과는 달리 서명된 L2 거래를 입력하는 것이 아닙니다. 그러나 설계상으로는 Arbitrum과 유사하게 L1에서 큐를 유지하고, Sequencer가 사용자가 직접 제출한 대기 거래를 큐에서 꺼내 거래 기록에 작성합니다.
사용자가 zkSync의 공식 브리지를 통해 ETH를 Deposit하면, 이 거래는 MailBox 계약의 requestL2Transaction 함수를 호출하게 되며, 이 과정에서 Deposit ETH의 L2 거래가 우선 순위 큐에 넣어지고 NewPriorityRequest 이벤트가 발생합니다. 계약이 L2 거래 정보를 인코딩하여 바이트 문자열로 변환하므로 읽기 어렵지만, 이 L1 거래의 매개변수를 보면 L2 수신자도 거래 발신자와 동일하다는 것을 알 수 있습니다(자신에게 Deposit하기 때문입니다). 따라서 잠시 후 이 L2 거래가 Sequencer에 의해 우선 순위 큐에서 꺼내져 거래 기록에 포함될 때, L2에서 자신에게 송금하는 거래로 변환되며, 송금 금액은 거래 발신자가 L1의 Deposit ETH 거래에서 첨부한 ETH 금액입니다.
L1 Deposit 거래에서 거래 발신자와 수신자는 모두 0xeDc1…6909이며, 금액은 0.03ETH이고, calldata는 비어 있습니다.
L2에서는 0xeDc1…6909가 자신에게 송금하는 거래가 발생하며, 거래 유형(TxnType)은 255로, 시스템 거래입니다.
그 후 저는 이전에 Optimism의 강제 거래 기능을 실험한 것처럼 zkSync의 requestL2Transaction 함수를 호출하여 자가 송금 거래를 보냈습니다: 아무 ETH도 첨부하지 않고, calldata에 "force inclusion" 문자열의 HEX 인코딩을 포함했습니다.
그 후 이 거래는 L2에서 자신에게 송금하는 거래로 변환되며, calldata에는 "force inclusion"의 16진수 문자열이 포함됩니다: 0x666f72636520696e636c7573696f6e.
Sequencer가 거래를 우선 순위 큐에서 꺼내어 거래 기록에 작성할 때, L2에서 해당 L2 거래로 변환됩니다.
사용자는 requestL2Transaction 함수를 통해 L1에서 L2 주소와 동일한 계좌를 사용하여 정보를 제출하고, L2 수신자, 첨부할 ETH 금액 및 calldata를 지정할 수 있습니다. 사용자가 다른 계약을 호출하거나 다른 Data를 첨부하려면, 매개변수를 하나씩 requestL2Transaction 함수에 입력하면 됩니다.
아직 사용자가 강제로 수록할 수 있는 기능이 없음
비록 L2 거래가 우선 순위 큐에 넣어진 후, 이 L2 거래가 Sequencer에 의해 수록될 대기 기간이 계산되지만, 현재 zkSync 설계에는 사용자가 강제로 실행할 수 있는 Force Inclusion 함수가 없습니다. 즉, 반쪽짜리 기능만 제공하는 것입니다. 즉, "수록 대기 기간"이 있지만, 실제로는 "Sequencer가 수록할지 여부"를 지켜봐야 합니다: Sequencer는 만료된 후에야 수록할 수 있으며, 우선 순위 큐의 거래를 영원히 수록하지 않을 수도 있습니다.
향후 zkSync는 관련 함수를 추가하여 사용자가 유효 기간이 만료되었지만 Sequencer에 의해 수록되지 않은 경우, 거래를 강제로 L2 거래 기록에 포함할 수 있도록 해야 합니다. 그래야 진정한 Force Inclusion 메커니즘이 구현될 수 있습니다.
요약
L1은 수많은 검증자들에 의해 네트워크의 "안전성" 및 "검열 저항 능력"을 보장합니다. Rollup은 소수 또는 단일 Sequencer에 의해 거래를 기록하므로 검열 저항 능력이 더 약합니다. 따라서 Rollup은 Force Inclusion 메커니즘을 통해 사용자가 Sequencer를 우회하여 거래를 기록할 수 있도록 해야 하며, Sequencer의 검열로 인해 사용 불가능하거나 자금을 Rollup에서 인출할 수 없는 상황을 피해야 합니다.
Force Inclusion은 사용자가 거래를 기록할 수 있도록 강제하지만, 설계상으로는 "거래가 즉시 기록될 수 있는지, 즉시 효력이 발생할 수 있는지"에 대한 선택을 해야 합니다. 거래가 즉시 효력이 발생하도록 허용하면 Sequencer에 부정적인 영향을 미치게 됩니다. 왜냐하면 L2에서 수록 대기 중인 거래는 L1에서 강제로 수록된 거래에 의해 영향을 받을 수 있기 때문입니다.
따라서 현재 Rollup의 Force Inclusion 메커니즘은 L1에서 삽입된 거래가 대기 상태에 들어가도록 하고, Sequencer가 이러한 대기 거래를 수록할지를 반응할 수 있는 시간 창을 제공합니다.
zkSync와 Arbitrum은 L1에서 큐를 유지하여 사용자가 L1에서 보낸 L2 거래 또는 L2로의 메시지를 관리합니다. Arbitrum은 DelayedInbox라고 부르며, zkSync는 PriorityQueue라고 부릅니다.
하지만 zkSync가 L2 거래를 보내는 방식은 Optimism과 유사하여, L2 주소를 사용하여 L1에서 메시지를 보내고, L2 거래로 변환된 후 발신자가 해당 L2 주소가 됩니다. Optimism은 L2 거래를 보내는 함수를 depositTransaction이라고 하며, zkSync는 requestL2Transaction이라고 합니다. Arbitrum은 완전한 L2 거래를 생성하고 서명한 후 sendL2Message 함수를 통해 전송하며, L2에서 서명을 통해 서명자를 복원하여 L2 거래의 발신자로 사용합니다.
StarkNet은 현재 Force Inclusion 메커니즘이 없으며, zkSync는 반쪽짜리 Force Inclusion을 구현하고 있습니다. --- PriorityQueue가 있으며 각 Queue의 L2 거래는 수록 유효 기간이 있지만, 현재 이 유효 기간은 장식용일 뿐이며, 실제로 Sequencer는 PriorityQueue의 L2 거래를 수록하지 않을 수 있습니다.