The Graph: Web3 தரவு வினவலைச் சரிசெய்தல்
இந்த முறை நாம் The Graph-ஐப் பற்றி விரிவாகப் பார்ப்போம், இது கடந்த ஆண்டில் பரவலாக்கப்பட்ட செயலிகளை (dapps) உருவாக்குவதற்கான நிலையான அடுக்கின் ஒரு பகுதியாக மாறியுள்ளது. முதலில் பாரம்பரிய முறையில் நாம் எவ்வாறு காரியங்களைச் செய்வோம் என்பதைப் பார்ப்போம்...
The Graph இல்லாமல்...
விளக்கத்திற்காக ஒரு எளிய உதாரணத்தைப் பார்ப்போம். நாம் அனைவரும் விளையாட்டுகளை விரும்புகிறோம், எனவே பயனர்கள் பந்தயம் கட்டும் ஒரு எளிய விளையாட்டைக் கற்பனை செய்து பாருங்கள்:
pragma solidity 0.7.1;
contract Game {
uint256 totalGamesPlayerWon = 0;
uint256 totalGamesPlayerLost = 0;
event BetPlaced(address player, uint256 value, bool hasWon);
function placeBet() external payable {
bool hasWon = evaluateBetForPlayer(msg.sender);
if (hasWon) {
(bool success, ) = msg.sender.call{ value: msg.value * 2 }('');
require(success, "Transfer failed");
totalGamesPlayerWon++;
} else {
totalGamesPlayerLost++;
}
emit BetPlaced(msg.sender, msg.value, hasWon);
}
}
இப்போது நமது பரவலாக்கப்பட்ட செயலியில் (dapp), மொத்த பந்தயங்கள், தோற்ற/வென்ற மொத்த விளையாட்டுகளைக் காட்ட விரும்புகிறோம், மேலும் யாராவது மீண்டும் விளையாடும்போதெல்லாம் அதைப் புதுப்பிக்க விரும்புகிறோம் என்று வைத்துக்கொள்வோம். அதற்கான அணுகுமுறை இதுவாக இருக்கும்:
totalGamesPlayerWonஐப் பெறவும்.totalGamesPlayerLostஐப் பெறவும்.BetPlacedநிகழ்வுகளுக்கு குழுசேரவும்.
வலதுபுறத்தில் காட்டப்பட்டுள்ளபடி Web3 இல் உள்ள நிகழ்வை (புதிய தாவலில் திறக்கப்படும்) நாம் கவனிக்கலாம், ஆனால் இதற்குச் சில பல நிகழ்வுகளைக் கையாள வேண்டியிருக்கும்.
GameContract.events.BetPlaced({
fromBlock: 0
}, function(error, event) { console.log(event); })
.on('data', function(event) {
// நிகழ்வு தூண்டப்பட்டது
})
.on('changed', function(event) {
// நிகழ்வு மீண்டும் நீக்கப்பட்டது
})
.on('error', function(error, receipt) {
// பரிவர்த்தனை நிராகரிக்கப்பட்டது
});
இப்போது நமது எளிய உதாரணத்திற்கு இது ஓரளவு பரவாயில்லை. ஆனால் தற்போதைய வீரருக்கு மட்டும் தோற்ற/வென்ற பந்தயங்களின் அளவைக் காட்ட விரும்புகிறோம் என்று வைத்துக்கொள்வோம். நமக்கு அதிர்ஷ்டம் இல்லை, அந்த மதிப்புகளைச் சேமித்து அவற்றைப் பெறும் புதிய ஒப்பந்தத்தை நீங்கள் நிலைநிறுத்துவது நல்லது. இப்போது மிகவும் சிக்கலான திறன் ஒப்பந்தம் மற்றும் dapp-ஐக் கற்பனை செய்து பாருங்கள், விஷயங்கள் விரைவாகக் குழப்பமடையக்கூடும்.
இது எவ்வாறு உகந்தது அல்ல என்பதை நீங்கள் பார்க்கலாம்:
- ஏற்கனவே நிலைநிறுத்தப்பட்ட ஒப்பந்தங்களுக்கு வேலை செய்யாது.
- அந்த மதிப்புகளைச் சேமிப்பதற்கான கூடுதல் எரிவாயு செலவுகள்.
- எத்திரியம் கணுவிற்கான தரவைப் பெற மற்றொரு அழைப்பு தேவைப்படுகிறது.
இப்போது ஒரு சிறந்த தீர்வைப் பார்ப்போம்.
GraphQL-ஐ உங்களுக்கு அறிமுகப்படுத்துகிறேன்
முதலில் ஃபேஸ்புக் மூலம் வடிவமைக்கப்பட்டு செயல்படுத்தப்பட்ட GraphQL பற்றிப் பேசுவோம். பாரம்பரிய REST API மாதிரி உங்களுக்குத் தெரிந்திருக்கலாம். இப்போது அதற்குப் பதிலாக உங்களுக்குத் தேவையான தரவுகளுக்கு மட்டுமே நீங்கள் ஒரு வினவலை எழுத முடியும் என்று கற்பனை செய்து பாருங்கள்:
இந்த இரண்டு படங்களும் GraphQL-இன் சாராம்சத்தை மிகச்சரியாகப் படம்பிடிக்கின்றன. வலதுபுறத்தில் உள்ள வினவலின் மூலம் நமக்கு என்ன தரவு வேண்டும் என்பதைத் துல்லியமாக வரையறுக்க முடியும், எனவே ஒரே கோரிக்கையில் அனைத்தையும் பெறுகிறோம், மேலும் நமக்குத் தேவையானதைத் தவிர வேறு எதுவும் இல்லை. தேவையான அனைத்து தரவையும் பெறுவதை ஒரு GraphQL சேவையகம் கையாளுகிறது, எனவே முன்பக்க நுகர்வோர் தரப்பைப் பயன்படுத்துவது நம்பமுடியாத அளவிற்கு எளிதானது. உங்களுக்கு ஆர்வமிருந்தால், சேவையகம் ஒரு வினவலை எவ்வாறு சரியாகக் கையாளுகிறது என்பதற்கான ஒரு நல்ல விளக்கம் இது (புதிய தாவலில் திறக்கப்படும்).
இப்போது அந்த அறிவைக் கொண்டு, இறுதியாகத் தொகுதிச்சங்கிலி வெளி மற்றும் The Graph-க்குள் நுழைவோம்.
The Graph என்றால் என்ன?
தொகுதிச்சங்கிலி என்பது பரவலாக்கப்பட்ட தரவுத்தளமாகும், ஆனால் வழக்கமாக இருப்பதற்கு மாறாக, இந்தத் தரவுத்தளத்திற்கு வினவல் மொழி (query language) நம்மிடம் இல்லை. தரவை மீட்டெடுப்பதற்கான தீர்வுகள் கடினமானவை அல்லது முற்றிலும் சாத்தியமற்றவை. The Graph என்பது தொகுதிச்சங்கிலி தரவைக் குறியீடு செய்வதற்கும் வினவுவதற்குமான பரவலாக்கப்பட்ட நெறிமுறையாகும். நீங்கள் யூகித்திருக்கலாம், இது GraphQL-ஐ வினவல் மொழியாகப் பயன்படுத்துகிறது.
எதையாவது புரிந்துகொள்ள உதாரணங்கள் எப்போதும் சிறந்தவை, எனவே நமது GameContract உதாரணத்திற்கு The Graph-ஐப் பயன்படுத்துவோம்.
துணை வரைபடத்தை எவ்வாறு உருவாக்குவது
தரவை எவ்வாறு குறியீடு செய்வது என்பதற்கான வரையறை துணை வரைபடம் (subgraph) என்று அழைக்கப்படுகிறது. இதற்கு மூன்று கூறுகள் தேவை:
- மேனிஃபெஸ்ட் (
subgraph.yaml) - ஸ்கீமா (
schema.graphql) - மேப்பிங் (
mapping.ts)
மேனிஃபெஸ்ட் (subgraph.yaml)
மேனிஃபெஸ்ட் என்பது நமது உள்ளமைவு (configuration) கோப்பாகும், மேலும் இது பின்வருவனவற்றை வரையறுக்கிறது:
- எந்தத் திறன் ஒப்பந்தங்களைக் குறியீடு செய்ய வேண்டும் (முகவரி, பிணையம், ABI...)
- எந்த நிகழ்வுகளைக் கவனிக்க வேண்டும்
- சார்பு அழைப்புகள் (function calls) அல்லது தொகுதிகள் (blocks) போன்ற கவனிக்க வேண்டிய பிற விஷயங்கள்
- அழைக்கப்படும் மேப்பிங் சார்புகள் (கீழே உள்ள
mapping.tsஐப் பார்க்கவும்)
நீங்கள் இங்கே பல ஒப்பந்தங்கள் மற்றும் கையாளுபவர்களை (handlers) வரையறுக்கலாம். ஒரு வழக்கமான அமைப்பானது Hardhat திட்டத்திற்குள் அதன் சொந்த களஞ்சியத்துடன் (repository) ஒரு துணை வரைபடக் கோப்புறையைக் கொண்டிருக்கும். பின்னர் நீங்கள் ABI-ஐ எளிதாகக் குறிப்பிடலாம்.
வசதிக்காக நீங்கள் mustache போன்ற டெம்ப்ளேட் கருவியைப் பயன்படுத்த விரும்பலாம். பின்னர் நீங்கள் ஒரு subgraph.template.yaml ஐ உருவாக்கி, சமீபத்திய நிலைநிறுத்தங்களின் அடிப்படையில் முகவரிகளைச் செருகலாம். மிகவும் மேம்பட்ட உதாரண அமைப்பிற்கு, ஆவே துணை வரைபடக் களஞ்சியத்தைப் (புதிய தாவலில் திறக்கப்படும்) பார்க்கவும்.
முழுமையான ஆவணங்களை இங்கே (புதிய தாவலில் திறக்கப்படும்) காணலாம்.
specVersion: 0.0.1
description: Placing Bets on Ethereum
repository: - GitHub link -
schema:
file: ./schema.graphql
dataSources:
- kind: ethereum/contract
name: GameContract
network: mainnet
source:
address: '0x2E6454...cf77eC'
abi: GameContract
startBlock: 6175244
mapping:
kind: ethereum/events
apiVersion: 0.0.1
language: wasm/assemblyscript
entities:
- GameContract
abis:
- name: GameContract
file: ../build/contracts/GameContract.json
eventHandlers:
- event: PlacedBet(address,uint256,bool)
handler: handleNewBet
file: ./src/mapping.ts
ஸ்கீமா (schema.graphql)
ஸ்கீமா என்பது GraphQL தரவு வரையறையாகும். எந்தெந்த உருப்படிகள் (entities) உள்ளன மற்றும் அவற்றின் வகைகளை வரையறுக்க இது உங்களை அனுமதிக்கும். The Graph-ஆல் ஆதரிக்கப்படும் வகைகள்:
- Bytes
- ID
- String
- Boolean
- Int
- BigInt
- BigDecimal
உறவுகளை வரையறுக்க நீங்கள் உருப்படிகளை வகையாகவும் பயன்படுத்தலாம். நமது எடுத்துக்காட்டில், வீரருக்கும் பந்தயங்களுக்கும் இடையே 1-க்கு-பல (1-to-many) உறவை வரையறுக்கிறோம். ! என்பது மதிப்பு காலியாக இருக்க முடியாது என்பதைக் குறிக்கிறது. முழுமையான ஆவணங்களை இங்கே (புதிய தாவலில் திறக்கப்படும்) காணலாம்.
type Bet @entity {
id: ID!
player: Player!
playerHasWon: Boolean!
time: Int!
}
type Player @entity {
id: ID!
totalPlayedCount: Int
hasWonCount: Int
hasLostCount: Int
bets: [Bet]!
}
மேப்பிங் (mapping.ts)
The Graph-இல் உள்ள மேப்பிங் கோப்பு, உள்வரும் நிகழ்வுகளை உருப்படிகளாக மாற்றும் நமது சார்புகளை வரையறுக்கிறது. இது TypeScript-இன் துணைக்குழுவான AssemblyScript-இல் எழுதப்பட்டுள்ளது. அதாவது, மேப்பிங்கின் மிகவும் திறமையான மற்றும் கையடக்கச் செயலாக்கத்திற்காக இதை WASM (WebAssembly)-ஆகத் தொகுக்க முடியும்.
subgraph.yaml கோப்பில் பெயரிடப்பட்ட ஒவ்வொரு சார்பையும் நீங்கள் வரையறுக்க வேண்டும், எனவே நமது விஷயத்தில் நமக்கு ஒன்று மட்டுமே தேவை: handleNewBet. அனுப்புநரின் முகவரியை id-ஆகக் கொண்டு Player உருப்படியை ஏற்ற முதலில் முயற்சிக்கிறோம். அது இல்லையென்றால், புதிய உருப்படியை உருவாக்கி அதைத் தொடக்க மதிப்புகளுடன் நிரப்புகிறோம்.
பின்னர் நாம் ஒரு புதிய Bet உருப்படியை உருவாக்குகிறோம். இதற்கான id event.transaction.hash.toHex() + "-" + event.logIndex.toString() ஆக இருக்கும், இது எப்போதும் தனித்துவமான மதிப்பை உறுதி செய்கிறது. திறன் ஒப்பந்தம் வழியாக ஒரே பரிவர்த்தனையில் யாராவது placeBet சார்பைப் பலமுறை அழைக்கக்கூடும் என்பதால், ஹாஷை மட்டும் பயன்படுத்துவது போதாது.
இறுதியாக நாம் அனைத்து தரவுகளுடனும் Player உருப்படியைப் புதுப்பிக்கலாம். வரிசைகளை (Arrays) நேரடியாகத் தள்ள முடியாது, ஆனால் இங்கே காட்டப்பட்டுள்ளபடி புதுப்பிக்கப்பட வேண்டும். பந்தயத்தைக் குறிப்பிட id-ஐப் பயன்படுத்துகிறோம். மேலும் ஒரு உருப்படியைச் சேமிக்க முடிவில் .save() தேவைப்படுகிறது.
முழுமையான ஆவணங்களை இங்கே காணலாம்: https://thegraph.com/docs/en/developing/creating-a-subgraph/#writing-mappings (புதிய தாவலில் திறக்கப்படும்). மேப்பிங் கோப்பில் லாக்கிங் வெளியீட்டையும் நீங்கள் சேர்க்கலாம், இங்கே (புதிய தாவலில் திறக்கப்படும்) பார்க்கவும்.
import { Bet, Player } from "../generated/schema"
import { PlacedBet } from "../generated/GameContract/GameContract"
export function handleNewBet(event: PlacedBet): void {
let player = Player.load(event.transaction.from.toHex())
if (player == null) {
// இதுவரை இல்லையென்றால் உருவாக்கவும்
player = new Player(event.transaction.from.toHex())
player.bets = new Array<string>(0)
player.totalPlayedCount = 0
player.hasWonCount = 0
player.hasLostCount = 0
}
let bet = new Bet(
event.transaction.hash.toHex() + "-" + event.logIndex.toString()
)
bet.player = player.id
bet.playerHasWon = event.params.hasWon
bet.time = event.block.timestamp
bet.save()
player.totalPlayedCount++
if (event.params.hasWon) {
player.hasWonCount++
} else {
player.hasLostCount++
}
// அணியை இதுபோன்று புதுப்பிக்கவும்
let bets = player.bets
bets.push(bet.id)
player.bets = bets
player.save()
}
முன்பக்கத்தில் (Frontend) இதைப் பயன்படுத்துதல்
Apollo Boost போன்ற ஒன்றைப் பயன்படுத்தி, உங்கள் React dapp-இல் (அல்லது Apollo-Vue) The Graph-ஐ எளிதாக ஒருங்கிணைக்கலாம். குறிப்பாக React ஹூக்ஸ் மற்றும் Apollo-ஐப் பயன்படுத்தும் போது, தரவைப் பெறுவது உங்கள் கூறில் (component) ஒற்றை GraphQL வினவலை எழுதுவது போல எளிமையானது. ஒரு வழக்கமான அமைப்பு இதுபோன்று இருக்கலாம்:
// அனைத்து துணை வரைபடங்களையும் பார்க்கவும்: https://thegraph.com/explorer/
const client = new ApolloClient({
uri: "{{ subgraphUrl }}",
})
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById("root")
)
இப்போது நாம் உதாரணமாக இது போன்ற ஒரு வினவலை எழுதலாம். இது நமக்குப் பின்வருவனவற்றைப் பெற்றுத்தரும்
- தற்போதைய பயனர் எத்தனை முறை வென்றுள்ளார்
- தற்போதைய பயனர் எத்தனை முறை தோற்றுள்ளார்
- அவரது முந்தைய அனைத்து பந்தயங்களுடனான நேரமுத்திரைகளின் (timestamps) பட்டியல்
அனைத்தும் GraphQL சேவையகத்திற்கான ஒரே கோரிக்கையில்.
const myGraphQlQuery = gql`
players(where: { id: $currentUser }) {
totalPlayedCount
hasWonCount
hasLostCount
bets {
time
}
}
`
const { loading, error, data } = useQuery(myGraphQlQuery)
React.useEffect(() => {
if (!loading && !error && data) {
console.log({ data })
}
}, [loading, error, data])
ஆனால் புதிரின் கடைசிப் பகுதியை நாம் தவறவிடுகிறோம், அதுதான் சேவையகம். நீங்கள் அதை நீங்களே இயக்கலாம் அல்லது வழங்கப்பட்ட சேவையைப் (hosted service) பயன்படுத்தலாம்.
The Graph சேவையகம்
Graph Explorer: வழங்கப்பட்ட சேவை
வழங்கப்பட்ட சேவையைப் பயன்படுத்துவதே எளிதான வழியாகும். துணை வரைபடத்தை நிலைநிறுத்த இங்கே (புதிய தாவலில் திறக்கப்படும்) உள்ள வழிமுறைகளைப் பின்பற்றவும். பல திட்டங்களுக்கு நீங்கள் எக்ஸ்ப்ளோரரில் (புதிய தாவலில் திறக்கப்படும்) ஏற்கனவே உள்ள துணை வரைபடங்களைக் கண்டறியலாம்.
உங்கள் சொந்த கணுவை இயக்குதல்
மாற்றாக நீங்கள் உங்கள் சொந்த கணுவை இயக்கலாம். ஆவணங்கள் இங்கே (புதிய தாவலில் திறக்கப்படும்) உள்ளன. வழங்கப்பட்ட சேவையால் ஆதரிக்கப்படாத பிணையத்தைப் பயன்படுத்துவது இதைச் செய்வதற்கான ஒரு காரணமாக இருக்கலாம். தற்போது ஆதரிக்கப்படும் பிணையங்களை இங்கே காணலாம் (புதிய தாவலில் திறக்கப்படும்).
பரவலாக்கப்பட்ட எதிர்காலம்
புதிதாக வரும் நிகழ்வுகளுக்கான ஸ்ட்ரீம்களையும் GraphQL ஆதரிக்கிறது. இவை தற்போது திறந்த பீட்டாவில் உள்ள Substreams (புதிய தாவலில் திறக்கப்படும்) மூலம் வரைபடத்தில் ஆதரிக்கப்படுகின்றன.
2021 (புதிய தாவலில் திறக்கப்படும்) இல் The Graph பரவலாக்கப்பட்ட குறியீட்டுப் பிணையமாக மாறுவதைத் தொடங்கியது. இந்தப் பரவலாக்கப்பட்ட குறியீட்டுப் பிணையத்தின் கட்டமைப்பைப் பற்றி இங்கே (புதிய தாவலில் திறக்கப்படும்) நீங்கள் மேலும் படிக்கலாம்.
இரண்டு முக்கிய அம்சங்கள்:
- பயனர்கள் வினவல்களுக்குக் குறியீட்டாளர்களுக்குப் (indexers) பணம் செலுத்துகிறார்கள்.
- குறியீட்டாளர்கள் Graph டோக்கன்களை (GRT) பங்குவைப்பு (stake) செய்கிறார்கள்.





