
Cựu đại sứ kỹ thuật Arbitrum giải thích cấu trúc thành phần của Arbitrum (phần 2)
Tuyển chọn TechFlowTuyển chọn TechFlow

Cựu đại sứ kỹ thuật Arbitrum giải thích cấu trúc thành phần của Arbitrum (phần 2)
Arbitrum xử lý việc truyền tin nhắn liên chuỗi và giao dịch chống kiểm duyệt như thế nào?
Tác giả: Laobenben, Cựu Đại sứ Kỹ thuật Arbitrum, Người đóng góp web3 đam mê công nghệ
Trong bài viết trước "Cựu Đại sứ Kỹ thuật Arbitrum Giải thích Cấu trúc Thành phần của Arbitrum (Phần 1)", chúng ta đã giới thiệu các thành phần cốt lõi của Arbitrum như Sequencer (Bộ sắp xếp), Validator, Hợp đồng Sequencer Inbox, Rollup Block và chức năng của bằng chứng gian lận không tương tác. Trong bài viết hôm nay, chúng ta sẽ tập trung vào các thành phần cốt lõi của Arbitrum liên quan đến truyền tin nhắn xuyên chuỗi và cơ chế chống kiểm duyệt cho giao dịch.
Trước đó, chúng tôi từng đề cập rằng hợp đồng Sequencer Inbox chuyên tiếp nhận các gói dữ liệu giao dịch (batch) do bộ sắp xếp phát hành trên Layer 1. Đồng thời, chúng tôi cũng chỉ ra rằng Sequencer Inbox còn được gọi là hộp nhanh (fast inbox), đối lập với nó là hộp chậm Delayed Inbox (gọi tắt là Inbox). Dưới đây, chúng tôi sẽ phân tích chi tiết về Delayed Inbox và các thành phần liên quan đến truyền tin nhắn xuyên chuỗi.

Nguyên lý xuyên chuỗi và cầu nối
Giao dịch xuyên chuỗi có thể chia thành hai hướng: từ L1 sang L2 (nạp tiền) và từ L2 sang L1 (rút tiền). Lưu ý rằng "nạp tiền" và "rút tiền" ở đây không nhất thiết phải liên quan đến việc di chuyển tài sản xuyên chuỗi; chúng có thể đơn thuần là việc truyền tải tin nhắn không kèm theo tài sản. Vì vậy, hai từ này chỉ đơn giản biểu thị hai chiều hướng hành vi xuyên chuỗi.
So với giao dịch thuần L2, giao dịch xuyên chuỗi phức tạp hơn vì nó thực hiện trao đổi thông tin giữa hai hệ thống khác nhau là L1 và L2.
Hơn nữa, thông thường khi nói đến hành vi xuyên chuỗi, người ta nghĩ đến việc sử dụng cầu nối kiểu "người làm chứng" (witness) giữa hai mạng lưới hoàn toàn độc lập. Loại cầu nối này an toàn tùy thuộc vào người vận hành – trong lịch sử, các sự cố bị tấn công xảy ra khá thường xuyên đối với loại cầu nối dựa trên mô hình witness.
Tuy nhiên, hành vi xuyên chuỗi giữa Rollup và mạng chính ETH lại bản chất khác biệt so với loại trên, bởi vì trạng thái của Layer 2 được quyết định bởi dữ liệu ghi lại trên Layer 1. Miễn là bạn sử dụng cầu nối chính thức của Rollup, cấu trúc vận hành của nó là tuyệt đối an toàn.
Điều này làm nổi bật bản chất của Rollup: mặc dù nhìn từ góc độ người dùng giống như một chuỗi độc lập, nhưng thực tế thì cái gọi là «Layer 2» chỉ là cửa sổ hiển thị nhanh mà Rollup mở ra cho người dùng; cấu trúc chuỗi thật sự vẫn được khắc ghi trên Layer 1. Do đó, ta có thể coi L2 là nửa chuỗi, hoặc nói cách khác là «một chuỗi được tạo ra trên Layer 1».
Vé thử lại (Retryables)
Cần lưu ý rằng mọi hoạt động xuyên chuỗi đều mang tính bất đồng bộ và không nguyên tử. Không thể như trên một chuỗi duy nhất, sau khi xác nhận xong giao dịch thì biết ngay kết quả, cũng không thể đảm bảo điều gì sẽ chắc chắn xảy ra tại thời điểm nào đó bên kia chuỗi. Do đó, giao dịch xuyên chuỗi có thể thất bại do một số vấn đề mềm, nhưng nếu dùng đúng phương pháp, ví dụ như Vé thử lại (Retryable Ticket), thì sẽ không xảy ra các vấn đề cứng như tiền bị mắc kẹt.
Vé thử lại là công cụ cơ bản được dùng khi nạp tiền qua cầu nối chính thức Arbitrum, cả ETH và ERC20 đều sử dụng. Vòng đời của vé trải qua ba bước:
1. Gửi vé tại L1. Sử dụng phương thức createRetryableTicket() trong hợp đồng Delayed Inbox để tạo vé nạp tiền rồi gửi đi.
2. Tự động thanh toán tại L2. Trong hầu hết trường hợp, bộ sắp xếp có thể tự động giúp người dùng thanh toán vé, không cần thao tác thủ công thêm.
3. Thanh toán thủ công tại L2. Một số trường hợp biên như giá gas tại L2 tăng vọt khiến lượng gas trả trước trên vé không đủ, dẫn đến không thể tự động thanh toán. Lúc này người dùng phải tự xử lý.
Lưu ý: Nếu thanh toán tự động thất bại, người dùng phải tự tay thanh toán vé trong vòng 7 ngày, nếu không vé sẽ bị xóa (tiền sẽ mất vĩnh viễn), hoặc phải trả phí gia hạn để giữ vé.
Ngoài ra, quy trình rút tiền qua cầu nối chính thức Arbitrum tuy có chút tương đồng đối xứng với nạp tiền, nhưng không tồn tại khái niệm Retryables. Điều này có thể hiểu từ chính giao thức Rollup, hoặc qua một vài điểm khác biệt:
-
Quá trình rút tiền không có cơ chế thanh toán tự động, vì EVM không có bộ hẹn giờ hay tự động hóa, còn tại L2 việc tự động thanh toán là nhờ bộ sắp xếp hỗ trợ. Vì vậy tại L1, người dùng phải tự tương tác với hợp đồng Outbox để Claim (nhận lại) tài sản.
-
Rút tiền cũng không có vấn đề vé quá hạn, miễn là đã qua giai đoạn thách thức, người dùng có thể nhận tài sản vào bất kỳ lúc nào.
Cổng Gateway cho tài sản ERC-20 xuyên chuỗi
Xuyên chuỗi tài sản ERC-20 là vấn đề phức tạp. Hãy suy nghĩ một vài câu hỏi:
-
Một token đã triển khai trên L1 thì nên triển khai thế nào lên L2?
-
Hợp đồng tương ứng tại L2 cần được triển khai thủ công trước, hay hệ thống có thể tự động triển khai hợp đồng tài sản cho token chưa có hợp đồng trên L2?
-
Địa chỉ hợp đồng tương ứng của tài sản ERC-20 trên L1 tại L2 là gì? Có cần trùng khớp với L1?
-
Token phát hành gốc tại L2 thì làm sao để đưa về L1?
-
Token có chức năng đặc biệt như token rebase (điều chỉnh số lượng), token sinh lãi tự động, thì xuyên chuỗi thế nào?
Chúng tôi không định trả lời tất cả các câu hỏi này vì sẽ rất phức tạp. Chúng chỉ nhằm minh họa độ phức tạp của việc xuyên chuỗi ERC20.

Hiện nay rất nhiều giải pháp mở rộng dùng phương án danh sách trắng + danh sách thủ công để tránh các vấn đề phức tạp và tình huống biên.
Arbitrum sử dụng hệ thống Gateway để giải quyết phần lớn các điểm đau trong việc xuyên chuỗi ERC20, với những đặc điểm sau:
-
Thành phần Gateway xuất hiện thành cặp ở cả L1 và L2.
-
Gateway Router chịu trách nhiệm duy trì ánh xạ địa chỉ giữa Token L1<->Token L2, cũng như ánh xạ giữa some token <-> some gateway.
-
Bản thân Gateway có thể chia thành StandardERC20 gateway, Generic-custom gateway, Custom gateway,... để giải quyết các vấn đề cầu nối cho các loại và chức năng ERC20 khác nhau.
Ta lấy ví dụ đơn giản là WETH xuyên chuỗi để thấy rõ nhu cầu cần gateway tùy chỉnh.
WETH là dạng ERC20 tương đương với ETH. Ether là đồng tiền chính, nhiều chức năng phức tạp trong dApp không thể thực hiện được, do đó cần một phiên bản tương đương dưới dạng ERC20. Khi gửi ETH vào hợp đồng WETH, số ETH này sẽ bị khóa lại và sinh ra lượng WETH tương ứng.
Tương tự, có thể hủy WETH để rút lại ETH. Rõ ràng, số lượng WETH đang lưu hành và số lượng ETH bị khóa luôn tỷ lệ 1:1.

Nếu bây giờ chuyển WETH trực tiếp sang L2, ta sẽ gặp một số vấn đề kỳ lạ:
-
Không thể Unwrap WETH thành ETH trên L2, vì trên L2 không có lượng ETH bị khóa tương ứng.
-
Chức năng Wrap vẫn dùng được, nhưng lượng WETH mới sinh ra nếu quay trở lại L1 thì không thể giải bao để lấy ETH, vì hợp đồng WETH trên L1 và L2 không «đối xứng».
Rõ ràng điều này vi phạm nguyên lý thiết kế của WETH. Do đó, khi WETH xuyên chuỗi, dù là nạp hay rút, đều phải Unwrap thành ETH trước, sau đó mới chuyển sang bên kia rồi Wrap lại thành WETH. Đây chính là vai trò của WETH Gateway.
Tương tự với các token có logic phức tạp hơn, cần Gateway được thiết kế tinh vi và phức tạp hơn để hoạt động bình thường trong môi trường xuyên chuỗi. Gateway tùy chỉnh của Arbitrum thừa hưởng logic truyền tin nhắn xuyên chuỗi từ Gateway thông thường, đồng thời cho phép nhà phát triển tự định nghĩa hành vi xuyên chuỗi liên quan đến logic token, đáp ứng được phần lớn nhu cầu.
Hộp chậm - Delayed Inbox
Đối lập với hộp nhanh (tức SequencerInbox) là hộp chậm Inbox (tên đầy đủ là Delayed Inbox). Vì sao lại phân biệt nhanh/chậm? Bởi vì hộp nhanh chuyên tiếp nhận batch giao dịch L2 do bộ sắp xếp phát hành, mọi giao dịch chưa được bộ sắp xếp xử lý sơ bộ trong mạng L2 đều không nên xuất hiện trong hợp đồng hộp nhanh.
Tác dụng đầu tiên của hộp chậm là xử lý hành vi nạp tiền từ L1 sang L2. Người dùng nạp tiền qua hộp chậm, bộ sắp xếp theo dõi và phản ánh lên L2, cuối cùng bản ghi nạp tiền này sẽ được bộ sắp xếp đưa vào chuỗi giao dịch L2 và gửi tới hợp đồng hộp nhanh Sequencer Inbox.
Trong ví dụ này, việc người dùng gửi trực tiếp giao dịch nạp tiền vào hộp nhanh là không phù hợp, vì giao dịch gửi vào Sequencer Inbox sẽ làm nhiễu thứ tự giao dịch bình thường trên Layer 2, ảnh hưởng đến hoạt động của bộ sắp xếp.
Tác dụng thứ hai của hộp chậm là chống kiểm duyệt. Giao dịch người dùng gửi trực tiếp vào hợp đồng hộp chậm thường sẽ được bộ sắp xếp tổng hợp vào hộp nhanh trong vòng 10 phút. Nhưng nếu bộ sắp xếp cố ý bỏ qua yêu cầu của bạn, hộp chậm còn có chức năng thu thập bắt buộc (force inclusion):
Nếu một giao dịch đã được gửi vào Delayed Inbox nhưng sau 24 giờ vẫn chưa được bộ sắp xếp đưa vào chuỗi giao dịch, người dùng có thể kích hoạt hàm force inclusion thủ công trên Layer 1 để ép đưa yêu cầu giao dịch bị bỏ qua vào hộp nhanh Sequencer Inbox, sau đó sẽ được tất cả các nút Arbitrum One theo dõi, và bị buộc phải đưa vào chuỗi giao dịch Layer 2.

Như đã nói, dữ liệu trong hộp nhanh chính là dữ liệu lịch sử thực tế của L2. Trong trường hợp bị kiểm duyệt ác ý, việc sử dụng hộp chậm giúp lệnh giao dịch cuối cùng vẫn được đưa vào sổ cái L2, bao gồm cả các kịch bản rút tiền bắt buộc để thoát khỏi Layer 2.
Từ đó có thể thấy, đối với mọi giao dịch ở mọi hướng và cấp độ, bộ sắp xếp cuối cùng không thể kiểm duyệt bạn mãi mãi.
Một số hàm cốt lõi của hộp chậm Inbox:
-
depositETH(), hàm nạp ETH đơn giản nhất.
-
createRetryableTicket(), dùng được cho nạp ETH, ERC20 và tin nhắn. So với depositETH() thì linh hoạt hơn, ví dụ có thể chỉ định địa chỉ nhận trên L2 sau khi nạp.
-
forceInclusion(), tức chức năng thu thập bắt buộc, bất kỳ ai cũng có thể gọi. Hàm này sẽ kiểm tra xem một giao dịch gửi vào hợp đồng hộp chậm đã quá 24 giờ chưa được xử lý hay chưa. Nếu điều kiện thỏa mãn, sẽ tiến hành thu thập bắt buộc tin nhắn.
Tuy nhiên cần lưu ý rằng hàm forceInclusion thực tế nằm trong hợp đồng hộp nhanh, chỉ vì tiện cho việc hiểu nên chúng tôi đặt nó vào đây để giải thích cùng hộp chậm.
Hộp xuất - Outbox
Hộp xuất Outbox chỉ liên quan đến việc rút tiền, có thể hiểu là hệ thống ghi nhận và quản lý hành vi rút tiền:
-
Chúng ta biết rằng rút tiền qua cầu nối chính thức Arbitrum cần chờ khoảng 7 ngày thách thức, sau khi Rollup Block được xác nhận cuối cùng thì mới thực hiện được. Người dùng sau khi hết thời gian thách thức, gửi Merkle Proof tương ứng tới hợp đồng Outbox trên Layer 1, sau đó hợp đồng này giao tiếp với các hợp đồng chức năng khác (ví dụ mở khóa tài sản bị khóa trong hợp đồng khác) để hoàn tất việc rút tiền.
-
Hợp đồng OutBox ghi lại những tin nhắn xuyên chuỗi nào từ L2 sang L1 đã được xử lý để ngăn chặn việc ai đó gửi lại yêu cầu rút tiền đã thực hiện. Nó sử dụng
-
mapping(uint256 => bytes32) public spent, ghi lại mối quan hệ giữa chỉ số spent Index và thông tin yêu cầu rút tiền. Nếu mapping[spentIndex] != bytes32(0) thì yêu cầu đã được rút. Nguyên lý tương tự bộ đếm giao dịch Nonce để chống tấn công phát lại.
Dưới đây chúng ta sẽ lấy ETH làm ví dụ để giải thích trọn vẹn quy trình nạp và rút tiền. Đối với ERC20, khác biệt duy nhất là đi qua Gateway, nên không cần nhắc lại.
Nạp ETH
1. Người dùng gọi hàm depositETH() của hộp chậm.
2. Hàm này tiếp tục gọi bridge.enqueueDelayedMessage() để ghi nhận tin nhắn trong hợp đồng bridge, đồng thời gửi ETH đến hợp đồng bridge. Mọi khoản tiền nạp ETH đều được giữ trong hợp đồng bridge, tương đương một địa chỉ nạp tiền.
3. Bộ sắp xếp theo dõi tin nhắn nạp tiền trong hộp chậm, phản ánh thao tác nạp tiền vào cơ sở dữ liệu L2, người dùng có thể thấy tài sản đã nạp trên mạng L2.
4. Bộ sắp xếp đưa bản ghi nạp tiền này vào batch giao dịch, gửi tới hợp đồng hộp nhanh trên L1.

Rút ETH
1. Người dùng trên L2 gọi hàm withdrawEth() của hợp đồng ArbSys, hủy số ETH tương ứng trên L2.
2. Bộ sắp xếp gửi yêu cầu rút tiền này tới hộp nhanh.
3. Các nút Validator dựa trên chuỗi giao dịch trong hộp nhanh để tạo Rollup Block mới, trong đó chứa giao dịch rút tiền nói trên.
4. Sau khi Rollup Block qua thời gian thách thức và được xác nhận, người dùng có thể gọi hàm Outbox.executeTransaction() trên L1, cung cấp các tham số do hợp đồng ArbSys nói trên đưa ra.
5. Hợp đồng Outbox xác nhận chính xác thì mở khóa lượng ETH tương ứng trong bridge và gửi cho người dùng.

Rút tiền nhanh
Sử dụng cầu nối chính thức của optimistic Rollup để rút tiền sẽ gặp vấn đề chờ thời gian thách thức. Ta có thể dùng cầu nối xuyên chuỗi tư nhân bên thứ ba để tránh vấn đề này:
-
Trao đổi khóa nguyên tử (Atomic Swap). Cách này chỉ đơn thuần là hai bên trao đổi tài sản trên chuỗi riêng, có tính nguyên tử: chỉ cần một bên cung cấp Preimage, cả hai bên chắc chắn nhận được tài sản mong muốn. Nhưng vấn đề là thanh khoản khan hiếm, cần tìm đối tác trực tiếp.
-
Cầu nối kiểu witness. Hầu hết các loại cầu nối hiện nay đều thuộc loại witness. Người dùng gửi yêu cầu rút tiền, đích đến là người vận hành hoặc nhóm thanh khoản của cầu nối bên thứ ba. Witness khi thấy giao dịch đã được gửi vào hợp đồng hộp nhanh trên L1 có thể trực tiếp chuyển tiền cho người dùng tại L1. Về bản chất, cách này dùng một hệ thống đồng thuận khác để giám sát Layer 2 và hành động dựa trên dữ liệu đã được gửi lên Layer 1. Vấn đề là mức độ an toàn trong mô hình này thấp hơn cầu nối chính thức của Rollup.
Rút tiền bắt buộc
Chức năng forceInclusion (thu thập bắt buộc) dùng để chống kiểm duyệt từ bộ sắp xếp, có thể áp dụng cho mọi giao dịch nội bộ L2, giao dịch từ L1 sang L2 và từ L2 sang L1. Việc kiểm duyệt ác ý từ bộ sắp xếp ảnh hưởng nghiêm trọng đến trải nghiệm giao dịch, trong đa số trường hợp người ta chọn rút tiền rời khỏi L2, do đó dưới đây lấy ví dụ rút tiền bắt buộc để giới thiệu cách dùng forceInclusion.
Nhắc lại các bước rút ETH, chỉ có bước 1 và 2 là liên quan đến kiểm duyệt từ bộ sắp xếp, do đó chỉ cần thay đổi hai bước này:

-
Gọi hàm inbox.sendL2Message() trong hợp đồng hộp chậm trên L1, tham số nhập vào là những tham số cần dùng khi gọi withdrawEth() trên L2. Tin nhắn này sẽ được chia sẻ với hợp đồng bridge trên L1.
-
Sau thời gian chờ 24 giờ để thu thập bắt buộc, gọi forceInclusion() trong hộp nhanh để thực hiện thu thập bắt buộc, hợp đồng hộp nhanh sẽ kiểm tra xem trong bridge có tin nhắn tương ứng hay không.
Cuối cùng người dùng có thể rút tiền từ Outbox, các bước còn lại giống như rút tiền bình thường.
Ngoài ra, arbitrum-tutorials cũng có hướng dẫn chi tiết sử dụng Arb SDK để hướng dẫn người dùng cách dùng forceInclusion() thực hiện giao dịch nội bộ L2 và giao dịch từ L2 sang L1.
Chào mừng tham gia cộng đồng chính thức TechFlow
Nhóm Telegram:https://t.me/TechFlowDaily
Tài khoản Twitter chính thức:https://x.com/TechFlowPost
Tài khoản Twitter tiếng Anh:https://x.com/BlockFlow_News














