Ajută la actualizarea acestei pagini

🌏

Există o nouă versiune a acestei pagini, dar acum este doar în engleză. Ajută-ne să traducem cea mai recentă versiune.

The Graph: Remedierea interogării datelor Web3

De data aceasta vom arunca o privire mai atentă la „The Graph” care, în esență, a devenit parte din stiva standard pentru dezvoltarea aplicațiilor dapp în ultimul an. Să vedem mai întâi cum am face lucrurile în mod tradițional...

Fără „The Graph”...

Vom folosi un exemplu simplu în scopul de ilustrare. Tuturor ne plac jocurile, deci să ne imaginăm un joc simplu, cu utilizatori care plasează pariuri:

1pragma solidity 0.7.1;
2
3contract Game {
4 uint256 totalGamesPlayerWon = 0;
5 uint256 totalGamesPlayerLost = 0;
6 event BetPlaced(address player, uint256 value, bool hasWon);
7
8 function placeBet() external payable {
9 bool hasWon = evaluateBetForPlayer(msg.sender);
10
11 if (hasWon) {
12 (bool success, ) = msg.sender.call{ value: msg.value * 2 }('');
13 require(success, "Transferul nu a reușit");
14 totalGamesPlayerWon++;
15 } else {
16 totalGamesPlayerLost++;
17 }
18
19 emit BetPlaced(msg.sender, msg.value, hasWon);
20 }
21}
22
Afișează tot
📋 Copiere

Acum să spunem că în aplicația noastră dapp, vrem să afișăm totalul jocurilor pierdute/câștigate și, de asemenea, să le actualizăm ori de câte ori cineva joacă din nou. Abordarea ar fi:

  1. Preia totalGamesPlayerWon.
  2. Preia totalGamesPlayerLost.
  3. Abonează-te la evenimente BetPlaced.

Putem asculta evenimentul în Web3 așa cum se arată în dreapta, dar necesită manipularea destul de multor cazuri.

1GameContract.events.BetPlaced({
2 fromBlock: 0
3}, function(error, event) { console.log(event); })
4.on('data', function(event) {
5 // eveniment declanșat
6})
7.on('changed', function(event) {
8 // evenimentul a fost eliminat din nou
9})
10.on('error', function(error, receipt) {
11 // tx respins
12});
13
Afișează tot
📋 Copiere

Acum, acest lucru este încă destul de bun pentru exemplul nostru simplu. Dar să presupunem că vrem să afișăm numai câte pariuri a pierdut/câștigat doar jucătorul actual. Ei bine, nu avem noroc, ar fi bine să implementezi un nou contract care stochează valorile respective și să le afișeze. Și acum să ne imaginăm un contract inteligent și o aplicație dapp mult mai complicate, lucrurile pot deveni repede foarte confuze.

Nu faci interogări pur și simplu

Putem vedea de ce acest lucru nu este optim:

  • Nu funcționează pentru contracte deja implementate.
  • Costuri suplimentare de gaz pentru stocarea acestor valori.
  • Necesită un alt apel pentru a prelua datele pentru un nod Ethereum.

Asta nu e suficient de bine

Acum să analizăm o soluție mai bună.

Permite-mi să-ți prezint GraphQL

În primul rând, să vorbim despre GraphQL, inițial proiectat și implementat de Facebook. Este posibil să fii familiarizat cu modelul tradițional API Rest. Acum imaginează-ți că ai putea scrie o interogare pentru exact datele pe care le-ai dorit:

GraphQL API față de REST API

Cele două imagini surprind destul de mult esența GraphQL. Cu interogarea din dreapta putem defini exact ce date vrem, astfel încât vom obține totul într-o singură cerere și nimic mai mult decât exact ceea ce avem nevoie. Un server GraphQL se ocupă de preluarea tuturor datelor necesare, astfel încât este incredibil de ușor de partea front-end a consumatorului. Aceasta este o explicație frumoasă a modului în care serverul gestionează o interogare dacă ești interesat.

Acum, cu aceste cunoștințe, să sărim în cele din urmă în spațiul blockchain și „The Graph”.

Ce este „The Graph”?

Un blockchain este o bază de date descentralizată, dar spre deosebire de ceea ce se întâmplă de obicei, nu avem un limbaj de interogare pentru această bază de date. Soluțiile pentru obținerea datelor sunt dureroase sau complet imposibile. „The Graph” este un protocol descentralizat pentru indexarea și interogarea datelor blockchain. Și s-ar putea să fi ghicit, se utilizează GraphQL ca limbaj de interogare.

The Graph

Exemplele sunt cele mai bune ca să înțelegem ceva, așa că hai să folosim „The Graph” pentru exemplul nostru „GameContract”

Cum să creăm un Subgraph

Definiția modului de indexare a datelor se numește „subgraph”. Acesta necesită trei componente:

  1. Manifestul (subgraph.yaml)
  2. Schema (schema.graphql)
  3. Maparea (mapping.ts)

Manifest (subgraph.yaml)

Manifestul este fișierul nostru de configurare și definește:

  • ce contracte inteligente să indexeze (adresa, rețea, ABI...)
  • ce evenimente să asculte
  • alte lucruri de ascultat, cum ar fi apeluri de funcții sau blocuri
  • funcțiile de mapare apelate (vezi mapping.ts mai jos)

Aici poți defini mai multe contracte și manipulatoare. O configurare tipică ar avea un folder subgraph în proiectul Truffle/Hardhat cu propriul depozit. Apoi, poți face cu ușurință referire la ABI.

Din motive de confort, probabil ai vrea să utilizezi un instrument șablon, cum ar fi „mustache”. Apoi să creezi un subgraph.template.yaml și să introduci adresele pe baza celor mai recente implementări. Pentru un exemplu de configurare mai avansat, consultă depozitul Aave subgraph.

Și documentația completă poate fi văzută aici: https://thegraph.com/docs/define-a-subgraph#the-subgraph-manifest.

1specVersion: 0.0.1
2description: Plasarea pariurilor pe Ethereum
3repository: - Github link -
4schema:
5 file: ./schema.graphql
6dataSources:
7 - kind: ethereum/contract
8 name: GameContract
9 network: mainnet
10 source:
11 address: '0x2E6454...cf77eC'
12 abi: GameContract
13 startBlock: 6175244
14 mapping:
15 kind: ethereum/events
16 apiVersion: 0.0.1
17 language: wasm/assemblyscript
18 entities:
19 - GameContract
20 abis:
21 - name: GameContract
22 file: ../build/contracts/GameContract.json
23 eventHandlers:
24 - event: PlacedBet(address,uint256,bool)
25 handler: handleNewBet
26 file: ./src/mapping.ts
27
Afișează tot

Schema (schema.graphql)

Schema este definiția datelor GraphQL. Aceasta îți va permite să definești ce entități există și tipurile lor. Tipurile acceptate din „The Graph” sunt

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

De asemenea, poți utiliza entitățile ca „tip” pentru a defini relațiile. În exemplul nostru definim o relație 1-la-mulți de la jucător la pariuri. Simbolul ! înseamnă că valoarea nu poate fi goală. Documentația completă poate fi consultată aici: https://thegraph.com/docs/define-a-subgraph#the-graphql-schema.

1type Bet @entity {
2 id: ID!
3 player: Player!
4 playerHasWon: Boolean!
5 time: Int!
6}
7
8type Player @entity {
9 id: ID!
10 totalPlayedCount: Int
11 hasWonCount: Int
12 hasLostCount: Int
13 bets: [Bet]!
14}
15
Afișează tot

Mapping (mapping.ts)

Fișierul de mapare din „The Graph” definește funcțiile noastre care transformă evenimentele primite în entități. Este scris în AssemblyScript, un subset de Typescript. Deci poate fi compilat în WASM (WebAssembly) pentru executarea mai eficientă și portabilă a mapării.

Va trebui să definești fiecare funcție numită în fișierul subgraph.yaml, deci în cazul nostru avem nevoie doar de una: handleNewBet. Mai întâi încercăm să încărcăm entitatea Player din adresa expeditorului ca id. Dacă nu există, creăm o entitate nouă și o completăm cu valorile inițiale.

Apoi vom crea o nouă entitate Bet. Id-ul pentru aceasta va fi event.transaction.hash.toHex() + "-" + event.logIndex.toString() asigurând întotdeauna o valoare unică. Numai utilizarea hash-ului nu este suficientă deoarece cineva poate apela funcția „placeBet” de mai multe ori într-o singură tranzacție printr-un contract inteligent.

În cele din urmă, putem actualiza entitatea „Player” cu toate datele. Matricele nu pot fi împinse direct, dar trebuie actualizate așa cum se arată aici. Folosim id-ul pentru a face referire la pariu. Și ".save()" este necesară la sfârșit pentru a stoca o entitate.

Documentația completă poate fi consultată aici: https://thegraph.com/docs/define-a-subgraph#writing-mappings. De asemenea, poți adăuga rezultatele jurnalizării în fișierul de mapare, consultă aici.

1import { Bet, Player } from "../generated/schema"
2import { PlacedBet } from "../generated/GameContract/GameContract"
3
4export function handleNewBet(event: PlacedBet): void {
5 let player = Player.load(event.transaction.from.toHex())
6
7 if (player == null) {
8 // creare dacă nu există încă
9 player = new Player(event.transaction.from.toHex())
10 player.bets = new Array<string>(0)
11 player.totalPlayedCount = 0
12 player.hasWonCount = 0
13 player.hasLostCount = 0
14 }
15
16 let bet = new Bet(
17 event.transaction.hash.toHex() + "-" + event.logIndex.toString()
18 )
19 bet.player = player.id
20 bet.playerHasWon = event.params.hasWon
21 bet.time = event.block.timestamp
22 bet.save()
23
24 player.totalPlayedCount++
25 if (event.params.hasWon) {
26 player.hasWonCount++
27 } else {
28 player.hasLostCount++
29 }
30
31 // actualizează matrice ca aceasta
32 let bets = player.bets
33 bets.push(bet.id)
34 player.bets = bets
35
36 player.save()
37}
38
Afișează tot

Folosindu-l în Front-end

Folosind ceva de genul Apollo Boost, poți integra cu ușurință „The Graph” în aplicația ta React Dapp (sau Apollo Vue). Mai ales atunci când utilizezi hooks React și Apollo, preluarea datelor este la fel de simplă ca scrierea unei singure interogări GrafQl în componenta ta. O configurare tipică ar putea arăta astfel:

1// Vezi toate subgraph-urile: https://thegraph.com/explorer/
2const client = new ApolloClient({
3 uri: "{{ subgraphUrl }}",
4})
5
6ReactDOM.render(
7 <ApolloProvider client={client}>
8 <App />
9 </ApolloProvider>,
10 document.getElementById("root")
11)
12
Afișează tot

Și acum putem scrie, de exemplu, o interogare ca aceasta. Aceasta ne va aduce

  • de câte ori a câștigat utilizatorul curent
  • de câte ori a pierdut utilizatorul curent
  • o listă a marcajelor temporale cu toate pariurile sale anterioare

Toate într-o singură cerere către GraphQL server.

1const myGraphQlQuery = gql`
2 players(where: { id: $currentUser }) {
3 totalPlayedCount
4 hasWonCount
5 hasLostCount
6 bets {
7 time
8 }
9 }
10`
11
12const { loading, error, data } = useQuery(myGraphQlQuery)
13
14React.useEffect(() => {
15 if (!loading && !error && data) {
16 console.log({ data })
17 }
18}, [loading, error, data])
19
Afișează tot

Magic

Dar ne lipsește o ultimă piesă din puzzle și acesta este serverul. Îl poți rula singur sau poți utiliza serviciul găzduit.

Serverul „The Graph”

Exploratorul Graph: Serviciul găzduit

Cel mai simplu mod de a utiliza serviciul găzduit. Urmează instrucțiunile aici pentru a implementa un subgraph. Pentru multe proiecte, poți găsi de fapt, „subgraph”-uri deja realizate în explorer la https://thegraph.com/explorer/.

Exploratorul - The Graph

Rularea propriului tău nod

Alternativ, poți rula propriul nod: https://github.com/graphprotocol/graph-node#quick-start. Un motiv pentru a face acest lucru poate fi utilizarea unei rețele care nu este acceptată de serviciul găzduit. În prezent, sunt acceptate rețeaua principală, Kovan, Rinkeby, Ropsten, Goerli, PoA-Core, xDAI și Sokol.

Viitorul descentralizat

GraphQL suportă fluxuri și pentru evenimente nou primite. Acest lucru nu este încă pe deplin susținut de „The Graph”, dar va fi lansat în curând.

Un aspect care lipsește este totuși descentralizarea. „The Graph” are planuri viitoare pentru a deveni în cele din urmă un protocol complet descentralizat. Acestea sunt două articole mari care explică planul în detaliu:

Două aspecte esențiale sunt:

  1. Utilizatorii vor plăti indexurile pentru interogări.
  2. Indexurile vor miza tokenuri Graph (GRT).
Ultima editare: , Invalid DateTime
Edit page