headphones
How Ethereum L2 Linea proactively shuts down 4 mainstream Rollups and resists censorship
528btc
528btc
authIcon
BCrypto Pioneer
2024-08-02 16:30
Follow
Focus
The sorter of Layer2 is unlikely to have much decentralization, and ultimately may not be as decentralized as the BSC chain. If that's really the case, what should we do?
Helpful
Unhelpful
Play

Author:Token Analyst

Author: NIC Lin, Head of Taipei Ethereum Meetup

Title: Introduction to Rollup's Force Inclusion Mechanism

Just yesterday, something shocked countless people: the Ethereum Layer 2 Linea, launched by Consensus, the parent company of Metamask, voluntarily shut down. The official stated that the purpose of doing so was to reduce the impact of the Velocore hacker attack. And this inevitably reminds people of the previous incident where BSC Chain (BNB Chain) shut down under official coordination in order to reduce the losses of hacker attacks. Whenever people talk about this, they tend to doubt the decentralized value advocated by Web3.

Of course, the core reason for the above-mentioned events lies more in the inadequate infrastructure itself, that is, the lack of decentralization: if a chain is decentralized enough, then it should not stop at will. Due to the unique construction of Ethereum's Layer 2, most Layer2 relies on a centralized Sequencer. Although there has been an increasing discourse on decentralized sequencers in recent years, considering the purpose and structure of Layer 2, we can assume that Layer2's sequencers are unlikely to have much decentralization and may not even be as decentralized as the BSC chain. If that's really the case, what should we do?

In fact, for the second layer, the most direct harm caused by the lack of decentralization in the sorter lies in its resistance to censorship and activity. If there are few entities (sequencers) handling transactions, then it has absolute power over whether or not to serve you: if you want to reject you, reject you, and you may have no choice. How to solve the anti censorship problem of Layer2 is obviously an important topic.

In the past few years, various solutions have been proposed by Ethereum's second layer to combat censorship issues, such as Loopring and Degate, as well as StarkEx's forced withdrawal and escape pod functions, Arbitrarum, and other OP Rollup's Force Inclusion functions. These methods can create checks and balances on Sequencers under certain conditions to prevent them from unreasonably rejecting any user's transaction requests.

In today's article, NIC Lin from the Taipei Ethereum Association personally tested the anti censorship transaction function of four mainstream Rollups, and analyzed the mechanism design of Force Inclusion in depth from the aspects of workflow and operation methods. This is particularly valuable for the Ethereum community and large holders of huge assets as a reference.

Transaction Review and Force Inclusion

Censorship Resistance is crucial for a blockchain. If a blockchain can arbitrarily review and reject transactions initiated by users, it is no different from a Web2 server. The current anti censorship capability of Ethereum's transactions comes from its numerous Validator. If someone wants to review Bob's transactions and prevent them from being put on the chain, they either try to buy most of the Validator in the network or spam the entire network, constantly sending out garbage transactions with higher transaction fees than Bob to seize block space. Either way, the cost will be very high.

Note: In the current PBS architecture of Ethereum, the cost of reviewing transactions will be significantly reduced. You can refer to the proportion of blocks that cooperate with OFAC to review Tornado Cash transactions. The current ability to resist censorship relies on independent validators and relays outside the jurisdiction of OFAC and government.

But what about Rollup? Rollup does not require a bunch of validators to ensure security, even if Rollup only has one centralized role (Sequencer) to produce blocks, it is as secure as L1. But security and anti censorship capabilities are two different things. Even if a Rollup is as secure as Ethereum, with only one centralized Sequencer, any user's transaction can be censored.

Sequencer can refuse to process user transactions, resulting in user funds being withheld and unable to leave the Rollup

Force Inclusion Mechanism

Instead of requiring Rollup to have a large number of decentralized sequencers, it is better to directly utilize L1's anti censorship capabilities:

Originally, Sequencer was supposed to package transaction data into L1's Rollup contract. It's better to add a design in the contract that allows users to insert transactions into the Rollup contract themselves. This mechanism is called "Force Inclusion". As long as Sequencer cannot review users at the L1 level, it cannot prevent users from forcibly inserting transactions in L1. In this way, Rollup can inherit L1's ability to resist censorship.

Sequencer cannot review users' L1 transactions unless a high cost is incurred

How should mandatory trading take effect?

If the transaction is allowed to be directly written into the Rollup contract through Force Inclusion (i.e. immediately effective), the state of Rollup will immediately change. For example, if Bob inserts a "transfer 1000 DAI to Carol" transaction through the Force Inclusion mechanism, and the transaction takes effect immediately, Bob's balance in the latest state will be 1000 DAI less and Carol will be 1000 DAI more.

If Force Inclusion can directly write the transaction into the Rollup contract and take immediate effect, the status will change immediately

If the Sequencer is also collecting transactions off chain at this time and sending the next batch of transactions to the Rollup contract, it may be affected by Bob's forced insertion and immediately effective transactions. This kind of problem should be avoided as much as possible, so Rollup generally does not allow Force Inclusion transactions to take effect immediately. Instead, users are first asked to insert the transaction into the waiting queue on L1 and enter the "in preparation" state.

When the Sequencer packages off chain transactions and sends them to the Rollup contract, it chooses whether to include the aforementioned transactions in the transaction sequence. If the Sequencer continues to ignore these transactions that are in a "preparation" state, after the window period ends, the user can forcibly insert these transactions into the Rollup contract.

Sequencer can decide when to 'incidentally collect' and wait for transactions in the queue

Sequencer can still refuse to process transactions in the waiting queue

If Sequencer refuses for a long time, anyone can forcefully insert the transaction into the Rollup contract through the Force Inclusion function after a period of time

Next, we will introduce four well-known Rollup Force Inclusion mechanisms, namely Optimism, Arbitrarum, StarkNet, and zkSync, in sequence.

The Force Inclusion Mechanism of Optimism

Firstly, let's introduce the Deposit process of Optimism, which not only refers to depositing money into Optimism, but also includes sending the information sent by the user to L2. After receiving the newly deposited message, the L2 node will convert the message into an L2 transaction to execute and deliver it to the designated recipient of the message.

Message from L1 Deposit to L2 by the user

L1CrossDomainMessenger Contract

When a user wants to deposit ETH or ERC-20 tokens into Optimism, they will interact with the L1StandardBridge contract on L1 through the front-end webpage, specifying how much to deposit and which L2 address to receive these assets from.

The L1StandardBridge contract will pass messages to the L1CrossDomainMessenger contract in the next layer, which mainly serves as a communication component between L1 and L2. The L1StandardBridge communicates with the L2StandardBridge on L2 through this universal communication component to determine who can mint tokens in L2 or unlock tokens from L1.

If a developer needs to develop a contract for interoperability and synchronization between L1 and L2, they can build it on top of the L1CrossDomainMessenger contract.

User messages are transmitted from L1 to L2 through the CrossDomainMessenger contract. Note: In some of the images in this article, CrossDomainMessenger is written as CrossChainMessenger

OptimismPortal Contract

The L1CrossDomainMessenger contract will then send the message to the lowest level OptimismoPortal contract. After processing, the OptimismoPortal contract will throw an event called TransactionDeposited, with parameters including "sender", "recipient", and related execution parameters.

Next, the Optimism node of L2 will listen to the Transaction Deposited event thrown by the OptimismoPortal contract and convert the parameters in the event into an L2 transaction. The initiator of this transaction will be the "sender" specified in the Transaction Deposited event parameters, and the transaction recipient will be the "receiver" specified in the event parameters. Other transaction parameters are also derived from the parameters in the above event.

The L2 node will convert the Transaction Deposited event parameter of OptimismoPortalemit into an L2 transaction

For example, this is a transaction where a user deposits 0.01 ETH through the L1StandardBridge contract. This message and ETH are transmitted all the way to the OptimismoPortal contract (address 0xbEb5... 06Ed), and then converted into an L2 transaction a few minutes later:

The initiator of the message is the L1CrossDomainMessenger contract; The recipient is the L2CrossDomainMessenger contract on L2; The message states that L1StandardBridge has received a 0.01 ETH deposit from BoB. Afterwards, some processes will be triggered, such as issuing 0.01 ETH for L2StandardBridge, which will then be transferred to Bob.

How to trigger it specifically

When you want to force a transaction into Optimism's Rollup contract, the effect you want to achieve is to ensure that a "transaction initiated and to be executed from your L2 address on L2" can be executed smoothly. At this point, you should submit the message directly to the Optimism Portal contract using your own L2 address (note that the Optimism Portal contract is actually on L1, but the OP's address format is the same as the L1 address format. You can directly call the above contract using the L1 account with the same address as the L2 account).

Afterwards, the "initiator" of the L2 transaction converted from the Transaction Deposited event thrown by the contract will be your L2 account, and the transaction format will be consistent with normal L2 transactions.

In the L2 transaction converted from the Transaction Deposited event, the initiator will be Bob himself; The recipient is the Uniswap contract; And it will come with a specified ETH, just like Bob initiating L2 transactions himself

If you want to call the Force Inclusion function of Optimism, you need to directly call the deposit Transaction function of the OptimismoPortal contract and fill in the parameters of the transaction you want to execute in L2

I conducted a simple Force Inclusion experiment, and this transaction aims to achieve the following: self transfer on L2 using my address (0xeDc1... 6909), with a text message indicating "force inclusion".

This is an L1 transaction executed by me through the OptimismoPortal contract using the sedimentTransaction function. It can be seen that in the Transaction Deposited event it throws, both from and to are myself

The remaining values in the opaque Data column encode information such as "how much ETH the person calling the deposit transaction function has attached", "how much ETH the L2 transaction initiator needs to send to the receiver", "L2 transaction GasLimit", and "Data for the L2 receiver".

After decoding the above information, we will obtain:

How much ETH did the person calling deposit transaction attach? ": 0, because I did not deposit ETH from L1 to L2;

How much ETH should the L2 transaction initiator send to the receiver? ": 5566 (wei)

GasLimit for L2 trading: 50000

'Data for L2 receiver': 0x666f72636520696e636c7573696f6e, which is the hexadecimal encoding of the string 'force inclusion'

Not long after, a converted L2 transaction appeared: an L2 transaction where I transferred money to myself, with an amount of 5566 wei and Data as the "force inclusion" string. Moreover, it can be noted that the TxnType (transaction type) in the Other Attributes of the second to last row in the figure shows System transaction 126, indicating that this transaction was not initiated by myself in L2, but was converted from the Deposited event of L1 transaction.

L2 transaction converted into

If you want to call L2 contracts and send different data through Force Inclusion, it's nothing more than filling in the parameters one by one into the deposit transaction function in front of you. Just remember to call the deposit transaction function with the same L1 address as your L2 account, so that when the deposited event is converted into an L2 transaction, the initiator is your L2 account.

SequencerWindow

The Optimism L2 node mentioned earlier converts the Transaction Deposited event into an L2 transaction. In fact, this Optimism node refers to the Sequencer, as it is related to transaction sorting. Therefore, only the Sequencer can decide when to convert the aforementioned event into an L2 transaction.

When monitoring the TransactionDeposited event, the Sequencer may not immediately convert the event into an L2 transaction, and there may be a delay, the maximum value of which is called SequencerWindow.

At present, the Sequencer Window on the Optimism main website is 24 hours, which means that when a user deposits a sum of money or Force Inclusion transaction from L1, the worst-case scenario is that it is not included in the L2 transaction history until 24 hours later.

Arbitrarum's Force Inclusion Mechanism

In Optimism, the Deposit operation of L1 will throw a Transaction Deposited event, and the rest is to wait for the Sequencer to record the above operation; But in Arbitrarum, operations that occur in L1 (such as saving money or sending messages to L2) will be stored in a queue on L1 instead of simply throwing an event.

The Sequencer will be given a period of time to include the transactions in the queue in the L2 transaction history. If the Sequencer does not take any action by the time, anyone can complete it for the Sequencer.

Arbitrarum will maintain a queue in the L1 contract. If the Sequencer does not actively process the transactions in the queue, anyone can force the transactions in the queue to be included in the L2 transaction history when the time is up

In the design of Arbitrarum, operations such as deposits that occur on L1 must go through the Delayed Inbox contract, as the name suggests, all operations here will be delayed in taking effect; The other contract is Sequencer Inbox, which is the direct location where Sequencer uploads L2 transactions to L1. Every time Sequencer uploads L2 transactions, it can also retrieve some pending transactions from the Delayed Inbox and write them into the transaction history.

When the Sequencer writes a new transaction, it can also take out the transaction from the Delayed dInbox and write it together with complex designs and reference materials that can be easily presented

If readers directly refer to the official section of Arbitrarum on Sequencer and Force Inclusion, they will see that it roughly explains how Force Inclusion works, as well as some parameter and function names:

The user first goes to the DelayedInbox contract and calls the sendunsigned Transaction function. If the Sequencer is not indexed within about 24 hours, the user can call the forceInclusion function of the SequencerInbox contract. And then the official website of Arbitrarum did not attach the link to the function in the official documentation, so they had to look at the corresponding function in the contract code themselves.

When you find the sendunsigned Transaction function, you realize that you have to fill in the nonce value and maxFeePerGas value yourself. Which address's nonce is it? Which network is maxFeePerGas on? How to fill it out better? There are no file references, not even Natpsec. Then you will also find a bunch of functions in the Arbitrarum contract that look similar:

sendL1FundedUnsignedTransaction、sendUnsignedTransactionToFork、sendContractTransaction、sendL1FundedContractTransaction, There is no file that tells you the differences between these functions, how to use them, how to fill in parameters, not even Natpsec.

You try to fill in the parameters and send out the transaction with a trial and error mentality, hoping to find the correct usage through trial and error. However, you find that all these functions will use your L1 address as AddressAliasing, resulting in a completely different sender address when initiating the transaction on L2. As a result, your L2 address remains unchanged.

sendL2Message

Later, by chance, I clicked on Google search and discovered that Arbitrarum had its own Tutorial library, which included scripts demonstrating how to send L2 transactions from L1 (meaning Force Inclusion). However, the functions it listed were not any of the ones mentioned above, but rather a function called sendL2Message, and the message parameter was actually a transaction signed with an L2 account?

Who would have known that the message sent to L2 through Force Inclusion would actually be a signed L2 transaction? And there are no files or Natspec explanations on when and how to use this function.

Conclusion: It is difficult to manually generate a forced transaction for Arbitrarum. It is recommended to follow the official tutorial to run the Arbitrarum SDK. Unlike other Rollups, Arbitrarum does not have clear developer documentation and code annotations, and many functions lack explanation of their purpose and parameters, resulting in developers spending more time than expected to access and use them. I also asked the people at Arbitrarum Discord, but did not receive satisfactory answers.

When asked on Discord, the other party only asked me to look at sendL2Message and did not want to explain the functions of other functions (even the sendUnsigned Transaction mentioned in the Force Inclusion document) for what purpose, how to use it, and when to use it.

StarkNet's ForceIclusion mechanism

Unfortunately, StarkNet currently does not have a ForceIclusion mechanism. There are only two articles discussing Censorship and ForceIclusion on the official forum.

Unable to prove failed transactions

The above reason is actually because StarkNet's zero knowledge proof system cannot prove a failed transaction, so Force Inclusion cannot be allowed. Because if someone maliciously (or unintentionally) Force Include a failed, unproven transaction, StarkNet will simply get stuck: because after the transaction is forcibly collected, the Prover must prove the failed transaction, but it cannot prove it.

StarkNet expects to introduce the function of proving failed transactions in version 0.15.0, after which it should be possible to further implement the Force Inclusion mechanism.

Force Inclusion Mechanism of zkSync

The L1->L2 message transmission and Force Inclusion mechanism of zkSync are both carried out through the requestL2Transaction function of the MailBox contract. The user specifies the L2 address, calldata, additional ETH amount, L2GasLimit value, etc. requestL2Transaction will combine these parameters into an L2 transaction and put it in the PriorityQueue. The Sequencer will indicate how many transactions need to be included in the L2 transaction record when the transaction is packaged and uploaded to L1 (through the commit Batches function).

ZkSync is similar to Optimism in terms of Force Inclusion, as it calls relevant functions using the initiator's L2 address (which is consistent with the L1 address) and fills in data (called party, calldata, etc.), rather than filling in a signed L2 transaction like Arbitrarum; But in terms of design, it is the same as Arbitrarum, which maintains a queue in L1, and the Sequencer retrieves the pending transactions directly submitted by users from the queue and writes them into the transaction history.

If you deposit ETH through the official bridge of zkSync, like this transaction, it will call the requestL2Transaction function of the MailBox contract, which will put the L2 transaction of depositing ETH into the priority queue and throw a NewPriorityRequest event. Because the contract encodes L2 transaction data into a string of bytes, it is not easy to read. If we look at the parameters of this L1 transaction, we will see that the recipient of L2 in the parameters is also the initiator of the transaction (because it is deposited to oneself). Therefore, after a while, when this L2 transaction is taken out of the priority queue by Sequencer and included in the transaction history, it will be converted into a transaction transferred to oneself on L2, and the transferred amount is the ETH amount carried by the transaction initiator in L1's Deposit ETH transaction.

In the L1Deposit transaction, both the initiator and receiver are 0xeDc1... 6909, the amount is 0.03ETH, and calldata is empty

On L2, there will be a transaction of 0xeDc1... 6909 transferring funds to oneself, with a transaction type (TxnType) of 255, which is a system transaction

Then I directly called the requestL2Transaction function of zkSync, just like I did in the previous experiment with OP's forced trading function, and sent a self transfer: without any ETH, calldata was encoded in HEX with the "force inclusion" string.

Then it is converted into a self converted transaction on L2, with the hexadecimal string "force inclusion" in calldata: 0x666f72636520696e636c7573696f6e.

When the Sequencer retrieves the transaction from PriorityQueue and writes it into the transaction history, it will be converted into the corresponding L2 transaction on L2

Through the requestL2Transaction function, users can use the same L1 account as the L2 address to submit data in L1, specifying the L2 recipient, attached ETH amount, and calldata. If the user wants to call other contracts with different data, the same is to fill in the parameters one by one into the requestL2Transaction function.

There is no mandatory inclusion feature for users yet

Although the waiting period for the L2 transaction to be included in the Sequencer will be calculated when it is placed in the priority queue, there is currently no Force Inclusion function in zkSync design that allows users to enforce it, which is equivalent to only half a set. That is to say, although there is a "waiting period for inclusion", in reality, it still depends on whether the Sequencer should be included: Sequencers can wait until it expires before being included, or they can never be included in any transactions in the priority queue again.

In the future, zkSync should add relevant functions that allow users to force transactions to be included in L2 transaction history when their income validity period has expired but they have not yet been indexed by Sequency. This is the truly effective Force Inclusion mechanism.

summary

L1 relies on numerous validators to ensure the "security" and "anti censorship ability" of the network, while Rollup has weaker anti censorship ability because it is written into transactions by a few or even a single Sequencer. Therefore, Rollup needs a Force Inclusion mechanism to allow users to bypass Sequencer and write transactions into history, avoiding being reviewed by Sequencer and unable to use or withdraw funds from the Rollup.

Force Inclusion allows users to force transactions to be written into the history, but in terms of design, they need to choose whether the transaction can be immediately inserted into the history and take effect immediately. If trades are allowed to take effect immediately, it will have a negative impact on Sequencer, as trades waiting to be collected on L2 may be affected by exchanges that are forcibly collected by L1.

Therefore, currently Rollup's Force Inclusion mechanism will first put the transactions inserted on L1 into a waiting state, and give Sequencer a time window to react and choose whether to include these waiting transactions.

Both zkSync and Arbitrarum maintain a queue in L1 to manage L2 transactions or messages sent by users from L1 to L2. Arbitrarum is called DelayedInbox; ZkSync is called PriorityQueue

But the way zkSync sends L2 transactions is similar to Optimism, both sending messages to L1 using L2 addresses. After converting to L2 transactions, the initiator will be the same L2 address. The function that Optimism uses to send L2 transactions is called sedimentTransaction; ZkSync is called requestL2Transaction. And Arbitrarum generates a complete L2 transaction and signs it, then sends it out through the sendL2Message function. Arbitrarum restores the signer as the initiator of the L2 transaction through the signature on L2.

StarkNet currently does not have a Force Inclusion mechanism; ZkSync is like doing half a set of Force Inclusion, with PriorityQueue and each L2 transaction in the queue has a validity period for inclusion, but this validity period is currently only for decoration. In fact, Sequencer can choose not to include any L2 transactions in PriorityQueue at all

Open App for Full Article
DisclaimerThis website, hyperlinks, related apps, forums, blogs, media accounts, and other platforms' content are all sourced from third-party platforms and users. CoinWorldNet makes no guarantees about the website or its content. All blockchain data and other materials are for educational and research purposes only and do not constitute investment, legal, or other advice. Users of the CoinWorldNet and third-party platforms are solely responsible for the content they post, which is unrelated to CoinWorldNet. CoinWorldNet is not liable for any loss arising from the use of this website's information. You should use the data and content cautiously and bear all associated risks. It is strongly recommended that you independently research, review, analyze, and verify the content.
Comments(0)
Popular
Latest

No Comments

edit
comment
collection
like
share