ProHoster > Blog > Ma'muriyat > Telegram Open Network-da aqlli shartnomani qanday yozish va nashr etish haqida (TON)
Telegram Open Network-da aqlli shartnomani qanday yozish va nashr etish haqida (TON)
TONda aqlli shartnomani qanday yozish va nashr qilish haqida
Ushbu maqola nima haqida?
Maqolada men Telegram blokcheynidagi birinchi (ikkitadan) tanlovida qanday ishtirok etganim, sovrin olmaganim va tajribam unutilib ketmasligi va, ehtimol, yordam berishi uchun maqolada yozib olishga qaror qilganim haqida gapiraman. kimdir.
Men mavhum kod yozishni emas, balki biron bir ish bilan shug'ullanishni istamaganim uchun, maqola uchun men lahzali lotereya uchun aqlli shartnoma va oraliq xotiradan foydalanmasdan to'g'ridan-to'g'ri TON-dan aqlli shartnoma ma'lumotlarini ko'rsatadigan veb-sayt yozdim.
Maqola TONda birinchi aqlli shartnomasini tuzmoqchi bo'lganlar uchun foydali bo'ladi, lekin qaerdan boshlashni bilmaydi.
Lotereyani misol sifatida ishlatib, men muhitni o'rnatishdan aqlli shartnomani nashr qilish, u bilan o'zaro aloqa qilish va ma'lumotlarni qabul qilish va nashr etish uchun veb-sayt yozishga o'taman.
Tanlovda ishtirok etish haqida
Oβtgan yilning oktyabr oyida Telegram yangi tillar bilan blokcheyn tanlovini eβlon qildi Fift ΠΈ FunC. Taklif etilgan beshta aqlli shartnomadan birini yozishni tanlash kerak edi. Kelajakda boshqa hech narsa yozish shart boβlmasa ham, boshqacha ish qilsam, til oβrgansam, nimadir qilsam yaxshi boβlardi, deb oβyladim. Bundan tashqari, mavzu doimo labda.
Aytishim kerakki, men aqlli shartnomalarni ishlab chiqishda tajribam yo'q edi.
Men imkon qadar oxirigacha qatnashishni va keyin sharh maqola yozishni rejalashtirgandim, lekin birinchisida darhol muvaffaqiyatsizlikka uchraganman. I hamyon yozgan ko'p imzo yoqilgan FunC va u umuman ishladi. Men buni asos qilib oldim Solidity bo'yicha aqlli shartnoma.
O'shanda men bu hech bo'lmaganda sovrinli o'rinni egallash uchun yetarli, deb o'ylardim. Natijada 40 nafar ishtirokchidan 60 nafarga yaqini sovrindor boβldi va men ular orasida yoβq edim. Umuman olganda, buning hech qanday yomon joyi yo'q, lekin meni bir narsa bezovta qildi. Natijalar e'lon qilingan paytda, mening shartnomam bo'yicha testni ko'rib chiqish o'tkazilmagan edi, men suhbat ishtirokchilaridan boshqa hech kim yo'qligini so'radim, yo'q edi.
Mening xabarlarimga e'tibor bergan shekilli, ikki kundan keyin hakamlar izoh e'lon qilishdi va men hali ham tushunmayapman, ular hakamlik paytida tasodifan mening aqlli shartnomamni o'tkazib yubordilarmi yoki shunchaki buni juda yomon deb o'ylashdimi, izohga muhtoj emasman. Men sahifada savol berdim, lekin javob olmadim. Kim hukm qilgani sir bo'lmasa-da, shaxsiy xabarlar yozishni keraksiz deb bildim.
Tushunishga ko'p vaqt sarflandi, shuning uchun maqola yozishga qaror qilindi. Hali ko'p ma'lumot yo'qligi sababli, ushbu maqola qiziqqan har bir kishi uchun vaqtni tejashga yordam beradi.
TONdagi aqlli shartnomalar kontseptsiyasi
Biror narsa yozishdan oldin, bu narsaga qaysi tomondan yondashish kerakligini aniqlab olishingiz kerak. Shuning uchun, endi men sizga tizim qanday qismlardan iboratligini aytib beraman. Aniqrog'i, hech bo'lmaganda qandaydir mehnat shartnomasini yozish uchun qanday qismlarni bilishingiz kerak.
Biz aqlli shartnoma yozish va u bilan ishlashga e'tibor qaratamiz TON Virtual Machine (TVM), Fift ΠΈ FunC, shuning uchun maqola ko'proq muntazam dasturni ishlab chiqish tavsifiga o'xshaydi. Biz bu erda platformaning o'zi qanday ishlashi haqida to'xtalmaymiz.
Umuman olganda, u qanday ishlashi haqida TVM va til Fift yaxshi rasmiy hujjatlar mavjud. Tanlovda qatnashayotganimda va hozirgi shartnomani yozishda men unga tez-tez murojaat qilardim.
Aqlli shartnomalar yoziladigan asosiy til FunC. Hozirda bu borada hech qanday hujjat yo'q, shuning uchun biror narsa yozish uchun siz rasmiy ombordan aqlli shartnomalar misollarini va u erda tilning o'zini amalga oshirishni o'rganishingiz kerak, shuningdek, so'nggi ikki yildagi aqlli shartnomalar misollarini ko'rishingiz mumkin. musobaqalar. Maqolaning oxiridagi havolalar.
Aytaylik, biz allaqachon aqlli shartnoma yozdik FunC, shundan so'ng biz kodni Fift assemblerga kompilyatsiya qilamiz.
Tuzilgan aqlli shartnoma hali ham nashr etilishi kerak. Buni amalga oshirish uchun siz funktsiyani yozishingiz kerak Fift, kirish sifatida aqlli shartnoma kodini va boshqa parametrlarni oladi va chiqish kengaytmali fayl bo'ladi. .boc (bu "hujayralar sumkasi" degan ma'noni anglatadi) va uni qanday yozishimizga qarab, aqlli shartnoma kodi asosida yaratilgan shaxsiy kalit va manzil. Siz allaqachon e'lon qilinmagan aqlli shartnoma manziliga gramm yuborishingiz mumkin.
TONda aqlli shartnomani nashr qilish uchun qabul qilindi .boc faylni blokcheynga engil mijoz yordamida yuborish kerak bo'ladi (quyida batafsilroq). Ammo nashr etishdan oldin siz grammlarni yaratilgan manzilga o'tkazishingiz kerak, aks holda aqlli shartnoma nashr etilmaydi. Nashr etilgandan so'ng, siz aqlli shartnoma bilan tashqi tomondan (masalan, engil mijoz yordamida) yoki ichkaridan xabarlar yuborish orqali o'zaro aloqada bo'lishingiz mumkin (masalan, bitta aqlli shartnoma boshqasiga TON ichida xabar yuboradi).
Kod qanday chop etilishini tushunganimizdan so'ng, bu osonroq bo'ladi. Biz taxminan nima yozmoqchi ekanligimizni va dasturimiz qanday ishlashini bilamiz. Yozish paytida biz bu mavjud aqlli shartnomalarda qanday amalga oshirilganligini qidiramiz yoki amalga oshirish kodini ko'rib chiqamiz Fift ΠΈ FunC rasmiy omborda yoki rasmiy hujjatlarga qarang.
Men tez-tez barcha tanlov ishtirokchilari va Telegram xodimlari to'plangan Telegram chatida kalit so'zlarni qidirardim va shunday bo'ldiki, musobaqa davomida hamma u erga yig'ilib, Fift va FunCni muhokama qila boshladi. Maqolaning oxiridagi havola.
Nazariyadan amaliyotga o'tish vaqti keldi.
TON bilan ishlash uchun muhitni tayyorlash
Men MacOS-dagi maqolada tasvirlangan hamma narsani qildim va uni Docker-dagi toza Ubuntu 18.04 LTS da ikki marta tekshirdim.
Siz qilishingiz kerak bo'lgan birinchi narsa - yuklab olish va o'rnatish lite-client uning yordamida siz TONga so'rov yuborishingiz mumkin.
Rasmiy veb-saytdagi ko'rsatmalar o'rnatish jarayonini juda batafsil va aniq tasvirlab beradi va ba'zi tafsilotlarni o'tkazib yuboradi. Bu erda biz ko'rsatmalarga amal qilamiz, yo'l davomida etishmayotgan bog'liqliklarni o'rnatamiz. Men har bir loyihani o'zim kompilyatsiya qilmadim va rasmiy Ubuntu omboridan o'rnatmadim (men MacOS da ishlatganman brew).
Barcha bog'liqliklar o'rnatilgandan so'ng siz o'rnatishingiz mumkin lite-client, Fift, FunC.
Birinchidan, biz TON omborini uning bog'liqliklari bilan birga klonlaymiz. Qulaylik uchun biz hamma narsani papkada qilamiz ~/TON.
cd ~/TON
git clone https://github.com/ton-blockchain/ton.git
cd ./ton
git submodule update --init --recursive
Repository shuningdek, ilovalarni saqlaydi Fift ΠΈ FunC.
Endi biz loyihani yig'ishga tayyormiz. Ombor kodi papkaga klonlanadi ~/TON/ton. The ~/TON papka yarating build va unda loyihani to'plang.
mkdir ~/TON/build
cd ~/TON/build
cmake ../ton
Biz aqlli shartnoma yozmoqchi bo'lganimiz uchun, biz nafaqat kerak lite-clientlekin Fift Ρ FunC, shuning uchun hamma narsani kompilyatsiya qilaylik. Bu tez jarayon emas, shuning uchun biz kutamiz.
cd ~/TON/build
./lite-client/lite-client -C ton-lite-client-test1.config.json
Agar qurish muvaffaqiyatli bo'lsa, ishga tushirilgandan so'ng siz yorug'lik mijozining tugunga ulanishi jurnalini ko'rasiz.
[ 1][t 2][1582054822.963129282][lite-client.h:201][!testnode] conn ready
[ 2][t 2][1582054823.085654020][lite-client.cpp:277][!testnode] server version is 1.1, capabilities 7
[ 3][t 2][1582054823.085725069][lite-client.cpp:286][!testnode] server time is 1582054823 (delta 0)
...
Siz buyruqni bajarishingiz mumkin help va qanday buyruqlar mavjudligini ko'ring.
help
Keling, ushbu maqolada foydalanadigan buyruqlarni sanab o'tamiz.
list of available commands:
last Get last block and state info from server
sendfile <filename> Load a serialized message from <filename> and send it to server
getaccount <addr> [<block-id-ext>] Loads the most recent state of specified account; <addr> is in [<workchain>:]<hex-or-base64-addr> format
runmethod <addr> [<block-id-ext>] <method-id> <params>... Runs GET method <method-id> of account <addr> with specified parameters
Yuqorida yozganimdek, biz yozayotgan aqlli shartnoma lotereyadir.
Bundan tashqari, bu siz chipta sotib olishingiz va bir soat, kun yoki oy kutishingiz kerak bo'lgan lotereya emas, balki foydalanuvchi shartnoma manziliga o'tkazadigan lahzali lotereyadir. N gramm va uni darhol qaytarib oladi 2 * N gramm yoki yo'qotadi. Biz g'alaba qozonish ehtimolini taxminan 40% qilamiz. Agar to'lov uchun gramm etarli bo'lmasa, biz tranzaktsiyani to'ldirish sifatida ko'rib chiqamiz.
Bundan tashqari, garovlarni real vaqt rejimida va qulay shaklda ko'rish mumkin bo'lishi muhim, shunda foydalanuvchi o'zining yutgan yoki yutqazganligini darhol tushunishi mumkin. Shuning uchun, siz tikish va natijalarni to'g'ridan-to'g'ri TONdan ko'rsatadigan veb-sayt qilishingiz kerak.
Aqlli shartnoma yozish
Qulaylik uchun men FunC kodini ajratib ko'rsatdim; plaginni Visual Studio Code qidiruvida topish va o'rnatish mumkin; agar siz to'satdan biror narsa qo'shmoqchi bo'lsangiz, men plaginni hamma uchun ochiq qildim. Bundan tashqari, kimdir ilgari Fift bilan ishlash uchun plagin yaratgan, siz uni o'rnatishingiz va VSC-da topishingiz mumkin.
Keling, darhol oraliq natijalarni beradigan omborni yarataylik.
Hayotimizni osonlashtirish uchun biz aqlli shartnoma yozamiz va tayyor bo'lgunga qadar uni mahalliy sinovdan o'tkazamiz. Shundan keyingina biz uni TONda nashr qilamiz.
Aqlli kontraktda kirish mumkin bo'lgan ikkita tashqi usul mavjud. Birinchidan, recv_external() bu funksiya shartnomaga so'rov tashqi dunyodan kelganda, ya'ni TONdan emas, masalan, biz o'zimiz xabar ishlab chiqarganimizda va uni lite-mijoz orqali jo'natganimizda bajariladi. Ikkinchi, recv_internal() Bu, TONning o'zida, har qanday shartnoma biznikiga tegishli. Ikkala holatda ham siz funksiyaga parametrlarni o'tkazishingiz mumkin.
Keling, oddiy misol bilan boshlaylik, agar nashr etilsa ishlaydi, lekin unda funktsional yuk yo'q.
Bu erda biz nima ekanligini tushuntirishimiz kerak slice. TON Blockchain-da saqlangan barcha ma'lumotlar to'plamdir TVM cell yoki oddiygina cell, bunday katakda siz 1023 bitgacha ma'lumotni va boshqa hujayralarga 4 tagacha havolani saqlashingiz mumkin.
TVM cell slice yoki slice bu mavjud qismning bir qismi cell uni tahlil qilish uchun ishlatiladi, keyinroq aniq bo'ladi. Biz uchun asosiysi transfer qilishimiz mumkin slice va xabar turiga qarab, ma'lumotlarni qayta ishlang recv_external() yoki recv_internal().
impure β funksiya aqlli shartnoma maΚΌlumotlarini oΚ»zgartirishini bildiruvchi kalit soΚ»z.
Keling, shartnoma kodini saqlaymiz lottery-code.fc va kompilyatsiya qilish.
Bayroqlarning ma'nosini buyruq yordamida ko'rish mumkin
~/TON/build/crypto/func -help
Biz Fift assembler kodini tuzdik lottery-compiled.fif:
// lottery-compiled.fif
"Asm.fif" include
// automatically generated from `/Users/rajymbekkapisev/TON/ton/crypto/smartcont/stdlib.fc` `./lottery-code.fc`
PROGRAM{
DECLPROC recv_internal
DECLPROC recv_external
recv_internal PROC:<{
// in_msg
DROP //
}>
recv_external PROC:<{
// in_msg
DROP //
}>
}END>c
Uni mahalliy darajada ishga tushirish mumkin, buning uchun biz muhitni tayyorlaymiz.
E'tibor bering, birinchi qator ulanadi Asm.fif, bu Fift assembler uchun Fiftda yozilgan kod.
Biz aqlli shartnomani mahalliy sifatida ishga tushirish va sinab ko'rishni xohlayotganimiz sababli, biz fayl yaratamiz lottery-test-suite.fif va tuzilgan kodni u erda nusxa ko'chiring, undagi oxirgi qatorni almashtiring, bu aqlli shartnoma kodini doimiyga yozadi. codekeyin uni virtual mashinaga o'tkazish uchun:
"TonUtil.fif" include
"Asm.fif" include
PROGRAM{
DECLPROC recv_internal
DECLPROC recv_external
recv_internal PROC:<{
// in_msg
DROP //
}>
recv_external PROC:<{
// in_msg
DROP //
}>
}END>s constant code
Hozircha bu aniq ko'rinadi, endi TVMni ishga tushirish uchun foydalanadigan kodni o'sha faylga qo'shamiz.
Π c7 biz kontekstni, ya'ni TVM (yoki tarmoq holati) ishga tushiriladigan ma'lumotlarni yozamiz. Hatto tanlov davomida ishlab chiquvchilardan biri qanday yaratishni ko'rsatdi c7 va men nusxa ko'chirdim. Ushbu maqolada biz o'zgartirishimiz kerak bo'lishi mumkin rand_seed chunki tasodifiy sonni yaratish unga bog'liq va agar o'zgartirilmasa, har safar bir xil raqam qaytariladi.
recv_internal ΠΈ recv_external 0 va -1 qiymatlari bo'lgan konstantalar aqlli shartnomada mos keladigan funktsiyalarni chaqirish uchun javobgar bo'ladi.
Endi biz bo'sh aqlli shartnomamiz uchun birinchi testni yaratishga tayyormiz. Aniqlik uchun hozircha biz barcha testlarni bitta faylga qo'shamiz lottery-test-suite.fif.
Keling, o'zgaruvchini yarataylik storage va unga bo'sh birini yozing cell, bu aqlli kontrakt xotirasi bo'ladi.
message bu tashqi tomondan aqlli kontaktga uzatadigan xabar. Biz uni hozircha bo'sh qilamiz.
Konstantalar va o'zgaruvchilarni tayyorlaganimizdan so'ng, biz buyruq yordamida TVM ni ishga tushiramiz runvmctx va yaratilgan parametrlarni kiritishga o'tkazing.
Ajoyib, biz aqlli shartnomaning birinchi ishchi versiyasini yozdik.
Endi biz funksionallikni qo'shishimiz kerak. Avval tashqi dunyodan kelgan xabarlar bilan shug'ullanamiz recv_external()
Ishlab chiquvchining o'zi shartnoma qabul qilishi mumkin bo'lgan xabar formatini tanlaydi.
Lekin odatda
birinchidan, biz shartnomamizni tashqi dunyodan himoya qilmoqchimiz va uni faqat shartnoma egasi unga tashqi xabarlarni yuborishi mumkin bo'lgan qilib yaratmoqchimiz.
ikkinchidan, biz TON ga to'g'ri xabar yuborganimizda, biz buni aynan bir marta sodir bo'lishini istaymiz va biz yana bir xil xabarni yuborganimizda, aqlli shartnoma uni rad etadi.
Shunday qilib, deyarli har bir shartnoma bu ikki muammoni hal qiladi, chunki bizning shartnomamiz tashqi xabarlarni qabul qiladi, biz bu haqda ham g'amxo'rlik qilishimiz kerak.
Biz buni teskari tartibda qilamiz. Birinchidan, muammoni takrorlash bilan hal qilaylik, agar shartnoma allaqachon bunday xabarni olgan va uni qayta ishlagan bo'lsa, u ikkinchi marta bajarmaydi. Va keyin biz muammoni faqat ma'lum bir odamlar doirasi aqlli shartnomaga xabar yuborishi uchun hal qilamiz.
Ikki nusxadagi xabarlar bilan muammoni hal qilishning turli usullari mavjud. Buni qanday qilamiz. Aqlli shartnomada biz qabul qilingan xabarlar hisoblagichini boshlang'ich qiymati 0 bilan ishga tushiramiz. Aqlli shartnomaga har bir xabarda joriy hisoblagich qiymatini qo'shamiz. Agar xabardagi hisoblagich qiymati aqlli shartnomadagi qiymatga mos kelmasa, biz uni qayta ishlamaymiz, agar shunday bo'lsa, biz uni qayta ishlaymiz va aqlli kontraktdagi hisoblagichni 1 ga oshiramiz.
ga qaytaylik lottery-test-suite.fif va unga ikkinchi test qo'shing. Agar biz noto'g'ri raqam yuborsak, kod istisno qilishi kerak. Masalan, shartnoma ma'lumotlari 166 ni saqlasin, biz esa 165 ni yuboramiz.
<b 166 32 u, b> storage !
<b 165 32 u, b> message !
message @
recv_external
code
storage @
c7
runvmctx
drop
exit_code !
."Exit code " exit_code @ . cr
exit_code @ 33 - abort"Test #2 Not passed"
Keling, ishga tushamiz.
~/TON/build/crypto/fift -s lottery-test-suite.fif
Va test xato bilan bajarilganligini ko'ramiz.
[ 1][t 0][1582283084.210902214][words.cpp:3046] lottery-test-suite.fif:67: abort": Test #2 Not passed
[ 1][t 0][1582283084.210941076][fift-main.cpp:196] Error interpreting file `lottery-test-suite.fif`: error interpreting included file `lottery-test-suite.fif` : lottery-test-suite.fif:67: abort": Test #2 Not passed
Bu bosqichda lottery-test-suite.fif kabi ko'rinishi kerak aloqa.
Endi aqlli kontraktga qarshi mantiqni qo'shamiz lottery-code.fc.
() recv_internal(slice in_msg) impure {
;; TODO: implementation
}
() recv_external(slice in_msg) impure {
if (slice_empty?(in_msg)) {
return ();
}
int msg_seqno = in_msg~load_uint(32);
var ds = begin_parse(get_data());
int stored_seqno = ds~load_uint(32);
throw_unless(33, msg_seqno == stored_seqno);
}
Π slice in_msg biz yuborgan xabar yotadi.
Biz qiladigan birinchi narsa - xabarda ma'lumotlar mavjudligini tekshirish, agar bo'lmasa, biz shunchaki chiqamiz.
Keyin biz xabarni tahlil qilamiz. in_msg~load_uint(32) 165, 32 bitli raqamni yuklaydi unsigned int uzatilgan xabardan.
Keyinchalik biz aqlli kontrakt xotirasidan 32 bitni yuklaymiz. Yuklangan raqam o'tgan raqamga mos kelishini tekshiramiz, agar bo'lmasa, biz istisno qilamiz. Bizning holatda, biz o'yindan tashqari o'tayotganimiz sababli, istisno qilish kerak.
Olingan koddan nusxa oling lottery-test-suite.fif, oxirgi qatorni almashtirishni unutmang.
Sinovdan o'tganligini tekshiramiz:
~/TON/build/crypto/fift -s lottery-test-suite.fif
Bu erda Joriy natijalar bilan tegishli majburiyatni ko'rishingiz mumkin.
E'tibor bering, aqlli shartnomaning tuzilgan kodini doimiy ravishda sinovlar bilan faylga nusxalash noqulay, shuning uchun biz kodni o'zimiz uchun doimiyga yozadigan skript yozamiz va biz kompilyatsiya qilingan kodni oddiygina testlarimizga ulaymiz. "include".
Loyiha papkasida fayl yarating build.sh quyidagi tarkib bilan.
Endi shartnomani tuzish uchun skriptimizni ishga tushiring. Ammo bundan tashqari, biz uni doimiyga yozishimiz kerak code. Shunday qilib, biz yangi fayl yaratamiz lotter-compiled-for-test.fif, biz faylga kiritamiz lottery-test-suite.fif.
Keling, sh ga skript kodini qo'shamiz, bu shunchaki kompilyatsiya qilingan faylni takrorlaydi lotter-compiled-for-test.fif va undagi oxirgi qatorni o'zgartiring.
# copy and change for test
cp lottery-compiled.fif lottery-compiled-for-test.fif
sed '$d' lottery-compiled-for-test.fif > test.fif
rm lottery-compiled-for-test.fif
mv test.fif lottery-compiled-for-test.fif
echo -n "}END>s constant code" >> lottery-compiled-for-test.fif
Endi tekshirish uchun natijada olingan skriptni ishga tushiramiz va fayl yaratiladi lottery-compiled-for-test.fif, biz buni o'zimizga kiritamiz lottery-test-suite.fif
Π lottery-test-suite.fif shartnoma kodini o'chiring va qatorni qo'shing "lottery-compiled-for-test.fif" include.
Biz ularning muvaffaqiyatli ekanligini tekshirish uchun testlarni o'tkazamiz.
~/TON/build/crypto/fift -s lottery-test-suite.fif
Ajoyib, endi testlarni ishga tushirishni avtomatlashtirish uchun fayl yarataylik test.sh, bu birinchi navbatda amalga oshiriladi build.sh, va keyin testlarni bajaring.
Keling buni bajaramiz test.sh va testlar ishlayotganiga ishonch hosil qilish uchun uni ishga tushiring.
chmod +x ./test.sh
./test.sh
Biz shartnoma tuzilganligini va sinovlar o'tkazilganligini tekshiramiz.
Ajoyib, endi ishga tushirildi test.sh Testlar darhol tuziladi va o'tkaziladi. Mana havola topshirmoq.
Mayli, davom etishdan oldin, qulaylik uchun yana bir narsani qilaylik.
Keling, papka yarataylik build bu erda biz ko'chirilgan kontraktni va uning doimiyga yozilgan klonini saqlaymiz lottery-compiled.fif, lottery-compiled-for-test.fif. Keling, papkani ham yarataylik test test fayli qayerda saqlanadi? lottery-test-suite.fif va potentsial boshqa qo'llab-quvvatlovchi fayllar. Tegishli o'zgarishlarga havola.
Keling, aqlli shartnomani ishlab chiqishda davom etaylik.
Keyinchalik, biz to'g'ri raqamni yuborganimizda, xabar qabul qilinganligini va hisoblagich do'konda yangilanganligini tekshiradigan test bo'lishi kerak. Lekin buni keyinroq qilamiz.
Keling, aqlli shartnomada qanday ma'lumotlar tuzilishi va qanday ma'lumotlarni saqlash kerakligini o'ylab ko'raylik.
Keyin ikkita funktsiyani yozishingiz kerak. Birinchisiga qo'ng'iroq qilaylik pack_state(), bu keyinchalik aqlli kontrakt xotirasida saqlash uchun ma'lumotlarni to'playdi. Keling, ikkinchisiga qo'ng'iroq qilaylik unpack_state() xotiradan ma'lumotlarni o'qiydi va qaytaradi.
_ pack_state(int seqno, int pubkey, int order_seqno, int number_of_wins, int incoming_amount, int outgoing_amount, int owner_wc, int owner_account_id, cell orders) inline_ref {
return begin_cell()
.store_uint(seqno, 32)
.store_uint(pubkey, 256)
.store_uint(order_seqno, 32)
.store_uint(number_of_wins, 32)
.store_grams(incoming_amount)
.store_grams(outgoing_amount)
.store_int(owner_wc, 32)
.store_uint(owner_account_id, 256)
.store_dict(orders)
.end_cell();
}
_ unpack_state() inline_ref {
var ds = begin_parse(get_data());
var unpacked = (ds~load_uint(32), ds~load_uint(256), ds~load_uint(32), ds~load_uint(32), ds~load_grams(), ds~load_grams(), ds~load_int(32), ds~load_uint(256), ds~load_dict());
ds.end_parse();
return unpacked;
}
Biz ushbu ikkita funktsiyani aqlli shartnomaning boshiga qo'shamiz. Bu amalga oshadi bu oraliq natija.
Ma'lumotlarni saqlash uchun siz o'rnatilgan funksiyani chaqirishingiz kerak bo'ladi set_data() va u ma'lumotlarni yozadi pack_state() aqlli kontrakt xotirasida.
Endi bizda ma'lumotlarni yozish va o'qish uchun qulay funktsiyalar mavjud, biz davom etishimiz mumkin.
Biz tashqaridan kelgan xabarni shartnoma egasi (yoki shaxsiy kalitga kirish huquqiga ega bo'lgan boshqa foydalanuvchi) imzolaganligini tekshirishimiz kerak.
Biz aqlli shartnomani nashr qilganimizda, biz uni saqlashda kerak bo'lgan ma'lumotlar bilan ishga tushirishimiz mumkin, ular kelajakda foydalanish uchun saqlanadi. Kiruvchi xabar tegishli shaxsiy kalit bilan imzolanganligini tekshirishimiz uchun biz u yerda ochiq kalitni yozib olamiz.
Davom etishdan oldin shaxsiy kalit yaratamiz va uni yozamiz test/keys/owner.pk. Buning uchun interaktiv rejimda Fiftni ishga tushiramiz va to'rtta buyruqni bajaramiz.
Keling, papka yarataylik keys papka ichida test va u erda shaxsiy kalitni yozing.
mkdir test/keys
cd test/keys
~/TON/build/crypto/fift -i
newkeypair
ok
.s
BYTES:128DB222CEB6CF5722021C3F21D4DF391CE6D5F70C874097E28D06FCE9FD6917 BYTES:DD0A81AAF5C07AAAA0C7772BB274E494E93BB0123AA1B29ECE7D42AE45184128
drop
ok
"owner.pk" B>file
ok
bye
Biz joriy papkada faylni ko'ramiz owner.pk.
Biz ochiq kalitni stekdan olib tashlaymiz va kerak bo'lganda uni shaxsiy kalitdan olishimiz mumkin.
Endi biz imzo tekshiruvini yozishimiz kerak. Sinovdan boshlaylik. Avval biz funktsiyadan foydalanib fayldan shaxsiy kalitni o'qiymiz file>B va uni o'zgaruvchiga yozing owner_private_key, keyin funksiyadan foydalaning priv>pub shaxsiy kalitni umumiy kalitga aylantiring va natijani yozing owner_public_key.
Biz aqlli kontrakt xotirasini funktsiyadagi kabi ketma-ketlikda o'zboshimchalik bilan ma'lumotlar bilan ishga tushiramiz pack_state()va uni o'zgaruvchiga yozing storage.
Natijada, biz aqlli shartnomaga yuboradigan xabar o'zgaruvchida qayd etiladi message_to_send, funksiyalar haqida hashu, ed25519_sign_uint o'qishingiz mumkin Fift hujjatlarida.
Va testni o'tkazish uchun biz yana qo'ng'iroq qilamiz.
Mana bunday Sinovlar bilan fayl ushbu bosqichda shunday ko'rinishi kerak.
Keling, sinovni o'tkazamiz va u muvaffaqiyatsiz bo'ladi, shuning uchun biz aqlli shartnomani ushbu formatdagi xabarlarni qabul qilishi va imzoni tekshirishi uchun o'zgartiramiz.
Birinchidan, biz xabardan imzoning 512 bitini hisoblaymiz va uni o'zgaruvchiga yozamiz, keyin hisoblagich o'zgaruvchining 32 bitini hisoblaymiz.
Bizda aqlli kontrakt xotirasidan ma'lumotlarni o'qish funktsiyasi mavjud bo'lgani uchun biz undan foydalanamiz.
Keyingi - saqlash bilan uzatilgan hisoblagichni tekshirish va imzoni tekshirish. Agar biror narsa mos kelmasa, biz tegishli kod bilan istisno qilamiz.
var signature = in_msg~load_bits(512);
var message = in_msg;
int msg_seqno = message~load_uint(32);
(int stored_seqno, int pubkey, int order_seqno, int number_of_wins, int incoming_amount, int outgoing_amount, int owner_wc, int owner_account_id, cell orders) = unpack_state();
throw_unless(33, msg_seqno == stored_seqno);
throw_unless(34, check_signature(slice_hash(in_msg), signature, pubkey));
Keling, testlarni o'tkazamiz va ikkinchi sinov muvaffaqiyatsiz ekanligini ko'ramiz. Ikkita sababga ko'ra, xabarda bitlar etarli emas va xotirada etarli bitlar mavjud emas, shuning uchun kod tahlil qilishda ishlamay qoladi. Biz yuborayotgan xabarga imzo qo'shishimiz va oxirgi sinovdan saqlashni nusxalashimiz kerak.
Ikkinchi testda biz xabar imzosini qo'shamiz va aqlli kontrakt xotirasini o'zgartiramiz. Mana bunday sinovlari bo'lgan fayl hozirgidek ko'rinadi.
Keling, to'rtinchi testni yozaylik, unda biz boshqa birovning shaxsiy kaliti bilan imzolangan xabarni yuboramiz. Keling, boshqa shaxsiy kalit yaratamiz va uni faylga saqlaymiz not-owner.pk. Biz ushbu shaxsiy kalit bilan xabarni imzolaymiz. Keling, testlarni o'tkazamiz va barcha testlar o'tganiga ishonch hosil qilamiz. Qabul qiling shu daqiqada.
Endi biz nihoyat aqlli kontrakt mantig'ini amalga oshirishga o'tishimiz mumkin.
Π recv_external() biz ikki turdagi xabarlarni qabul qilamiz.
Shartnomamiz o'yinchilarning yo'qotishlarini jamlaganligi sababli, bu pul lotereya yaratuvchisiga o'tkazilishi kerak. Lotereya yaratuvchisining hamyon manzili shartnoma tuzilganda saqlashda qayd etiladi.
Har holda, biz yutqazganlarning grammlarini yuboradigan manzilni o'zgartirish qobiliyatiga muhtojmiz. Shuningdek, lotereyadan egasining manziliga gramm yuborishimiz kerak.
Birinchisidan boshlaylik. Avval xabarni yuborganingizdan so'ng, aqlli shartnoma yangi manzilni xotirada saqlaganligini tekshiradigan test yozamiz. Xabarda hisoblagich va yangi manzildan tashqari biz ham uzatamiz action 7 bitli butun son manfiy bo'lmagan raqam, unga qarab, biz aqlli shartnomada xabarni qanday qayta ishlashni tanlaymiz.
<b 0 32 u, 1 @ 7 u, new_owner_wc @ 32 i, new_owner_account_id @ 256 u, b> message_to_sign !
Sinovda siz aqlli kontrakt xotirasi qanday seriyadan chiqarilganligini ko'rishingiz mumkin storage beshda. O'zgaruvchilarning seriyasizlanishi Fift hujjatlarida tasvirlangan.
Keling, sinovni o'tkazamiz va uning muvaffaqiyatsizligiga ishonch hosil qilamiz. Endi lotereya egasining manzilini o'zgartirish uchun mantiq qo'shamiz.
Aqlli shartnomada biz tahlil qilishni davom ettiramiz message, o'qing action. Eslatib o'tamiz, bizda ikkita bo'ladi action: manzilni o'zgartiring va gramm yuboring.
Keyin shartnoma egasining yangi manzilini o'qiymiz va uni saqlash joyiga saqlaymiz.
Biz testlarni o'tkazamiz va uchinchi sinov muvaffaqiyatsiz ekanligini ko'ramiz. Shartnoma endi sinovda etishmayotgan xabarning 7 bitini qo'shimcha ravishda tahlil qilganligi sababli u buziladi. Xabarga mavjud bo'lmaganni qo'shing action. Keling, testlarni o'tkazamiz va hamma narsa o'tishini ko'ramiz. shu yerda o'zgarishlarga rozi bo'ling. Ajoyib.
Endi belgilangan miqdordagi grammni avval saqlangan manzilga yuborish mantiqini yozamiz.
Birinchidan, test yozamiz. Biz ikkita test yozamiz, biri muvozanat bo'lmasa, ikkinchisi hamma narsa muvaffaqiyatli o'tishi kerak. Sinovlarni ko'rish mumkin bu majburiyatda.
Endi kodni qo'shamiz. Birinchidan, ikkita yordamchi usulni yozamiz. Birinchi olish usuli aqlli shartnomaning joriy balansini aniqlashdir.
int balance() inline_ref method_id {
return get_balance().pair_first();
}
Ikkinchisi esa boshqa aqlli shartnomaga gramm yuborish uchun. Men ushbu usulni boshqa aqlli shartnomadan to'liq ko'chirib oldim.
() send_grams(int wc, int addr, int grams) impure {
;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 011000
cell msg = begin_cell()
;; .store_uint(0, 1) ;; 0 <= format indicator int_msg_info$0
;; .store_uint(1, 1) ;; 1 <= ihr disabled
;; .store_uint(1, 1) ;; 1 <= bounce = true
;; .store_uint(0, 1) ;; 0 <= bounced = false
;; .store_uint(4, 5) ;; 00100 <= address flags, anycast = false, 8-bit workchain
.store_uint (196, 9)
.store_int(wc, 8)
.store_uint(addr, 256)
.store_grams(grams)
.store_uint(0, 107) ;; 106 zeroes + 0 as an indicator that there is no cell with the data.
.end_cell();
send_raw_message(msg, 3); ;; mode, 2 for ignoring errors, 1 for sender pays fees, 64 for returning inbound message value
}
Keling, ushbu ikki usulni aqlli shartnomaga qo'shamiz va mantiqni yozamiz. Birinchidan, biz xabardan grammlar sonini tahlil qilamiz. Keyin balansni tekshiramiz, agar bu etarli bo'lmasa, biz istisno qilamiz. Har bir narsa yaxshi bo'lsa, biz grammlarni saqlangan manzilga yuboramiz va hisoblagichni yangilaymiz.
Mana bunday hozirgi paytda aqlli shartnomaga o'xshaydi. Keling, testlarni o'tkazamiz va ularning muvaffaqiyatli o'tishiga ishonch hosil qilamiz.
Aytgancha, har safar qayta ishlangan xabar uchun aqlli shartnomadan komissiya yechib olinadi. Smart kontrakt xabarlari so'rovni bajarishi uchun asosiy tekshiruvlardan so'ng siz qo'ng'iroq qilishingiz kerak accept_message().
Endi ichki xabarlarga o'tamiz. Aslida, biz faqat grammlarni qabul qilamiz va agar o'yinchi g'alaba qozonsa, ikki baravar pulni, agar u yutqazsa, uchinchisini egasiga qaytarib yuboramiz.
Birinchidan, oddiy test yozamiz. Buning uchun bizga aqlli kontraktning sinov manzili kerak bo'ladi, undan biz go'yoki aqlli kontraktga gramm yuboramiz.
Aqlli kontrakt manzili ikkita raqamdan iborat bo'lib, ish zanjiri uchun mas'ul bo'lgan 32 bitli tamsayΔ± va ushbu ish zanjiridagi 256 bitli manfiy bo'lmagan butun son noyob hisob raqami. Masalan, -1 va 12345, bu biz faylga saqlaydigan manzil.
Manzilni saqlash funksiyasidan nusxa oldim TonUtil.fif.
// ( wc addr fname -- ) Save address to file in 36-byte format
{ -rot 256 u>B swap 32 i>B B+ swap B>file } : save-address
Funktsiya qanday ishlashini ko'rib chiqaylik, bu Fift qanday ishlashi haqida tushuncha beradi. Interaktiv rejimda Fiftni ishga tushiring.
~/TON/build/crypto/fift -i
Avval biz stekga -1, 12345 va kelajakdagi fayl nomi "sender.addr" ni bosing:
-1 12345 "sender.addr"
Keyingi qadam funktsiyani bajarishdir -rot, bu stekni shunday o'zgartiradiki, stekning yuqori qismida noyob aqlli kontrakt raqami mavjud:
"sender.addr" -1 12345
256 u>B 256 bitli manfiy bo'lmagan butun sonni baytga aylantiradi.
Va nihoyat baytlar faylga yoziladi B>file. Shundan so'ng bizning stekimiz bo'sh. Biz to'xtadik Fift. Joriy jildda fayl yaratildi sender.addr. Keling, faylni yaratilgan papkaga o'tkazamiz test/addresses/.
Keling, aqlli shartnomaga gramm yuboradigan oddiy test yozaylik. Mana, majburiyat.
Endi lotereya mantig'ini ko'rib chiqaylik.
Biz qiladigan birinchi narsa - xabarni tekshirish bounced yoki agar bo'lmasa bounced, keyin biz bunga e'tibor bermaymiz. bounced Agar biron bir xatolik yuzaga kelsa, shartnoma grammlarni qaytaradi, degan ma'noni anglatadi. Agar to'satdan xatolik yuzaga kelsa, biz grammlarni qaytarmaymiz.
Biz tekshiramiz, agar balans yarim grammdan kam bo'lsa, biz shunchaki xabarni qabul qilamiz va unga e'tibor bermaymiz.
Keyinchalik, biz xabar kelgan aqlli shartnoma manzilini tahlil qilamiz.
Biz saqlash ma'lumotlarini o'qiymiz va agar ular yigirmatadan ortiq bo'lsa, eski tikishlarni tarixdan o'chirib tashlaymiz. Qulaylik uchun men uchta qo'shimcha funktsiyani yozdim pack_order(), unpack_order(), remove_old_orders().
Keyinchalik, balans to'lov uchun etarli bo'lmasa, biz bu pul tikish emas, balki to'ldirish deb hisoblaymiz va to'ldirishni saqlab qo'yamiz. orders.
Keyin nihoyat aqlli shartnomaning mohiyati.
Birinchidan, agar o'yinchi yutqazsa, biz uni tikish tarixida saqlaymiz va agar summa 3 grammdan ortiq bo'lsa, biz aqlli shartnoma egasiga 1/3 qismini yuboramiz.
Agar o'yinchi g'alaba qozonsa, biz o'yinchining manziliga ikki baravar pul yuboramiz, so'ngra tikish haqidagi ma'lumotlarni tarixda saqlaymiz.
() recv_internal(int order_amount, cell in_msg_cell, slice in_msg) impure {
var cs = in_msg_cell.begin_parse();
int flags = cs~load_uint(4); ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
if (flags & 1) { ;; ignore bounced
return ();
}
if (order_amount < 500000000) { ;; just receive grams without changing state
return ();
}
slice src_addr_slice = cs~load_msg_addr();
(int src_wc, int src_addr) = parse_std_addr(src_addr_slice);
(int stored_seqno, int pubkey, int order_seqno, int number_of_wins, int incoming_amount, int outgoing_amount, int owner_wc, int owner_account_id, cell orders) = unpack_state();
orders = remove_old_orders(orders, order_seqno);
if (balance() < 2 * order_amount + 500000000) { ;; not enough grams to pay the bet back, so this is re-fill
builder order = pack_order(order_seqno, 1, now(), order_amount, src_wc, src_addr);
orders~udict_set_builder(32, order_seqno, order);
set_data(pack_state(stored_seqno, pubkey, order_seqno + 1, number_of_wins, incoming_amount + order_amount, outgoing_amount, owner_wc, owner_account_id, orders));
return ();
}
if (rand(10) >= 4) {
builder order = pack_order(order_seqno, 3, now(), order_amount, src_wc, src_addr);
orders~udict_set_builder(32, order_seqno, order);
set_data(pack_state(stored_seqno, pubkey, order_seqno + 1, number_of_wins, incoming_amount + order_amount, outgoing_amount, owner_wc, owner_account_id, orders));
if (order_amount > 3000000000) {
send_grams(owner_wc, owner_account_id, order_amount / 3);
}
return ();
}
send_grams(src_wc, src_addr, 2 * order_amount);
builder order = pack_order(order_seqno, 2, now(), order_amount, src_wc, src_addr);
orders~udict_set_builder(32, order_seqno, order);
set_data(pack_state(stored_seqno, pubkey, order_seqno + 1, number_of_wins + 1, incoming_amount, outgoing_amount + 2 * order_amount, owner_wc, owner_account_id, orders));
}
Endi qolgan narsa oddiy, keling, shartnoma holati to'g'risida tashqi dunyodan ma'lumot olishimiz uchun olish usullarini yarataylik (aslida ularning aqlli kontrakt xotirasidan ma'lumotlarni o'qing).
Men aqlli shartnomani nashr qilishda yuzaga keladigan birinchi so'rovni qayta ishlaydigan kodni qo'shishni ham unutib qo'ydim. Tegishli majburiyat. Va yana tuzatilgan summaning 1/3 qismini egasining hisobiga yuborish bilan bog'liq xato.
Keyingi qadam aqlli shartnomani nashr qilishdir. Keling, papka yarataylik requests.
E'tibor berishga arziydigan narsa. Biz aqlli kontrakt xotirasi va kirish xabarini yaratamiz. Shundan so'ng, smart-kontrakt manzili yaratiladi, ya'ni manzil TONda nashr etilishidan oldin ham ma'lum. Keyinchalik, ushbu manzilga bir necha gramm yuborishingiz kerak va shundan keyingina siz aqlli shartnoma bilan faylni yuborishingiz kerak, chunki tarmoq aqlli shartnoma va undagi operatsiyalarni saqlash uchun komissiya oladi (smartni saqlaydigan va bajaradigan tasdiqlovchilar). shartnomalar). Kodni bu erda ko'rish mumkin.
Keyin nashr kodini bajaramiz va olamiz lottery-query.boc aqlli shartnoma fayli va manzili.
Va biz ushbu manzil bilan hisob bo'sh ekanligini ko'ramiz.
account state is empty
Manzilga yuboramiz 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 Gram va bir necha soniyadan so'ng biz bir xil buyruqni bajaramiz. Gram yuborish uchun men foydalanaman rasmiy hamyon, va siz suhbatdan kimdirdan test grammlarini so'rashingiz mumkin, men maqolaning oxirida gaplashaman.
Keling, aqlli kontrakt bilan ishlash uchun so'rovlarni yarataylik.
Aniqrog'i, birinchisini manzilni o'zgartirish uchun mustaqil ish sifatida qoldiramiz, ikkinchisini esa egasining manziliga gramm yuborish uchun qilamiz. Aslida, biz grammlarni yuborish uchun testda bo'lgani kabi, xuddi shunday qilishimiz kerak bo'ladi.
Bu biz aqlli shartnoma yuboramiz xabar, qaerda msg_seqno 165, action Yuborish uchun 2 va 9.5 gramm.
<b 165 32 u, 2 7 u, 9500000000 Gram, b>
Shaxsiy kalitingiz bilan xabarni imzolashni unutmang lottery.pk, bu aqlli shartnomani yaratishda avval yaratilgan. Mana, tegishli majburiyat.
Get usullaridan foydalangan holda aqlli shartnomadan ma'lumot olish
Keling, aqlli kontrakt olish usullarini qanday ishlatishni ko'rib chiqaylik.
Ishga tushirish lite-client va biz yozgan get usullarini ishga tushiring.
Biz lite-client-dan foydalanamiz va saytdagi aqlli shartnoma haqidagi ma'lumotlarni ko'rsatish usullarini olamiz.
Veb-saytda aqlli shartnoma ma'lumotlarini ko'rsatish
Men aqlli shartnoma ma'lumotlarini qulay tarzda ko'rsatish uchun Python-da oddiy veb-sayt yozdim. Bu erda men bu haqda batafsil to'xtalmayman va saytni nashr etaman bitta majburiyatda.
TONga so'rovlar quyidagilardan amalga oshiriladi Python yordamida lite-client. Qulaylik uchun sayt Docker-da paketlangan va Google Cloud-da nashr etilgan. Havola.
Urinish
Keling, to'ldirish uchun u erga gramm yuborishga harakat qilaylik hamyon. Biz 40 gramm yuboramiz. Va aniqlik uchun bir nechta pul tikamiz. Ko'ramizki, sayt garovlar tarixi, joriy yutuq foizi va boshqa foydali ma'lumotlarni ko'rsatadi.
Ko'ramizBirinchisida g'alaba qozonganimizni, ikkinchisida yutqazganimizni.
So'zdan keyin
Maqola men kutganimdan ancha uzun bo'lib chiqdi, ehtimol u qisqaroq bo'lishi mumkin edi, yoki shunchaki TON haqida hech narsa bilmaydigan va u bilan o'zaro aloqada bo'lish qobiliyatiga ega unchalik oddiy bo'lmagan aqlli shartnoma yozish va nashr etishni xohlaydigan odam uchun. bu. Ehtimol, ba'zi narsalarni soddaroq tushuntirish mumkin edi.
Ehtimol, amalga oshirishning ba'zi jihatlari yanada samarali va oqlangan bo'lishi mumkin edi, ammo keyin maqolani tayyorlash uchun ko'proq vaqt kerak bo'lar edi. Bundan tashqari, men biror joyda xatoga yo'l qo'ygan yoki biror narsani tushunmagan bo'lishim mumkin, shuning uchun agar siz jiddiy ish qilmoqchi bo'lsangiz, rasmiy hujjatlarga yoki TON kodli rasmiy omborga tayanishingiz kerak.
Shuni ta'kidlash kerakki, TONning o'zi hali ham faol rivojlanish bosqichida bo'lganligi sababli, ushbu maqoladagi har qanday qadamni buzadigan o'zgarishlar yuz berishi mumkin (bu men yozayotganimda sodir bo'lgan, u allaqachon tuzatilgan), ammo umumiy yondashuv o'zgarishi dargumon.
Men TON kelajagi haqida gapirmayman. Ehtimol, platforma katta narsaga aylanadi va biz uni o'rganishga vaqt ajratishimiz va mahsulotlarimiz bilan joyni to'ldirishimiz kerak.
TON dan kattaroq foydalanuvchilarning potentsial auditoriyasiga ega Facebook-dan Libra ham mavjud. Men Libra haqida deyarli hech narsa bilmayman, forumga ko'ra, u erda TON hamjamiyatiga qaraganda ko'proq faollik mavjud. TON ishlab chiquvchilari va jamoasi ko'proq yer ostiga o'xshasa ham, bu ham ajoyib.
Telegramda TON haqida suhbatlashing, bu haqiqatan ham uni dastlabki bosqichda aniqlashga yordam berdi. Menimcha, TON uchun nimadir yozganlarning hammasi o'sha yerda desam xato bo'lmaydi. Siz u erda test grammlarini ham so'rashingiz mumkin. https://t.me/tondev_ru