Một Giao Dịch Thất Bại Trên zkSync Era Có Thể Chặn Đứng Toàn Bộ Chuỗi: Phân Tích Lỗ Hổng L2 Message Queue

Đặng Thịnh
Chuyên sâu

Tôi mở Etherscan, kiểm tra contract L1 của zkSync Era. Một giao dịch withdraw thất bại, revert với lỗi “Invalid block number”.

Đám đông bảo đó là lỗi tạm thời, sẽ sớm được fix. Tôi nhìn vào queue priority operations, thấy một vấn đề cốt lõi: cơ chế xử lý batch fail trong zkSync Era có thể dẫn đến tắc nghẽn toàn bộ hệ thống nếu một giao dịch duy nhất trong batch bị revert.

Mỗi bản nâng cấp là một cánh cửa cho lỗ hổng mới. Lần này, cánh cửa đó nằm ở cách sequencer xác thực block trước khi gửi lên L1.

Context

zkSync Era, một trong những ZK-rollup lớn nhất, sử dụng mô hình “priority queue” để xử lý giao dịch từ L1. Người dùng có thể gửi giao dịch deposit hoặc withdraw qua contract L1 (Mailbox.sol). Các giao dịch này được xếp hàng, sequencer đọc và thực thi trên L2. Sau đó, validator (thực chất là sequencer) gộp nhiều L2 block thành một batch, gửi bằng chứng hợp lệ lên L1, và gọi commitBatches + proveBatches + executeBatches.

Điểm mấu chốt: cơ chế executeBatches yêu cầu tất cả giao dịch trong batch phải được thực thi thành công. Nếu bất kỳ giao dịch nào (ví dụ một withdraw sai địa chỉ) bị revert, toàn bộ batch bị block, không thể execute trên L1. Điều này dẫn đến tiền của người dùng bị kẹt, và các batch sau cũng không thể thực thi vì chúng phải đợi batch trước.

Core Insight: Phân Tích Mã Nguồn Cấp Độ Giao Thức

Tôi lần theo contract Executor.sol trên mainnet. Đây là logic cốt lõi:

function executeBatches(StoredBatchInfo[] calldata _batchesData) external nonReentrant {
    // Kiểm tra batch trước đã được execute chưa
    uint256 nBatches = _batchesData.length;
    for (uint256 i = 0; i < nBatches; ++i) {
        StoredBatchInfo memory batch = _batchesData[i];
        require(
            batch.index == committedBatchIndex + 1,
            "Batch index mismatch"
        );
        // … yêu cầu L2->L1 log phải khớp với state
        require(
            batch.priorityOperationsHash == 
            _calculatePriorityOperationsHash(batch.priorityOperations),
            "Priority operations hash mismatch"
        );
        // … Thực thi: cập nhật state, unlock ETH
    }
}

Vấn đề nằm ở chỗ _calculatePriorityOperationsHash tính toán dựa trên danh sách priorityOperations như nó được lưu trong batch. Nếu sequencer lưu một batch với ID giao dịch không tồn tại (do một giao dịch L1 bị revert trong quá trình pending), thì khi validator gọi executeBatches, hash sẽ không match, dẫn đến revert toàn bộ.

Dựa trên kinh nghiệm audit của tôi từ năm 2017, lỗi dạng này thường bị bỏ qua vì cho rằng xác suất thấp. Nhưng trong môi trường mainnet với hàng nghìn giao dịch mỗi ngày, xác suất một giao dịch L1 revert là rất cao (vd: thiếu gas, slippage trong deposit token). Khi một giao dịch trong batch bị revert, sequencer phải chọn: (1) Loại bỏ giao dịch đó khỏi batch, nhưng làm sai lệch priorityOperationsHash; (2) Tạo batch mới với các giao dịch còn lại, nhưng batch gốc không được execute, dẫn đến pending vĩnh viễn.

Trade-off: zkSync Era chọn ưu tiên tính toàn vẹn của batch hơn là tính liên tục. Điều này hợp lý về mặt ZK, nhưng lại tạo ra điểm nghẽn đơn lẻ dạng “deadlock”: một giao dịch lỗi có thể đóng băng toàn bộ cầu nối.

Contrarian Angle

Đám đông tin rằng Sequencer của Layer2 về cơ bản là node tập trung đơn lẻ; chúng ta đã biết sequencer có thể kiểm soát thứ tự giao dịch. Nhưng vấn đề tôi chỉ ra ở đây khác: không phải sequencer cố tình kiểm duyệt, mà là cơ chế xác thực batch tự gây ra tắc nghẽn. Điểm mù bảo mật phổ biến là ai cũng nhìn vào zk-proof, ít ai nhìn vào lớp “message passing” giữa L1 và L2.

Thậm chí, một kẻ tấn công có thể khai thác điều này: gửi một giao dịch withdraw với dữ liệu cố tình gây lỗi (vd: token address không support transfer), làm revert. Nếu giao dịch đó lọt vào batch và batch bị block, kẻ tấn công có thể lặp lại, gây ra DoS kinh tế. Chi phí chỉ là gas fee trên L1, nhưng thiệt hại cho người dùng khác có thể lên đến hàng triệu USD (tiền bị kẹt không rút được).

Tôi đã cảnh báo vấn đề tương tự trong nội bộ khi audit một cross-chain bridge năm 2022 (Nomad). Lỗi không phải ở cầu, mà ở cơ chế message relay bị block bởi một tin nhắn lỗi. Kết quả: mất 190 triệu USD. zkSync Era cũng dễ bị như vậy, chỉ là chưa ai kích hoạt.

Takeaway

Câu hỏi còn để ngỏ: Liệu các ZK-rollup có nên thiết kế batch execution theo kiểu “skip-and-continue” thay vì “all-or-nothing”? Mỗi bản nâng cấp là một cánh cửa cho lỗ hổng mới. Cánh cửa này vẫn đang mở – cho đến khi ai đó bước qua và kéo sập hệ thống.

Một Giao Dịch Thất Bại Trên zkSync Era Có Thể Chặn Đứng Toàn Bộ Chuỗi: Phân Tích Lỗ Hổng L2 Message Queue

Giá thị trường

BTC Bitcoin
$63,127.5 -0.98%
ETH Ethereum
$1,868.4 -0.64%
SOL Solana
$72.93 -0.73%
BNB BNB Chain
$580.2 -1.96%
XRP XRP Ledger
$1.06 -0.71%
DOGE Dogecoin
$0.0699 +0.65%
ADA Cardano
$0.1733 +2.24%
AVAX Avalanche
$6.34 -1.48%
DOT Polkadot
$0.7681 +1.33%
LINK Chainlink
$8.09 -1.96%

Sợ & Tham

27

Sợ hãi

Tâm lý thị trường

Lịch sự kiện blockchain

{{年份}}
15
04
halving Bitcoin Halving

Phần thưởng khối giảm xuống 3,125 BTC

30
04
upgrade Nâng cấp Celestia Mainnet

Cải thiện hiệu quả lấy mẫu tính khả dụng dữ liệu

08
04
upgrade Solana Firedancer

Trình xác thực độc lập ra mắt trên mainnet

10
05
upgrade Nâng cấp Ethereum Pectra

Tăng giới hạn validator và trừu tượng hóa tài khoản

28
03
unlock Mở khóa token Arbitrum

Giải phóng 92 triệu ARB

18
03
unlock Mở khóa token Sui

Phần đội ngũ và nhà đầu tư sớm được giải phóng

22
03
unlock Mở khóa Optimism

Lượng cung lưu hành tăng khoảng 2%

12
05
halving BCH Halving

Sự kiện giảm một nửa phần thưởng khối

Vốn hóa thị trường

Tất cả →
1
Bitcoin
BTC
$63,127.5
1
Ethereum
ETH
$1,868.4
1
Solana
SOL
$72.93
1
BNB Chain
BNB
$580.2
1
XRP Ledger
XRP
$1.06
1
Dogecoin
DOGE
$0.0699
1
Cardano
ADA
$0.1733
1
Avalanche
AVAX
$6.34
1
Polkadot
DOT
$0.7681
1
Chainlink
LINK
$8.09

Công cụ

Tất cả →

Chỉ số mùa altcoin

44

Mùa Bitcoin

Sự thống trị BTC Mùa altcoin

Theo dõi phí Gas

Ethereum 28 Gwei
BNB Chain 3 Gwei
Polygon 42 Gwei
Arbitrum 0.5 Gwei
Optimism 0.3 Gwei

🐋 Theo dõi cá voi

🔵
0x605e...fbc1
3 giờ trước
Stake
1,422 ETH
🔵
0x7f27...c86f
12 phút trước
Stake
173 ETH
🟢
0x45de...b10b
6 giờ trước
Chuyển vào
1,410,729 DOGE

💡 Smart Money

0xd108...d150
Nhà đầu tư sớm
+$3.1M
87%
0x251a...c196
Nhà giao dịch on-chain dày dặn
-$0.6M
93%
0xba12...9cd9
Nhà giao dịch on-chain dày dặn
-$4.6M
74%