اہم مواد پر جائیں

دی گراف: Web3 ڈیٹا کی دریافت کو درست کرنا

solidity
اسمارٹ معاہدات
querying
دی گراف
react
متوسط
Markus Waas
6 ستمبر، 2020
10 منٹ کی پڑھائی

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

دی گراف کے بغیر...

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

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 حاصل کریں۔
  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 // event fired
6})
7.on('changed', function(event) {
8 // event was removed again
9})
10.on('error', function(error, receipt) {
11 // tx rejected
12});
سب دکھائیں

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

کوئی آسانی سے دریافت نہیں کرتا

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

  • پہلے سے تعینات کردہ کنٹریکٹس کے لیے کام نہیں کرتا۔
  • ان اقدار کو ذخیرہ کرنے کے لیے اضافی گیس کی لاگت۔
  • ایتھریم نوڈ کے لیے ڈیٹا حاصل کرنے کے لیے ایک اور کال کی ضرورت ہے۔

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

اب آئیے ایک بہتر حل پر نظر ڈالتے ہیں۔

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

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

GraphQL API بمقابلہ REST API

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

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

دی گراف کیا ہے؟

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

دی گراف

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

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

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

  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 ڈیٹا کی تعریف ہے۔ یہ آپ کو یہ بیان کرنے کی اجازت دے گا کہ کون سی اینٹیٹیز موجود ہیں اور ان کی اقسام کیا ہیں۔ دی گراف سے معاون اقسام ہیں

  • بائٹس
  • ID
  • اسٹرنگ
  • بولین
  • Int
  • BigInt
  • BigDecimal

آپ تعلقات کی وضاحت کے لیے اینٹیٹیز کو قسم کے طور پر بھی استعمال کر سکتے ہیں۔ ہماری مثال میں ہم کھلاڑی سے شرطوں تک 1-سے-کئی تعلقات کی وضاحت کرتے ہیں۔ ! کا مطلب ہے کہ قدر خالی نہیں ہو سکتی۔ مکمل دستاویزات یہاں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)

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

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

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

آخر میں ہم تمام ڈیٹا کے ساتھ پلیئر اینٹیٹی کو اپ ڈیٹ کر سکتے ہیں۔ ایریز کو براہ راست پش نہیں کیا جا سکتا، بلکہ انہیں یہاں دکھائے گئے طریقے سے اپ ڈیٹ کرنے کی ضرورت ہے۔ ہم شرط کا حوالہ دینے کے لیے 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 // create if doesn't exist yet
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 // update array like this
32 let bets = player.bets
33 bets.push(bet.id)
34 player.bets = bets
35
36 player.save()
37}
سب دکھائیں

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

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

1// See all subgraphs: 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])
سب دکھائیں

جادو

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

دی گراف سرور

گراف ایکسپلورر: میزبان سروس

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

دی گراف-ایکسپلورر

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

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

غیر مرکزی مستقبل

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

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

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

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

صفحہ کی آخری تازہ کاری: 24 جون، 2025

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