Chuyển đến nội dung chính

The Graph: Khắc phục vấn đề truy vấn dữ liệu Web3

Solidity
hợp đồng thông minh
truy vấn
the graph
React
Trung cấp
Markus Waas
6 tháng 9, 2020
11 phút đọc

Lần này chúng ta sẽ xem xét kỹ hơn về The Graph, thứ về cơ bản đã trở thành một phần của bộ công cụ tiêu chuẩn để phát triển các ứng dụng phi tập trung (dapp) trong năm qua. Trước tiên, hãy xem chúng ta sẽ làm mọi thứ theo cách truyền thống như thế nào...

Nếu không có The Graph...

Vì vậy, hãy đi vào một ví dụ đơn giản để minh họa. Tất cả chúng ta đều thích trò chơi, vì vậy hãy tưởng tượng một trò chơi đơn giản với người dùng đặt cược:

Bây giờ giả sử trong dapp của chúng ta, chúng ta muốn hiển thị tổng số tiền cược, tổng số trò chơi thua/thắng và cũng cập nhật nó bất cứ khi nào có người chơi lại. Cách tiếp cận sẽ là:

  1. Tìm nạp totalGamesPlayerWon.
  2. Tìm nạp totalGamesPlayerLost.
  3. Đăng ký nhận các sự kiện BetPlaced.

Chúng ta có thể lắng nghe sự kiện trong Web3 (opens in a new tab) như được hiển thị ở bên phải, nhưng nó đòi hỏi phải xử lý khá nhiều trường hợp.

Bây giờ điều này vẫn phần nào ổn đối với ví dụ đơn giản của chúng ta. Nhưng giả sử bây giờ chúng ta muốn hiển thị số tiền cược thua/thắng chỉ cho người chơi hiện tại. Chà, chúng ta không may rồi, tốt hơn là bạn nên triển khai một hợp đồng mới lưu trữ các giá trị đó và tìm nạp chúng. Và bây giờ hãy tưởng tượng một hợp đồng thông minh và dapp phức tạp hơn nhiều, mọi thứ có thể trở nên lộn xộn một cách nhanh chóng.

One Does Not Simply Query

Bạn có thể thấy điều này không tối ưu như thế nào:

  • Không hoạt động đối với các hợp đồng đã được triển khai.
  • Tốn thêm chi phí Gas để lưu trữ các giá trị đó.
  • Yêu cầu một lệnh gọi khác để tìm nạp dữ liệu cho một nút Ethereum.

Thats not good enough

Bây giờ hãy xem xét một giải pháp tốt hơn.

Hãy để tôi giới thiệu với bạn về GraphQL

Đầu tiên hãy nói về GraphQL, ban đầu được thiết kế và triển khai bởi Facebook. Bạn có thể đã quen thuộc với mô hình REST API truyền thống. Bây giờ hãy tưởng tượng thay vào đó bạn có thể viết một truy vấn cho chính xác dữ liệu mà bạn muốn:

GraphQL API vs. REST API

Animated demonstration of a GraphQL query in The Graph playground

Hai hình ảnh này gần như nắm bắt được bản chất của GraphQL. Với truy vấn ở bên phải, chúng ta có thể xác định chính xác dữ liệu chúng ta muốn, vì vậy ở đó chúng ta nhận được mọi thứ trong một yêu cầu và không có gì nhiều hơn chính xác những gì chúng ta cần. Một máy chủ GraphQL xử lý việc tìm nạp tất cả dữ liệu được yêu cầu, vì vậy nó cực kỳ dễ sử dụng cho phía người dùng frontend. Đây là một lời giải thích hay (opens in a new tab) về cách chính xác máy chủ xử lý một truy vấn nếu bạn quan tâm.

Bây giờ với kiến thức đó, cuối cùng hãy bước vào không gian Chuỗi khối và The Graph.

The Graph là gì?

Chuỗi khối là một cơ sở dữ liệu phi tập trung, nhưng trái ngược với những gì thường xảy ra, chúng ta không có ngôn ngữ truy vấn cho cơ sở dữ liệu này. Các giải pháp để truy xuất dữ liệu rất khó khăn hoặc hoàn toàn không thể. The Graph là một Giao thức phi tập trung để lập chỉ mục và truy vấn dữ liệu Chuỗi khối. Và bạn có thể đã đoán ra, nó đang sử dụng GraphQL làm ngôn ngữ truy vấn.

The Graph

Các ví dụ luôn là cách tốt nhất để hiểu một điều gì đó, vì vậy hãy sử dụng The Graph cho ví dụ GameContract của chúng ta.

Cách tạo một đồ thị con

Định nghĩa về cách lập chỉ mục dữ liệu được gọi là đồ thị con. Nó yêu cầu ba thành phần:

  1. Manifest (subgraph.yaml)
  2. Schema (schema.graphql)
  3. Mapping (mapping.ts)

Manifest (subgraph.yaml)

Manifest là tệp cấu hình của chúng ta và xác định:

  • các hợp đồng thông minh nào cần lập chỉ mục (Địa chỉ, mạng lưới, ABI...)
  • các sự kiện nào cần lắng nghe
  • những thứ khác cần lắng nghe như các lệnh gọi hàm hoặc các khối
  • các hàm mapping được gọi (xem mapping.ts bên dưới)

Bạn có thể xác định nhiều hợp đồng và trình xử lý ở đây. Một thiết lập điển hình sẽ có một thư mục đồ thị con bên trong dự án Hardhat với kho lưu trữ riêng của nó. Sau đó, bạn có thể dễ dàng tham chiếu ABI.

Vì lý do thuận tiện, bạn cũng có thể muốn sử dụng một công cụ mẫu như mustache. Sau đó, bạn tạo một subgraph.template.yaml và chèn các Địa chỉ dựa trên các lần triển khai mới nhất. Để có một ví dụ thiết lập nâng cao hơn, hãy xem ví dụ kho lưu trữ đồ thị con Aave (opens in a new tab).

Và tài liệu đầy đủ có thể được xem tại đây (opens in a new tab).

Schema (schema.graphql)

Schema là định nghĩa dữ liệu GraphQL. Nó sẽ cho phép bạn xác định các thực thể nào tồn tại và các kiểu của chúng. Các kiểu được hỗ trợ từ The Graph là

  • Bytes
  • ID
  • String
  • Boolean
  • Int
  • BigInt
  • BigDecimal

Bạn cũng có thể sử dụng các thực thể làm kiểu để xác định các mối quan hệ. Trong ví dụ của chúng ta, chúng ta xác định mối quan hệ 1-nhiều từ người chơi đến các cược. Dấu ! có nghĩa là giá trị không thể trống. Tài liệu đầy đủ có thể được xem tại đây (opens in a new tab).

Mapping (mapping.ts)

Tệp mapping trong The Graph xác định các hàm của chúng ta để chuyển đổi các sự kiện đến thành các thực thể. Nó được viết bằng AssemblyScript, một tập hợp con của TypeScript. Điều này có nghĩa là nó có thể được biên dịch thành WASM (WebAssembly) để thực thi mapping hiệu quả và linh hoạt hơn.

Bạn sẽ cần xác định từng hàm được đặt tên trong tệp subgraph.yaml, vì vậy trong trường hợp của chúng ta, chúng ta chỉ cần một: handleNewBet. Đầu tiên, chúng ta cố gắng tải thực thể Player từ Địa chỉ người gửi dưới dạng id. Nếu nó không tồn tại, chúng ta tạo một thực thể mới và điền vào đó các giá trị ban đầu.

Sau đó, chúng ta tạo một thực thể Bet mới. Id cho thực thể này sẽ là event.transaction.hash.toHex() + "-" + event.logIndex.toString() đảm bảo luôn là một giá trị duy nhất. Chỉ sử dụng Mã băm là không đủ vì ai đó có thể gọi hàm placeBet nhiều lần trong một giao dịch thông qua một hợp đồng thông minh.

Cuối cùng, chúng ta có thể cập nhật thực thể Player với tất cả dữ liệu. Các mảng không thể được đẩy trực tiếp vào mà cần được cập nhật như hiển thị ở đây. Chúng ta sử dụng id để tham chiếu đến cược. Và .save() được yêu cầu ở cuối để lưu trữ một thực thể.

Tài liệu đầy đủ có thể được xem tại đây: https://thegraph.com/docs/en/developing/creating-a-subgraph/#writing-mappings (opens in a new tab). Bạn cũng có thể thêm đầu ra ghi nhật ký vào tệp mapping, xem tại đây (opens in a new tab).

Sử dụng nó trong Frontend

Sử dụng một công cụ như Apollo Boost, bạn có thể dễ dàng tích hợp The Graph vào dapp React của mình (hoặc Apollo-Vue). Đặc biệt khi sử dụng React hooks và Apollo, việc tìm nạp dữ liệu đơn giản như viết một truy vấn GraphQL duy nhất trong thành phần của bạn. Một thiết lập điển hình có thể trông như thế này:

Và bây giờ chúng ta có thể viết ví dụ một truy vấn như thế này. Điều này sẽ tìm nạp cho chúng ta

  • số lần người dùng hiện tại đã thắng
  • số lần người dùng hiện tại đã thua
  • một danh sách các dấu thời gian với tất cả các cược trước đó của họ

Tất cả trong một yêu cầu duy nhất đến máy chủ GraphQL.

Magic

Nhưng chúng ta đang thiếu một mảnh ghép cuối cùng và đó là máy chủ. Bạn có thể tự chạy nó hoặc sử dụng dịch vụ được lưu trữ.

Máy chủ The Graph

Graph Explorer: Dịch vụ được lưu trữ

Cách dễ nhất là sử dụng dịch vụ được lưu trữ. Làm theo các hướng dẫn tại đây (opens in a new tab) để triển khai một đồ thị con. Đối với nhiều dự án, bạn thực sự có thể tìm thấy các đồ thị con hiện có trong trình khám phá (opens in a new tab).

The Graph-Explorer

Chạy nút của riêng bạn

Ngoài ra, bạn có thể chạy nút của riêng mình. Tài liệu tại đây (opens in a new tab). Một lý do để làm điều này có thể là sử dụng một mạng lưới không được hỗ trợ bởi dịch vụ được lưu trữ. Các mạng lưới hiện được hỗ trợ có thể được tìm thấy tại đây (opens in a new tab).

Tương lai phi tập trung

GraphQL cũng hỗ trợ các luồng cho các sự kiện mới đến. Chúng được hỗ trợ trên the graph thông qua Substreams (opens in a new tab) hiện đang trong giai đoạn thử nghiệm mở (open beta).

Vào năm 2021 (opens in a new tab), The Graph đã bắt đầu quá trình chuyển đổi sang một mạng lưới lập chỉ mục phi tập trung. Bạn có thể đọc thêm về kiến trúc của mạng lưới lập chỉ mục phi tập trung này tại đây (opens in a new tab).

Hai khía cạnh chính là:

  1. Người dùng trả tiền cho các trình lập chỉ mục (indexer) cho các truy vấn.
  2. Các trình lập chỉ mục đặt cọc Graph Tokens (GRT).