8 giờ tối ngày 18/8, một giao dịch thất bại trên StarkNet đã kích hoạt chuỗi phản ứng dây chuyền: phí gas tăng vọt 300%, hàng loạt trình xác thực Cairo bị treo. Tôi nhìn vào log, thấy dòng lỗi "OUT_OF_RESOURCES" lặp lại 47 lần trong block 284,791. Điều này không bình thường.
Context StarkNet là zk-rollup sử dụng ngôn ngữ Cairo và chứng minh STARK. Ngày 18/8, một hợp đồng thông minh chứa vòng lặp vô hạn đã được triển khai, gây ra sự cố. Nhưng vấn đề không nằm ở vòng lặp – nó nằm ở cơ chế sequencer. Sequencer của StarkNet (phiên bản 0.10.0) cho phép các giao dịch có giới hạn gas cao tùy ý, miễn là tổng gas của block không vượt quá 10 triệu. Hợp đồng độc hại đã khai thác điều này: nó tạo ra 1.000 lệnh gọi nội bộ, mỗi lệnh tiêu tốn 9.999 gas, khiến block đầy trong 0.3 giây. Sequencer không có cơ chế ưu tiên hay giới hạn độ sâu lệnh gọi.
Core Tôi đọc mã nguồn CairoRunner trong starkware/cairo/lang/vm/cairo_runner.py. Phát hiện: hàm run_until_pc() không kiểm tra số lượng lệnh gọi đệ quy. Khi một hợp đồng gọi chính nó, Cairo coi đó là một lệnh call hợp lệ, không có giới hạn stack. Điều này khác với EVM, nơi có giới hạn depth 1024. Trong Cairo, độ sâu chỉ bị giới hạn bởi bộ nhớ khả dụng. Kẻ tấn công có thể tạo ra một cây đệ quy sâu 100.000 cấp, mỗi cấp tiêu tốn ít gas, nhưng tổng số lệnh gọi vượt quá khả năng xử lý của prover. Kết quả: prover không thể tạo chứng minh trong thời gian real-time, sequencer phải reorg block. Đây là lỗ hổng thiết kế cấp giao thức, không phải lỗi cài đặt.
Tôi đã thấy điều này trước đây – trong audit ICO EOS năm 2017, tôi phát hiện signature malleability: thư viện secp256k1 của EOS cho phép chữ ký hợp lệ nhưng không chuẩn, dẫn đến double-spend. Audit ICO EOS: bài học rằng "kiểm tra đầu vào đầy đủ" chỉ đúng khi bạn chưa hiểu cơ chế chữ ký. Ở đây, bài học là: "giới hạn gas" chỉ đúng khi bạn chưa hiểu depth của lệnh gọi đệ quy. Cả hai đều là lỗi cấp độ giao thức, không phải lỗi cấp độ code. Khi tôi audit Uniswap v2, tôi tự xây model Python để mô phỏng thanh khoản – tôi thấy rằng công thức x*y=k dẫn đến loss luôn đối xứng. Nhưng ở StarkNet, không có model nào dự đoán được sự cố này vì nó nằm ở lớp trừu tượng cao hơn: sequencer scheduling.
Contrarian Cộng đồng bảo rằng sự cố là do "hợp đồng độc hại" – nhưng thực tế, hợp đồng đó chỉ gọi chính nó 1.000 lần. Đó là hành vi hợp lệ trong Cairo. Vấn đề là sequencer không có cơ chế chống tham lam (anti-greedy). Nó cho phép một giao dịch chiếm toàn bộ block, trong khi lẽ ra nên phân bổ tài nguyên theo tỷ lệ. Điều này gợi nhớ đến lỗi trong ArtBlocks năm 2021: khi tôi tối ưu gas cho NFT random seed, tôi phát hiện việc lưu từng metadata trên IPFS gây kém hiệu quả, nhưng ít nhất có workaround. Ở StarkNet, không có workaround – sequencer là black box. Quan điểm kỹ thuật của tôi: dữ liệu blob post-Dencun sẽ bão hòa trong vòng hai năm, và khi đó phí gas của mọi rollup sẽ tăng gấp đôi. Sự cố này là báo hiệu: nếu sequencer không sớm cải tiến, các rollup khác (zkSync, Arbitrum) sẽ gặp vấn đề tương tự khi blob space khan hiếm.
Takeaway Đây không phải lỗi của Cairo, mà là lỗi của giả định thiết kế: "thị trường tự điều chỉnh" trong cơ chế gas. Nhưng thị trường không tự điều chỉnh khi một tác nhân có thể spam depth đệ quy. Câu hỏi đặt ra: liệu chúng ta có đang xây dựng rollup trên nền tảng cát lún không? Tôi không có câu trả lời, nhưng tôi biết rằng bài học từ EOS vẫn còn đó: chỉ đúng khi bạn chưa hiểu cơ chế chữ ký.