Là một backend trong mảng blockchain build một crawler có lẽ là một trong những công việc thú vị nhất. Trong bài viết này, chúng ta sẽ tìm hiểu cách xây dựng một EVM crawler để đồng bộ hóa dữ liệu từ blockchain (onchain) với một database. Đây là công cụ quan trọng trong các ứng dụng phi tập trung (dApps), đặc biệt khi cần xử lý dữ liệu giao dịch hoặc sự kiện từ smart contract.
1. Nguyên Lý Chung Của Một Crawler
Một EVM crawler hoạt động như một "người liên tục lắng nghe" trên blockchain, thu thập dữ liệu từ các block và event của smart contract, sau đó lưu trữ hoặc xử lý dữ liệu đó trong một hệ thống cục bộ (thường là database). Nguyên lý chung bao gồm các bước sau:
Kết nối với blockchain: Sử dụng một node provider (như Infura, Alchemy) để truy cập dữ liệu blockchain qua JSON-RPC.
Xác định điểm bắt đầu: Quyết định block bắt đầu (thường là block triển khai hợp đồng) và block kết thúc (thường là block mới nhất).
Thu thập dữ liệu theo batch: Để tránh quá tải, dữ liệu được thu thập theo từng nhóm block (batch size).
Xử lý event: Crawl các event log từ smart contract (ví dụ: Deposit, Withdrawal) và trích xuất thông tin cần thiết.
Đồng bộ với database: Lưu dữ liệu vào database như MongoDB, PostgreSQL, đồng thời cập nhật trạng thái xử lý (ví dụ: block cuối cùng đã crawl).
Kiểm tra reorg: Blockchain có thể xảy ra fork hoặc reorg, crawler cần phát hiện và xử lý để đảm bảo dữ liệu chính xác.
Xác nhận giao dịch: Đảm bảo giao dịch đạt đủ số confirmations trước khi đánh dấu là hoàn tất.
Lặp lại liên tục: Crawler chạy liên tục hoặc định kỳ để cập nhật dữ liệu mới nhất, nhưng tránh chạy nhiều tiến trình song song.
2. Các Sai Lầm Hay Mắc Phải Khi Xây Dựng Crawler
Khi phát triển một EVM crawler, có một số sai lầm phổ biến mà chúng ta nên tránh:
Không xử lý reorg:
Blockchain có thể thay đổi lịch sử block gần đây khi xảy ra fork. Nếu không kiểm tra reorg, dữ liệu trong database có thể không đồng bộ với blockchain thực tế.
Chain reorg là gì?: Reorg (reorganization) xảy ra khi một chuỗi block tạm thời (thường do fork) bị thay thế bởi một chuỗi block khác dài hơn hoặc được mạng chấp nhận là chuỗi chính. Ví dụ, một miner có thể tạo ra block A ở độ cao 100, nhưng một miner khác tạo block B ở cùng độ cao và chuỗi của B được mở rộng nhanh hơn. Khi đó, block A và các giao dịch trong đó bị hủy bỏ, thay bằng block B. Nếu crawler đã lưu dữ liệu từ block A mà không phát hiện reorg, dữ liệu trong database sẽ không phản ánh đúng trạng thái onchain.
Cách khắc phục: Lưu trữ hash của các block gần đây và so sánh với blockchain để phát hiện thay đổi. Nếu hash của block đã thay đổi, cần rollback dữ liệu từ block đó và crawl lại.
Thu thập quá nhiều dữ liệu cùng lúc:
Lấy toàn bộ dữ liệu từ block 0 đến block mới nhất trong một lần có thể gây quá tải node hoặc vượt giới hạn API.
Cách khắc phục: Sử dụng batch size hợp lý (ví dụ: 1000 block/lần) và crawl dần dần, Chỉ crawl từ block contract deploy.
Không kiểm tra confirmations:
Một giao dịch có thể bị revert nếu không đạt đủ confirmations. Nếu cập nhật database ngay lập tức, dữ liệu có thể sai lệch. đặc biệt cập nhật liên quan tới balance
Cách khắc phục: Đợi đủ số confirmations (thường từ 6 đến 12) trước khi xác nhận giao dịch, cập nhật balance.
Không xử lý lỗi và khởi động lại:
Lỗi mạng, rate limit của node, hoặc lỗi database có thể làm crawler dừng đột ngột.
Cách khắc phục: Thêm cơ chế retry với delay (ví dụ: 5 giây) khi gặp lỗi, nhưng tránh dùng đệ quy hoặc interval để không tạo nhiều tiến trình.
Không tối ưu hiệu suất database:
Thực hiện quá nhiều truy vấn đơn lẻ thay vì bulk operation sẽ làm chậm quá trình đồng bộ.
Cách khắc phục: Sử dụng bulk write/update để xử lý nhiều giao dịch cùng lúc.
Thiếu cấu hình linh hoạt:
Hardcode các thông số như batch size, RPC URL hoặc confirmations khiến crawler khó mở rộng sang chain khác.
Cách khắc phục: Tạo file cấu hình riêng biệt cho từng chain.
Sử dụng đệ quy hoặc setInterval để gọi lại:
Sử dụng đệ quy có thể gây quá tải cho hệ thống và làm giảm hiệu suất.
Sử dụng setInterval để thực hiện các cuộc gọi lại có thể dẫn đến việc tạo ra nhiều tiến trình song song, gây quá tải cho hệ thống và làm giảm hiệu suất.
Cách khắc phục: Gọi lại bằng:
setTimeOut(()=>this.crawl(),this.RESTART_DELAY);
3. Giải Thích Cralwer
Tôi sẽ bóc tách từng phần chính của class Crawler mà tôi đã xây dựng và giải thích cách nó hoạt động.
Lưu ý: Sử dụng đệ quy thông qua setTimeout để crawl liên tục, cần cẩn thận để tránh chồng lấn tiến trình nếu không kiểm soát tốt.
Khởi động Crawler
publicasyncstart():Promise<void>{try{await mongoose.connect(String(process.env.DATABASE_URI));console.log(`✅ Connected to MongoDB for ${this.chain.name}`);awaitthis.crawl();}catch(error){console.error(`❌ Failed to start crawler for ${this.chain.name}:`, error
);}}
import{ Crawler }from"./crawler.js";const crawler =newCrawler(1);// Chain ID 1 cho Ethereum Mainnetcrawler.start();
Kết
Bài viết này đã giải thích chi tiết cách hoạt động của crawler, đồng thời cung cấp nguyên lý chung và các sai lầm cần tránh. Bạn có thể mở rộng crawler này bằng cách thêm hỗ trợ multi-chain, tối ưu batch size.
Để xem toàn bộ source code và các cập nhật mới nhất, hãy ghé thăm repository GitHub tại đây: https://github.com/chinhvuong/evm-crawler. Nếu bạn có ý tưởng cải tiến hoặc cần hỗ trợ thêm, đừng ngần ngại đóng góp hoặc liên hệ!