The Graph: ویب 3 ڈیٹا کیوریئنگ کا حل
اس بار ہم The Graph کا گہرائی سے جائزہ لیں گے جو پچھلے سال میں dapps تیار کرنے کے لیے معیاری اسٹیک کا لازمی حصہ بن گیا ہے۔ آئیے پہلے دیکھتے ہیں کہ ہم روایتی طریقے سے چیزیں کیسے کریں گے...
The Graph کے بغیر...
تو آئیے وضاحت کے مقاصد کے لیے ایک سادہ سی مثال لیتے ہیں۔ ہم سب کو گیمز پسند ہیں، لہذا ایک ایسے سادہ گیم کا تصور کریں جس میں صارفین شرط لگاتے ہیں:
1pragma solidity 0.7.1;23contract Game {4 uint256 totalGamesPlayerWon = 0;5 uint256 totalGamesPlayerLost = 0;6 event BetPlaced(address player, uint256 value, bool hasWon);78 function placeBet() external payable {9 bool hasWon = evaluateBetForPlayer(msg.sender);1011 if (hasWon) {12 (bool success, ) = msg.sender.call{ value: msg.value * 2 }('');13 require(success, "Transfer failed");14 totalGamesPlayerWon++;15 } else {16 totalGamesPlayerLost++;17 }1819 emit BetPlaced(msg.sender, msg.value, hasWon);20 }21}سب دکھائیںاب فرض کریں کہ ہم اپنی dapp میں، کل شرطیں، ہارے/جیتے گئے کل گیمز دکھانا چاہتے ہیں اور جب بھی کوئی دوبارہ کھیلے تو اسے اپ ڈیٹ بھی کرنا چاہتے ہیں۔ اس کا طریقہ کار یہ ہوگا:
totalGamesPlayerWonبازیافت (Fetch) کریں۔totalGamesPlayerLostبازیافت کریں۔BetPlacedایونٹس کو سبسکرائب کریں۔
ہم دائیں جانب دکھائے گئے طریقے کے مطابق Web3 میں ایونٹ (opens in a new tab) کو سن سکتے ہیں، لیکن اس کے لیے کافی سارے کیسز کو ہینڈل کرنے کی ضرورت ہوتی ہے۔
1GameContract.events.BetPlaced({2 fromBlock: 03}, 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 کے جوہر کو واضح کرتی ہیں۔ دائیں جانب کی کیوری کے ساتھ ہم بالکل واضح کر سکتے ہیں کہ ہمیں کون سا ڈیٹا چاہیے، لہذا وہاں ہمیں ایک ہی درخواست میں سب کچھ مل جاتا ہے اور ہماری ضرورت سے زیادہ کچھ نہیں۔ ایک GraphQL سرور درکار تمام ڈیٹا کو بازیافت کرنے کا کام سنبھالتا ہے، لہذا فرنٹ اینڈ کنزیومر سائیڈ کے لیے اسے استعمال کرنا انتہائی آسان ہے۔ اگر آپ دلچسپی رکھتے ہیں تو یہ ایک اچھی وضاحت ہے (opens in a new tab) کہ سرور کس طرح کیوری کو ہینڈل کرتا ہے۔
اب اس علم کے ساتھ، آئیے بالآخر بلاک چین کی دنیا اور The Graph کی طرف چلتے ہیں۔
The Graph کیا ہے؟
بلاک چین ایک ڈی سینٹرلائزڈ ڈیٹا بیس ہے، لیکن عام صورتحال کے برعکس، ہمارے پاس اس ڈیٹا بیس کے لیے کوئی کیوری لینگویج نہیں ہے۔ ڈیٹا بازیافت کرنے کے حل تکلیف دہ یا مکمل طور پر ناممکن ہیں۔ The Graph بلاک چین ڈیٹا کی انڈیکسنگ اور کیوریئنگ کے لیے ایک ڈی سینٹرلائزڈ پروٹوکول ہے۔ اور جیسا کہ آپ نے اندازہ لگا لیا ہوگا، یہ کیوری لینگویج کے طور پر GraphQL کا استعمال کر رہا ہے۔
کسی چیز کو سمجھنے کے لیے مثالیں ہمیشہ بہترین ہوتی ہیں، لہذا آئیے اپنی GameContract کی مثال کے لیے The Graph کا استعمال کریں۔
سب گراف (Subgraph) کیسے بنائیں
ڈیٹا کو انڈیکس کرنے کے طریقے کی تعریف کو سب گراف (subgraph) کہا جاتا ہے۔ اس کے لیے تین اجزاء کی ضرورت ہوتی ہے:
- مینی فیسٹ (
subgraph.yaml) - اسکیما (
schema.graphql) - میپنگ (
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.12description: Placing Bets on Ethereum3repository: - GitHub link -4schema:5 file: ./schema.graphql6dataSources:7 - kind: ethereum/contract8 name: GameContract9 network: mainnet10 source:11 address: '0x2E6454...cf77eC'12 abi: GameContract13 startBlock: 617524414 mapping:15 kind: ethereum/events16 apiVersion: 0.0.117 language: wasm/assemblyscript18 entities:19 - GameContract20 abis:21 - name: GameContract22 file: ../build/contracts/GameContract.json23 eventHandlers:24 - event: PlacedBet(address,uint256,bool)25 handler: handleNewBet26 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}78type Player @entity {9 id: ID!10 totalPlayedCount: Int11 hasWonCount: Int12 hasLostCount: Int13 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"34export function handleNewBet(event: PlacedBet): void {5 let player = Player.load(event.transaction.from.toHex())67 if (player == null) {8 // اگر ابھی تک موجود نہیں ہے تو بنائیں9 player = new Player(event.transaction.from.toHex())10 player.bets = new Array<string>(0)11 player.totalPlayedCount = 012 player.hasWonCount = 013 player.hasLostCount = 014 }1516 let bet = new Bet(17 event.transaction.hash.toHex() + "-" + event.logIndex.toString()18 )19 bet.player = player.id20 bet.playerHasWon = event.params.hasWon21 bet.time = event.block.timestamp22 bet.save()2324 player.totalPlayedCount++25 if (event.params.hasWon) {26 player.hasWonCount++27 } else {28 player.hasLostCount++29 }3031 // ایرے کو اس طرح اپ ڈیٹ کریں32 let bets = player.bets33 bets.push(bet.id)34 player.bets = bets3536 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})56ReactDOM.render(7 <ApolloProvider client={client}>8 <App />9 </ApolloProvider>,10 document.getElementById("root")11)سب دکھائیںاور اب ہم مثال کے طور پر اس طرح کی ایک کیوری لکھ سکتے ہیں۔ یہ ہمارے لیے بازیافت کرے گا:
- موجودہ صارف کتنی بار جیتا ہے
- موجودہ صارف کتنی بار ہارا ہے
- اس کی تمام پچھلی شرطوں کے ساتھ ٹائم اسٹیمپس کی ایک فہرست
یہ سب GraphQL سرور کو ایک ہی درخواست میں۔
1const myGraphQlQuery = gql`2 players(where: { id: $currentUser }) {3 totalPlayedCount4 hasWonCount5 hasLostCount6 bets {7 time8 }9 }10`1112const { loading, error, data } = useQuery(myGraphQlQuery)1314React.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) میں موجودہ سب گرافس تلاش کر سکتے ہیں۔
اپنا نوڈ چلانا
متبادل کے طور پر آپ اپنا نوڈ چلا سکتے ہیں۔ دستاویزات یہاں (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) پڑھ سکتے ہیں۔
دو اہم پہلو یہ ہیں:
- صارفین کیوریز کے لیے انڈیکسرز کو ادائیگی کرتے ہیں۔
- انڈیکسرز Graph Tokens (GRT) اسٹیک کرتے ہیں۔
صفحہ کی آخری اپ ڈیٹ: 26 فروری، 2026






