مرکزی مواد پر جائیں

The Graph: ویب 3 ڈیٹا کیوریئنگ کا حل

Solidity
اسمارٹ کانٹریکٹس
کیوریئنگ
the graph
React
درمیانی
مارکس واس
6 ستمبر، 2020
10 منٹ کی پڑھائی

اس بار ہم The Graph کا گہرائی سے جائزہ لیں گے جو پچھلے سال میں dapps تیار کرنے کے لیے معیاری اسٹیک کا لازمی حصہ بن گیا ہے۔ آئیے پہلے دیکھتے ہیں کہ ہم روایتی طریقے سے چیزیں کیسے کریں گے...

The Graph کے بغیر...

تو آئیے وضاحت کے مقاصد کے لیے ایک سادہ سی مثال لیتے ہیں۔ ہم سب کو گیمز پسند ہیں، لہذا ایک ایسے سادہ گیم کا تصور کریں جس میں صارفین شرط لگاتے ہیں:

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, "Transfer failed");
14 totalGamesPlayerWon++;
15 } else {
16 totalGamesPlayerLost++;
17 }
18
19 emit BetPlaced(msg.sender, msg.value, hasWon);
20 }
21}
سب دکھائیں

اب فرض کریں کہ ہم اپنی dapp میں، کل شرطیں، ہارے/جیتے گئے کل گیمز دکھانا چاہتے ہیں اور جب بھی کوئی دوبارہ کھیلے تو اسے اپ ڈیٹ بھی کرنا چاہتے ہیں۔ اس کا طریقہ کار یہ ہوگا:

  1. totalGamesPlayerWon بازیافت (Fetch) کریں۔
  2. totalGamesPlayerLost بازیافت کریں۔
  3. BetPlaced ایونٹس کو سبسکرائب کریں۔

ہم دائیں جانب دکھائے گئے طریقے کے مطابق Web3 میں ایونٹ (opens in a new tab) کو سن سکتے ہیں، لیکن اس کے لیے کافی سارے کیسز کو ہینڈل کرنے کی ضرورت ہوتی ہے۔

1GameContract.events.BetPlaced({
2 fromBlock: 0
3}, function(error, event) { console.log(event); })
4.on('data', function(event) {
5 // ایونٹ فائر ہو گیا
6})
7.on('changed', function(event) {
8 // ایونٹ دوبارہ ہٹا دیا گیا
9})
10.on('error', function(error, receipt) {
11 // ٹرانزیکشن مسترد کر دی گئی
12});
سب دکھائیں

اب یہ ہماری سادہ مثال کے لیے کسی حد تک ٹھیک ہے۔ لیکن فرض کریں کہ اب ہم صرف موجودہ کھلاڑی کے لیے ہاری/جیتی گئی شرطوں کی رقم دکھانا چاہتے ہیں۔ تو ہماری قسمت خراب ہے، آپ کے لیے بہتر ہے کہ ایک نیا کانٹریکٹ ڈیپلائے کریں جو ان ویلیوز کو اسٹور کرے اور انہیں بازیافت کرے۔ اور اب ایک بہت زیادہ پیچیدہ اسمارٹ کانٹریکٹ اور dapp کا تصور کریں، چیزیں تیزی سے الجھ سکتی ہیں۔

کوئی بھی آسانی سے کیوری نہیں کر سکتا

آپ دیکھ سکتے ہیں کہ یہ طریقہ کیوں بہترین نہیں ہے:

  • پہلے سے ڈیپلائے کیے گئے کانٹریکٹس کے لیے کام نہیں کرتا۔
  • ان ویلیوز کو اسٹور کرنے کے لیے اضافی گیس کی لاگت۔
  • ایتھیریم نوڈ کے لیے ڈیٹا بازیافت کرنے کے لیے ایک اور کال کی ضرورت ہوتی ہے۔

یہ کافی نہیں ہے

اب آئیے ایک بہتر حل کی طرف دیکھتے ہیں۔

آئیے میں آپ کا تعارف GraphQL سے کرواتا ہوں

پہلے ہم GraphQL کے بارے میں بات کرتے ہیں، جسے اصل میں فیس بک نے ڈیزائن اور نافذ کیا تھا۔ آپ شاید روایتی REST API ماڈل سے واقف ہوں گے۔ اب تصور کریں کہ اس کے بجائے آپ بالکل اسی ڈیٹا کے لیے کیوری لکھ سکتے ہیں جو آپ چاہتے تھے:

GraphQL API بمقابلہ REST API

The Graph پلے گراؤنڈ میں GraphQL کیوری کا متحرک مظاہرہ

یہ دونوں تصاویر کافی حد تک GraphQL کے جوہر کو واضح کرتی ہیں۔ دائیں جانب کی کیوری کے ساتھ ہم بالکل واضح کر سکتے ہیں کہ ہمیں کون سا ڈیٹا چاہیے، لہذا وہاں ہمیں ایک ہی درخواست میں سب کچھ مل جاتا ہے اور ہماری ضرورت سے زیادہ کچھ نہیں۔ ایک GraphQL سرور درکار تمام ڈیٹا کو بازیافت کرنے کا کام سنبھالتا ہے، لہذا فرنٹ اینڈ کنزیومر سائیڈ کے لیے اسے استعمال کرنا انتہائی آسان ہے۔ اگر آپ دلچسپی رکھتے ہیں تو یہ ایک اچھی وضاحت ہے (opens in a new tab) کہ سرور کس طرح کیوری کو ہینڈل کرتا ہے۔

اب اس علم کے ساتھ، آئیے بالآخر بلاک چین کی دنیا اور The Graph کی طرف چلتے ہیں۔

The Graph کیا ہے؟

بلاک چین ایک ڈی سینٹرلائزڈ ڈیٹا بیس ہے، لیکن عام صورتحال کے برعکس، ہمارے پاس اس ڈیٹا بیس کے لیے کوئی کیوری لینگویج نہیں ہے۔ ڈیٹا بازیافت کرنے کے حل تکلیف دہ یا مکمل طور پر ناممکن ہیں۔ The Graph بلاک چین ڈیٹا کی انڈیکسنگ اور کیوریئنگ کے لیے ایک ڈی سینٹرلائزڈ پروٹوکول ہے۔ اور جیسا کہ آپ نے اندازہ لگا لیا ہوگا، یہ کیوری لینگویج کے طور پر GraphQL کا استعمال کر رہا ہے۔

The Graph

کسی چیز کو سمجھنے کے لیے مثالیں ہمیشہ بہترین ہوتی ہیں، لہذا آئیے اپنی GameContract کی مثال کے لیے The Graph کا استعمال کریں۔

سب گراف (Subgraph) کیسے بنائیں

ڈیٹا کو انڈیکس کرنے کے طریقے کی تعریف کو سب گراف (subgraph) کہا جاتا ہے۔ اس کے لیے تین اجزاء کی ضرورت ہوتی ہے:

  1. مینی فیسٹ (subgraph.yaml)
  2. اسکیما (schema.graphql)
  3. میپنگ (mapping.ts)

مینی فیسٹ (subgraph.yaml)

مینی فیسٹ ہماری کنفیگریشن فائل ہے اور یہ درج ذیل کی وضاحت کرتی ہے:

  • کن اسمارٹ کانٹریکٹس کو انڈیکس کرنا ہے (ایڈریس، نیٹ ورک، ABI...)
  • کن ایونٹس کو سننا ہے
  • سننے کے لیے دیگر چیزیں جیسے فنکشن کالز یا بلاکس
  • کال کیے جانے والے میپنگ فنکشنز (نیچے mapping.ts دیکھیں)

آپ یہاں متعدد کانٹریکٹس اور ہینڈلرز کی وضاحت کر سکتے ہیں۔ ایک عام سیٹ اپ میں Hardhat پروجیکٹ کے اندر ایک سب گراف فولڈر ہوگا جس کی اپنی ریپوزٹری ہوگی۔ پھر آپ آسانی سے ABI کا حوالہ دے سکتے ہیں۔

سہولت کی وجوہات کی بنا پر آپ mustache جیسے ٹیمپلیٹ ٹول کا استعمال بھی کر سکتے ہیں۔ پھر آپ ایک subgraph.template.yaml بناتے ہیں اور تازہ ترین ڈیپلائیمنٹس کی بنیاد پر ایڈریسز داخل کرتے ہیں۔ مزید جدید مثال کے سیٹ اپ کے لیے، مثال کے طور پر Aave سب گراف ریپو (opens in a new tab) دیکھیں۔

اور مکمل دستاویزات یہاں (opens in a new tab) دیکھی جا سکتی ہیں۔

1specVersion: 0.0.1
2description: Placing Bets on 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
سب دکھائیں

اسکیما (schema.graphql)

اسکیما GraphQL ڈیٹا کی تعریف ہے۔ یہ آپ کو یہ واضح کرنے کی اجازت دے گا کہ کون سی اینٹیٹیز (entities) موجود ہیں اور ان کی اقسام کیا ہیں۔ The Graph کی طرف سے سپورٹ کردہ اقسام یہ ہیں:

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

آپ تعلقات (relationships) کی وضاحت کے لیے اینٹیٹیز کو بطور قسم (type) بھی استعمال کر سکتے ہیں۔ ہماری مثال میں ہم کھلاڑی سے شرطوں تک 1-سے-متعدد (1-to-many) تعلق کی وضاحت کرتے ہیں۔ ! کا مطلب ہے کہ ویلیو خالی نہیں ہو سکتی۔ مکمل دستاویزات یہاں (opens in a new tab) دیکھی جا سکتی ہیں۔

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}
سب دکھائیں

میپنگ (mapping.ts)

The Graph میں میپنگ فائل ہمارے ان فنکشنز کی وضاحت کرتی ہے جو آنے والے ایونٹس کو اینٹیٹیز میں تبدیل کرتے ہیں۔ یہ AssemblyScript میں لکھی گئی ہے، جو Typescript کا ایک ذیلی سیٹ (subset) ہے۔ اس کا مطلب ہے کہ میپنگ کے زیادہ موثر اور پورٹیبل نفاذ کے لیے اسے WASM (WebAssembly) میں مرتب (compile) کیا جا سکتا ہے۔

آپ کو subgraph.yaml فائل میں نامزد ہر فنکشن کی وضاحت کرنے کی ضرورت ہوگی، لہذا ہمارے معاملے میں ہمیں صرف ایک کی ضرورت ہے: handleNewBet۔ ہم سب سے پہلے بھیجنے والے کے ایڈریس سے بطور id پلیئر اینٹیٹی کو لوڈ کرنے کی کوشش کرتے ہیں۔ اگر یہ موجود نہیں ہے، تو ہم ایک نئی اینٹیٹی بناتے ہیں اور اسے ابتدائی ویلیوز سے بھرتے ہیں۔

پھر ہم ایک نئی Bet اینٹیٹی بناتے ہیں۔ اس کے لیے id event.transaction.hash.toHex() + "-" + event.logIndex.toString() ہوگی جو ہمیشہ ایک منفرد ویلیو کو یقینی بناتی ہے۔ صرف ہیش کا استعمال کافی نہیں ہے کیونکہ کوئی شخص اسمارٹ کانٹریکٹ کے ذریعے ایک ہی ٹرانزیکشن میں کئی بار placeBet فنکشن کو کال کر سکتا ہے۔

آخر میں ہم تمام ڈیٹا کے ساتھ پلیئر اینٹیٹی کو اپ ڈیٹ کر سکتے ہیں۔ ایریز (Arrays) کو براہ راست پش نہیں کیا جا سکتا، بلکہ انہیں یہاں دکھائے گئے طریقے کے مطابق اپ ڈیٹ کرنے کی ضرورت ہوتی ہے۔ ہم شرط کا حوالہ دینے کے لیے id کا استعمال کرتے ہیں۔ اور کسی اینٹیٹی کو اسٹور کرنے کے لیے آخر میں .save() درکار ہوتا ہے۔

مکمل دستاویزات یہاں دیکھی جا سکتی ہیں: https://thegraph.com/docs/en/developing/creating-a-subgraph/#writing-mappings۔ (opens in a new tab) آپ میپنگ فائل میں لاگنگ آؤٹ پٹ بھی شامل کر سکتے ہیں، یہاں (opens in a new tab) دیکھیں۔

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 // اگر ابھی تک موجود نہیں ہے تو بنائیں
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 // ایرے کو اس طرح اپ ڈیٹ کریں
32 let bets = player.bets
33 bets.push(bet.id)
34 player.bets = bets
35
36 player.save()
37}
سب دکھائیں

اسے فرنٹ اینڈ میں استعمال کرنا

Apollo Boost جیسی کسی چیز کا استعمال کرتے ہوئے، آپ آسانی سے The Graph کو اپنی React dapp (یا Apollo-Vue) میں ضم کر سکتے ہیں۔ خاص طور پر جب React hooks اور Apollo کا استعمال کیا جائے، تو ڈیٹا بازیافت کرنا اتنا ہی آسان ہے جتنا کہ آپ کے جزو (component) میں ایک واحد GraphQL کیوری لکھنا۔ ایک عام سیٹ اپ کچھ اس طرح دکھ سکتا ہے:

1// تمام سب گرافس دیکھیں: 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)
سب دکھائیں

اور اب ہم مثال کے طور پر اس طرح کی ایک کیوری لکھ سکتے ہیں۔ یہ ہمارے لیے بازیافت کرے گا:

  • موجودہ صارف کتنی بار جیتا ہے
  • موجودہ صارف کتنی بار ہارا ہے
  • اس کی تمام پچھلی شرطوں کے ساتھ ٹائم اسٹیمپس کی ایک فہرست

یہ سب GraphQL سرور کو ایک ہی درخواست میں۔

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])
سب دکھائیں

جادو

لیکن ہم پہیلی کا ایک آخری حصہ چھوڑ رہے ہیں اور وہ ہے سرور۔ آپ یا تو اسے خود چلا سکتے ہیں یا ہوسٹڈ سروس استعمال کر سکتے ہیں۔

The Graph سرور

گراف ایکسپلورر: ہوسٹڈ سروس

سب سے آسان طریقہ ہوسٹڈ سروس کا استعمال کرنا ہے۔ سب گراف ڈیپلائے کرنے کے لیے یہاں (opens in a new tab) دی گئی ہدایات پر عمل کریں۔ بہت سے پروجیکٹس کے لیے آپ دراصل ایکسپلورر (opens in a new tab) میں موجودہ سب گرافس تلاش کر سکتے ہیں۔

The Graph-Explorer

اپنا نوڈ چلانا

متبادل کے طور پر آپ اپنا نوڈ چلا سکتے ہیں۔ دستاویزات یہاں (opens in a new tab) ہیں۔ ایسا کرنے کی ایک وجہ ایسے نیٹ ورک کا استعمال ہو سکتی ہے جو ہوسٹڈ سروس کے ذریعے سپورٹڈ نہیں ہے۔ فی الحال سپورٹڈ نیٹ ورکس یہاں مل سکتے ہیں (opens in a new tab)۔

ڈی سینٹرلائزڈ مستقبل

GraphQL نئے آنے والے ایونٹس کے لیے اسٹریمز کو بھی سپورٹ کرتا ہے۔ یہ گراف پر Substreams (opens in a new tab) کے ذریعے سپورٹ کیے جاتے ہیں جو فی الحال اوپن بیٹا میں ہیں۔

2021 میں The Graph نے ایک ڈی سینٹرلائزڈ انڈیکسنگ نیٹ ورک کی طرف اپنی منتقلی شروع کی۔ آپ اس ڈی سینٹرلائزڈ انڈیکسنگ نیٹ ورک کے آرکیٹیکچر کے بارے میں مزید یہاں (opens in a new tab) پڑھ سکتے ہیں۔

دو اہم پہلو یہ ہیں:

  1. صارفین کیوریز کے لیے انڈیکسرز کو ادائیگی کرتے ہیں۔
  2. انڈیکسرز Graph Tokens (GRT) اسٹیک کرتے ہیں۔

صفحہ کی آخری اپ ڈیٹ: 26 فروری، 2026

کیا یہ ٹیوٹوریل مددگار تھا؟