ذا غراف: إصلاح استعلام بيانات ويب3
هذه المرة سنلقي نظرة فاحصة على ذا غراف الذي أصبح بشكل أساسي جزءًا من الحزمة القياسية لتطوير التطبيقات اللامركزية في العام الماضي. دعنا نرى أولاً كيف سنقوم بالأشياء بالطريقة التقليدية...
بدون ذا غراف...
لذا دعنا نستخدم مثالًا بسيطًا لأغراض التوضيح. كلنا نحب الألعاب، لذا تخيل لعبة بسيطة يضع فيها المستخدمون رهانات:
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}إظهار الكلالآن لنفترض أننا في تطبيقنا اللامركزي، نريد عرض إجمالي الرهانات، وإجمالي الألعاب الخاسرة/الرابحة وكذلك تحديثها كلما لعب شخص ما مرة أخرى. سيكون النهج:
- جلب
totalGamesPlayerWon. - جلب
totalGamesPlayerLost. - الاشتراك في أحداث
BetPlaced.
يمكننا الاستماع إلى الحدث في ويب3 (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});إظهار الكلالآن هذا لا يزال جيدًا إلى حد ما لمثالنا البسيط. ولكن لنفترض أننا نريد الآن عرض مبالغ الرهانات الخاسرة/الرابحة فقط للاعب الحالي. حسنًا، حظنا سيئ، من الأفضل لك نشر عقد جديد يخزن هذه القيم ويجلبها. والآن تخيل عقدًا ذكيًا وتطبيقًا لامركزيًا أكثر تعقيدًا، يمكن أن تصبح الأمور فوضوية بسرعة.
يمكنك أن ترى كيف أن هذا ليس الأمثل:
- لا يعمل مع العقود المنشورة بالفعل.
- تكاليف غاز إضافية لتخزين هذه القيم.
- يتطلب استدعاء آخر لجلب البيانات من عقدة إيثريوم.
الآن دعونا نلقي نظرة على حل أفضل.
دعني أقدم لكم جراف كيو إل
أولاً، دعنا نتحدث عن جراف كيو إل، الذي صممته ونفذته شركة فيسبوك في الأصل. قد تكون على دراية بنموذج واجهة برمجة التطبيقات REST التقليدية. تخيل الآن أنه يمكنك بدلاً من ذلك كتابة استعلام للبيانات التي تريدها بالضبط:
تلتقط الصورتان جوهر جراف كيو إل إلى حد كبير. باستخدام الاستعلام الموجود على اليمين، يمكننا تحديد البيانات التي نريدها بالضبط، لذلك نحصل على كل شيء في طلب واحد ولا شيء أكثر مما نحتاجه بالضبط. يتعامل خادم جراف كيو إل مع جلب جميع البيانات المطلوبة، لذلك من السهل جدًا على جانب المستهلك في واجهة التطبيق استخدامه. هذا شرح لطيف (opens in a new tab) لكيفية تعامل الخادم مع استعلام بالضبط إذا كنت مهتمًا.
الآن مع هذه المعرفة، دعنا ننتقل أخيرًا إلى فضاء البلوكتشين وذا غراف.
ما هو ذا غراف؟
البلوكتشين هي قاعدة بيانات لامركزية، ولكن على عكس ما هو معتاد، ليس لدينا لغة استعلام لقاعدة البيانات هذه. حلول استرجاع البيانات مؤلمة أو مستحيلة تمامًا. ذا غراف هو بروتوكول لامركزي لفهرسة بيانات البلوكتشين والاستعلام عنها. وربما خمنت ذلك، إنه يستخدم جراف كيو إل كلغة استعلام.
الأمثلة هي دائمًا الأفضل لفهم شيء ما، لذلك دعونا نستخدم ذا غراف لمثال GameContract الخاص بنا.
كيفية إنشاء Subgraph
يُطلق على تعريف كيفية فهرسة البيانات اسم subgraph. يتطلب ثلاثة مكونات:
- البيان (Manifest) (
subgraph.yaml) - المخطط (Schema) (
schema.graphql) - الربط (Mapping) (
mapping.ts)
البيان (Manifest) (subgraph.yaml)
البيان هو ملف التكوين الخاص بنا ويحدد:
- أي العقود الذكية يجب فهرستها (العنوان، الشبكة، واجهة التطبيق الثنائية...)
- أي الأحداث التي يجب الاستماع إليها
- أشياء أخرى للاستماع إليها مثل استدعاءات الوظائف أو الكتل
- دوال الربط التي يتم استدعاؤها (انظر
mapping.tsأدناه)
يمكنك تحديد عقود ومعالجات متعددة هنا. سيكون الإعداد النموذجي هو وجود مجلد subgraph داخل مشروع هارد هات مع مستودعه الخاص. ثم يمكنك بسهولة الرجوع إلى واجهة التطبيق الثنائية.
لأسباب تتعلق بالراحة، قد ترغب أيضًا في استخدام أداة قوالب مثل mustache. ثم تقوم بإنشاء subgraph.template.yaml وإدراج العناوين بناءً على أحدث عمليات النشر. لإعداد مثال أكثر تقدمًا، انظر على سبيل المثال مستودع آفي subgraph (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) (schema.graphql)
المخطط هو تعريف بيانات جراف كيو إل. سيسمح لك بتحديد الكيانات الموجودة وأنواعها. الأنواع المدعومة من ذا غراف هي
- بايت
- ID
- String
- Boolean
- 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}78type Player @entity {9 id: ID!10 totalPlayedCount: Int11 hasWonCount: Int12 hasLostCount: Int13 bets: [Bet]!14}إظهار الكلالربط (Mapping) (mapping.ts)
يحدد ملف الربط في ذا غراف وظائفنا التي تحول الأحداث الواردة إلى كيانات. إنه مكتوب بلغة AssemblyScript، وهي مجموعة فرعية من Typescript. وهذا يعني أنه يمكن تجميعه في WASM (ويب أسيمبلي) لتنفيذ الربط بشكل أكثر كفاءة وسهولة.
ستحتاج إلى تحديد كل دالة مسماة في ملف subgraph.yaml، لذا في حالتنا نحتاج فقط إلى دالة واحدة: handleNewBet. نحاول أولاً تحميل كيان اللاعب من عنوان المرسل كمعرّف. إذا لم يكن موجودًا، فإننا ننشئ كيانًا جديدًا ونملأه بالقيم الأولية.
ثم ننشئ كيان Bet جديد. سيكون المعرّف لهذا هو event.transaction.hash.toHex() + "-" + event.logIndex.toString() مما يضمن دائمًا قيمة فريدة. استخدام التجزئة (هاش) فقط لا يكفي حيث قد يقوم شخص ما باستدعاء دالة placeBet عدة مرات في معاملة واحدة عبر عقد ذكي.
أخيرًا، يمكننا تحديث كيان اللاعب بجميع البيانات. لا يمكن إلحاق العناصر بالمصفوفات مباشرةً، ولكن يجب تحديثها كما هو موضح هنا. نستخدم المعرّف للإشارة إلى الرهان. و .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، يمكنك بسهولة دمج ذا غراف في تطبيق رياكت اللامركزي (أو Apollo-Vue). خاصة عند استخدام رياكت hooks وApollo، فإن جلب البيانات بسيط مثل كتابة استعلام جراف كيو إل واحد في المكون الخاص بك. قد يبدو الإعداد النموذجي كما يلي:
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)إظهار الكلوالآن يمكننا كتابة استعلام مثل هذا على سبيل المثال. سيؤدي هذا إلى جلب
- كم مرة فاز المستخدم الحالي
- كم مرة خسر المستخدم الحالي
- قائمة من الطوابع الزمنية مع جميع رهاناته السابقة
كل ذلك في طلب واحد إلى خادم جراف كيو إل.
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])إظهار الكللكننا نفتقد قطعة أخيرة من اللغز وهي الخادم. يمكنك إما تشغيله بنفسك أو استخدام الخدمة المستضافة.
خادم ذا غراف
مستكشف ذا غراف: الخدمة المستضافة
أسهل طريقة هي استخدام الخدمة المستضافة. اتبع التعليمات هنا (opens in a new tab) لنشر subgraph. بالنسبة للعديد من المشاريع، يمكنك في الواقع العثور على subgraphs موجودة في المستكشف (opens in a new tab).
تشغيل عقدتك الخاصة
بدلاً من ذلك، يمكنك تشغيل عقدتك الخاصة. المستندات هنا (opens in a new tab). أحد أسباب القيام بذلك قد يكون استخدام شبكة غير مدعومة من قبل الخدمة المستضافة. يمكن العثور على الشبكات المدعومة حاليًا هنا (opens in a new tab).
المستقبل اللامركزي
يدعم جراف كيو إل التدفقات أيضًا للأحداث الواردة حديثًا. هذه مدعومة على the graph من خلال Substreams (opens in a new tab) وهي حاليًا في إصدار تجريبي مفتوح.
في 2021 (opens in a new tab) بدأ ذا غراف انتقاله إلى شبكة فهرسة لامركزية. يمكنك قراءة المزيد حول بنية شبكة الفهرسة اللامركزية هذه هنا (opens in a new tab).
هناك جانبان رئيسيان هما:
- يدفع المستخدمون للمفهرسين مقابل الاستعلامات.
- يقوم المفهرسون بتخزين حصص رموز ذا غراف (GRT).
آخر تحديث للصفحة: 26 فبراير 2026






