Vipengele vya seva na mawakala kwa programu za web3
Utangulizi
Katika hali nyingi, programu tumizi iliyogatuliwa (dapp) hutumia seva kusambaza programu, lakini mwingiliano wote halisi hufanyika kati ya kiteja (kawaida, kivinjari cha wavuti) na mnyororo wa vitalu.
Hata hivyo, kuna baadhi ya matukio ambapo programu itanufaika kwa kuwa na kipengele cha seva kinachofanya kazi kwa kujitegemea. Seva kama hiyo itaweza kujibu matukio, na maombi yanayotoka kwa vyanzo vingine, kama vile API, kwa kutoa miamala.
Kuna kazi kadhaa zinazowezekana kwa seva kama hiyo kutimiza.
-
Mshikiliaji wa hali ya siri. Katika michezo mara nyingi ni muhimu kutokuwa na taarifa zote ambazo mchezo unajua kupatikana kwa wachezaji. Hata hivyo, hakuna siri kwenye mnyororo wa vitalu, taarifa yoyote iliyo kwenye mnyororo wa vitalu ni rahisi kwa mtu yeyote kuigundua. Kwa hivyo, ikiwa sehemu ya hali ya mchezo inapaswa kuwekwa siri, inabidi ihifadhiwe mahali pengine (na ikiwezekana athari za hali hiyo zithibitishwe kwa kutumia uthibitisho wa sifuri-maarifa).
-
Orakeli iliyowekwa kati. Ikiwa hatari ni ndogo vya kutosha, seva ya nje inayosoma baadhi ya taarifa mtandaoni na kisha kuziweka kwenye mnyororo inaweza kuwa nzuri vya kutosha kutumika kama orakeli.
-
Wakala. Hakuna kinachotokea kwenye mnyororo wa vitalu bila muamala wa kuiwasha. Seva inaweza kutenda kwa niaba ya mtumiaji kufanya vitendo kama vile usuluhishi wakati fursa inapotokea.
Programu ya mfano
Unaweza kuona seva ya mfano kwenye GitHub (opens in a new tab). Seva hii inasikiliza matukio yanayotoka kwenye mkataba huu (opens in a new tab), toleo lililobadilishwa la Greeter ya Hardhat. Wakati salamu inabadilishwa, inairudisha nyuma.
Ili kuiendesha:
-
Nakili hazina.
git clone https://github.com/qbzzt/20240715-server-component.git cd 20240715-server-component -
Sakinisha vifurushi vinavyohitajika. Ikiwa huna tayari, sakinisha Node kwanza (opens in a new tab).
npm install -
Hariri
.envili kubainisha ufunguo wa siri wa akaunti ambayo ina ETH kwenye mtandao wa majaribio wa Holesky. Ikiwa huna ETH kwenye Holesky, unaweza kutumia bomba hili (opens in a new tab).PRIVATE_KEY=0x <private key goes here> -
Anzisha seva.
npm start -
Nenda kwenye kichunguzi cha bloku (opens in a new tab), na ukitumia anwani tofauti na ile iliyo na ufunguo wa siri badilisha salamu. Utaona kwamba salamu inabadilishwa kiotomatiki kurudi ilivyokuwa.
Inafanyaje kazi?
Njia rahisi ya kuelewa jinsi ya kuandika kipengele cha seva ni kupitia mfano mstari kwa mstari.
src/app.ts
Sehemu kubwa ya programu iko ndani ya src/app.ts (opens in a new tab).
Kuunda vipengee vya awali
import {
createPublicClient,
createWalletClient,
getContract,
http,
Address,
} from "viem"
Hizi ni huluki za Viem (opens in a new tab) tunazohitaji, vitendaji na aina ya Address (opens in a new tab). Seva hii imeandikwa kwa TypeScript (opens in a new tab), ambayo ni kiendelezi cha JavaScript kinachoifanya iwe na aina thabiti (opens in a new tab).
import { privateKeyToAccount } from "viem/accounts"
Kitendaji hiki (opens in a new tab) kinaturuhusu kuzalisha taarifa za mkoba, ikiwa ni pamoja na anwani, inayolingana na ufunguo wa siri.
import { holesky } from "viem/chains"
Ili kutumia mnyororo wa vitalu katika Viem unahitaji kuingiza ufafanuzi wake. Katika kesi hii, tunataka kuunganisha kwenye mnyororo wa vitalu wa majaribio wa Holesky (opens in a new tab).
// Hivi ndivyo tunavyoongeza fasili zilizo ndani ya .env kwenye process.env.
import * as dotenv from "dotenv"
dotenv.config()
Hivi ndivyo tunavyosoma .env kwenye mazingira. Tunaihitaji kwa ajili ya ufunguo wa siri (tazama baadaye).
const greeterAddress : Address = "0xB8f6460Dc30c44401Be26B0d6eD250873d8a50A6"
const greeterABI = [
{
"inputs": [
{
"internalType": "string",
"name": "_greeting",
"type": "string"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
.
.
.
{
"inputs": [
{
"internalType": "string",
"name": "_greeting",
"type": "string"
}
],
"name": "setGreeting",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
] as const
Ili kutumia mkataba tunahitaji anwani yake na yake. Tunatoa zote mbili hapa.
Katika JavaScript (na hivyo basi TypeScript) huwezi kugawa thamani mpya kwa konstanti, lakini unaweza kurekebisha kipengee kilichohifadhiwa ndani yake. Kwa kutumia kiambishi tamati as const tunaiambia TypeScript kwamba orodha yenyewe ni konstanti na haiwezi kubadilishwa.
const publicClient = createPublicClient({
chain: holesky,
transport: http(),
})
Unda kiteja cha umma (opens in a new tab) cha Viem. Wateja wa umma hawana ufunguo wa siri ulioambatishwa, na kwa hivyo hawawezi kutuma miamala. Wanaweza kuita vitendaji vya view (opens in a new tab), kusoma salio la akaunti, n.k.
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
Vigezo vya mazingira vinapatikana katika process.env (opens in a new tab). Hata hivyo, TypeScript ina aina thabiti. Kigezo cha mazingira kinaweza kuwa mfuatano wowote, au tupu, kwa hivyo aina ya kigezo cha mazingira ni string | undefined. Hata hivyo, ufunguo unafafanuliwa katika Viem kama 0x${string} (0x ikifuatiwa na mfuatano). Hapa tunaiambia TypeScript kwamba kigezo cha mazingira cha PRIVATE_KEY kitakuwa cha aina hiyo. Ikiwa sivyo, tutapata hitilafu ya wakati wa utekelezaji.
Kitendaji cha privateKeyToAccount (opens in a new tab) kisha hutumia ufunguo huu wa siri kuunda kipengee kamili cha akaunti.
const walletClient = createWalletClient({
account,
chain: holesky,
transport: http(),
})
Kisha, tunatumia kipengee cha akaunti kuunda kiteja cha mkoba (opens in a new tab). Kiteja hiki kina ufunguo wa siri na anwani, kwa hivyo kinaweza kutumika kutuma miamala.
const greeter = getContract({
address: greeterAddress,
abi: greeterABI,
client: { public: publicClient, wallet: walletClient },
})
Sasa kwa kuwa tuna mahitaji yote ya awali, hatimaye tunaweza kuunda mfano wa mkataba (opens in a new tab). Tutatumia mfano huu wa mkataba kuwasiliana na mkataba ulio mnyororoni.
Kusoma kutoka kwenye mnyororo wa vitalu
console.log(`Current greeting:`, await greeter.read.greet())
Vitendaji vya mkataba ambavyo ni vya kusoma tu (view (opens in a new tab) na pure (opens in a new tab)) vinapatikana chini ya read. Katika kesi hii, tunaitumia kufikia kitendaji cha greet (opens in a new tab), ambacho kinarudisha salamu.
JavaScript ina uzi mmoja, kwa hivyo tunapoanzisha mchakato unaoendelea kwa muda mrefu tunahitaji kubainisha kuwa tunaifanya kwa njia isiyosawazishwa (opens in a new tab). Kuita mnyororo wa vitalu, hata kwa operesheni ya kusoma tu, kunahitaji safari ya kwenda na kurudi kati ya kompyuta na nodi ya mnyororo wa vitalu. Hiyo ndiyo sababu tunabainisha hapa kwamba msimbo unahitaji await kwa matokeo.
Ikiwa una nia ya kujua jinsi hii inavyofanya kazi unaweza kusoma kuihusu hapa (opens in a new tab), lakini kwa vitendo unachohitaji kujua ni kwamba una-await matokeo ikiwa utaanzisha operesheni inayochukua muda mrefu, na kwamba kitendaji chochote kinachofanya hivi lazima kitangazwe kama async.
Kutoa miamala
const setGreeting = async (greeting: string): Promise<any> => {
Hiki ni kitendaji unachokiita ili kutoa muamala unaobadilisha salamu. Kwa kuwa hii ni operesheni ndefu, kitendaji kinatangazwa kama async. Kwa sababu ya utekelezaji wa ndani, kitendaji chochote cha async kinahitaji kurudisha kipengee cha Promise. Katika kesi hii, Promise<any> inamaanisha kuwa hatubainishi ni nini hasa kitarudishwa katika Promise.
const txHash = await greeter.write.setGreeting([greeting])
Sehemu ya write ya mfano wa mkataba ina vitendaji vyote vinavyoandika kwenye hali ya mnyororo wa vitalu (vile vinavyohitaji kutuma muamala), kama vile setGreeting (opens in a new tab). Vigezo, ikiwa vipo, hutolewa kama orodha, na kitendaji kinarudisha heshi ya muamala.
console.log(`Working on a fix, see https://eth-holesky.blockscout.com/tx/${txHash}`)
return txHash
}
Ripoti heshi ya muamala (kama sehemu ya URL kwa kichunguzi cha bloku ili kuitazama) na uirudishe.
Kujibu matukio
greeter.watchEvent.SetGreeting({
Kitendaji cha watchEvent (opens in a new tab) kinakuruhusu kubainisha kuwa kitendaji kitaendeshwa wakati tukio linapotolewa. Ikiwa unajali tu kuhusu aina moja ya tukio (katika kesi hii, SetGreeting), unaweza kutumia sintaksia hii kujiwekea kikomo kwa aina hiyo ya tukio.
onLogs: logs => {
Kitendaji cha onLogs kinaitwa wakati kuna maingizo ya logi. Katika Ethereum "logi" na "tukio" kwa kawaida hutumika kwa kubadilishana.
console.log(
`Address ${logs[0].args.sender} changed the greeting to ${logs[0].args.greeting}`
)
Kunaweza kuwa na matukio mengi, lakini kwa urahisi tunajali tu lile la kwanza. logs[0].args ni hoja za tukio, katika kesi hii sender na greeting.
if (logs[0].args.sender != account.address)
setGreeting(`${account.address} insists on it being Hello!`)
}
})
Ikiwa mtumaji sio seva hii, tumia setGreeting kubadilisha salamu.
package.json
Faili hili (opens in a new tab) linadhibiti usanidi wa Node.js (opens in a new tab). Makala haya yanaelezea tu ufafanuzi muhimu.
{
"main": "dist/index.js",
Ufafanuzi huu unabainisha ni faili gani la JavaScript la kuendesha.
"scripts": {
"start": "tsc && node dist/app.js",
},
Hati ni vitendo mbalimbali vya programu. Katika kesi hii, pekee tuliyo nayo ni start, ambayo inakusanya na kisha kuendesha seva. Amri ya tsc ni sehemu ya kifurushi cha typescript na inakusanya TypeScript kuwa JavaScript. Ikiwa unataka kuiendesha wewe mwenyewe, inapatikana katika node_modules/.bin. Amri ya pili inaendesha seva.
"type": "module",
Kuna aina nyingi za programu za nodi za JavaScript. Aina ya module inaturuhusu kuwa na await katika msimbo wa kiwango cha juu, ambayo ni muhimu unapofanya operesheni za polepole (na kwa hivyo zisizosawazishwa).
"devDependencies": {
"@types/node": "^20.14.2",
"typescript": "^5.4.5"
},
Hivi ni vifurushi ambavyo vinahitajika tu kwa maendeleo. Hapa tunahitaji typescript na kwa sababu tunaitumia na Node.js, tunapata pia aina za vigezo na vipengee vya nodi, kama vile process. Nukuu ya ^<version> (opens in a new tab) inamaanisha toleo hilo au toleo la juu zaidi ambalo halina mabadiliko yanayovunja. Tazama hapa (opens in a new tab) kwa taarifa zaidi kuhusu maana ya nambari za matoleo.
"dependencies": {
"dotenv": "^16.4.5",
"viem": "2.14.1"
}
}
Hivi ni vifurushi vinavyohitajika wakati wa utekelezaji, wakati wa kuendesha dist/app.js.
Hitimisho
Seva iliyowekwa kati tuliyounda hapa inafanya kazi yake, ambayo ni kutenda kama wakala kwa mtumiaji. Mtu mwingine yeyote anayetaka dapp iendelee kufanya kazi na yuko tayari kutumia gesi anaweza kuendesha mfano mpya wa seva na anwani yake mwenyewe.
Hata hivyo, hii inafanya kazi tu wakati vitendo vya seva iliyowekwa kati vinaweza kuthibitishwa kwa urahisi. Ikiwa seva iliyowekwa kati ina taarifa yoyote ya hali ya siri, au inaendesha hesabu ngumu, ni huluki iliyowekwa kati ambayo unahitaji kuiamini ili kutumia programu, ambayo ndiyo hasa minyororo ya vitalu inajaribu kuepuka. Katika makala yajayo ninapanga kuonyesha jinsi ya kutumia uthibitisho wa sifuri-maarifa ili kutatua tatizo hili.