Rreth asaj se si të shkruani dhe publikoni një kontratë inteligjente në Rrjetin e Hapur Telegram (TON)

Rreth asaj se si të shkruani dhe publikoni një kontratë inteligjente në TON

Për çfarë flet ky artikull?

Në artikull do të flas se si mora pjesë në konkursin e parë (nga dy) të bllokut të Telegramit, nuk mora një çmim dhe vendosa të regjistroj përvojën time në një artikull në mënyrë që të mos zhytet në harresë dhe, ndoshta, të ndihmojë dikush.

Meqenëse nuk doja të shkruaja kod abstrakt, por të bëja diçka që funksiononte, për artikullin shkrova një kontratë inteligjente për një llotari të menjëhershme dhe një faqe interneti që tregon të dhënat e kontratës inteligjente direkt nga TON pa përdorur ruajtje të ndërmjetme.

Artikulli do të jetë i dobishëm për ata që duan të bëjnë kontratën e tyre të parë inteligjente në TON, por nuk dinë nga të fillojnë.

Duke përdorur lotarinë si shembull, unë do të kaloj nga instalimi i mjedisit në publikimin e një kontrate inteligjente, ndërveprim me të dhe shkrimin e një faqe interneti për marrjen dhe publikimin e të dhënave.

Rreth pjesëmarrjes në konkurs

Tetorin e kaluar, Telegram njoftoi një konkurs blockchain me gjuhë të reja Fift и FunC. Ishte e nevojshme të zgjidhej nga shkrimi i ndonjë prej pesë kontratave inteligjente të propozuara. Mendova se do të ishte mirë të bëja diçka ndryshe, të mësoja një gjuhë dhe të bëja diçka, edhe nëse nuk do të më duhej të shkruaja asgjë tjetër në të ardhmen. Plus, tema është vazhdimisht në buzë.

Vlen të thuhet se nuk kisha përvojë në zhvillimin e kontratave inteligjente.

Planifikova të merrja pjesë deri në fund derisa të mundja dhe më pas të shkruaj një artikull rishikues, por dështova menjëherë në të parën. I shkroi një portofol me shumë nënshkrime në FunC dhe në përgjithësi funksionoi. E mora si bazë kontratë inteligjente mbi Solidity.

Në atë kohë, mendova se kjo ishte padyshim e mjaftueshme për të marrë të paktën një vend çmimi. Si rezultat, rreth 40 nga 60 pjesëmarrës u bënë fitues çmimesh dhe unë nuk isha në mesin e tyre. Në përgjithësi, nuk ka asgjë të keqe me këtë, por një gjë më shqetësoi. Në momentin e shpalljes së rezultateve nuk ishte bërë rishikimi i testit për kontratën time, pyeta pjesëmarrësit në chat nëse ka ndonjë tjetër që nuk e kishte, nuk kishte.

Me sa duket, duke i kushtuar vëmendje mesazheve të mia, dy ditë më vonë gjyqtarët publikuan një koment dhe unë ende nuk e kuptoj nëse ata e humbën aksidentalisht kontratën time të zgjuar gjatë gjykimit apo thjesht menduan se ishte aq e keqe sa nuk kishte nevojë për koment. Bëra një pyetje në faqe, por nuk mora përgjigje. Edhe pse nuk është sekret se kush gjykoi, e konsiderova të panevojshme të shkruaj mesazhe personale.

U shpenzua shumë kohë për të kuptuar, kështu që u vendos të shkruaj një artikull. Meqenëse nuk ka ende shumë informacione, ky artikull do t'ju ndihmojë të kurseni kohë për të gjithë të interesuarit.

Koncepti i kontratave inteligjente në TON

Para se të shkruani diçka, duhet të kuptoni se nga cila anë t'i qaseni kësaj gjëje. Prandaj, tani do t'ju tregoj se nga cilat pjesë përbëhet sistemi. Më saktësisht, cilat pjesë duhet të dini për të shkruar të paktën një lloj kontrate pune.

Ne do të fokusohemi në shkrimin e një kontrate të zgjuar dhe punën me të TON Virtual Machine (TVM), Fift и FunC, kështu që artikulli është më shumë si një përshkrim i zhvillimit të një programi të rregullt. Ne nuk do të ndalemi në mënyrën se si funksionon vetë platforma këtu.

Në përgjithësi për mënyrën se si funksionon TVM dhe gjuha Fift ka dokumentacion te mire zyrtar. Gjatë pjesëmarrjes në konkurs dhe tani duke shkruar kontratën aktuale, shpesh i drejtohesha asaj.

Gjuha kryesore në të cilën shkruhen kontratat inteligjente është FunC. Nuk ka asnjë dokumentacion për të për momentin, kështu që për të shkruar diçka duhet të studioni shembuj të kontratave inteligjente nga depoja zyrtare dhe zbatimi i vetë gjuhës atje, plus mund të shikoni shembuj të kontratave inteligjente nga dy të fundit konkurse. Lidhjet në fund të artikullit.

Le të themi se kemi shkruar tashmë një kontratë të zgjuar për FunC, pas kësaj ne përpilojmë kodin në asemblerin Fift.

Mbetet të publikohet kontrata e përpiluar smart. Për ta bërë këtë ju duhet të shkruani një funksion në Fift, i cili do të marrë kodin e kontratës inteligjente dhe disa parametra të tjerë si hyrje, dhe dalja do të jetë një skedar me shtesën .boc (që do të thotë "çantë me qeliza"), dhe, në varësi të mënyrës se si e shkruajmë, një çelës privat dhe adresë, e cila krijohet bazuar në kodin e kontratës inteligjente. Tashmë mund të dërgoni gramë në adresën e një kontrate inteligjente që ende nuk është publikuar.

Për të publikuar një kontratë të zgjuar në TON marrë .boc skedari do të duhet të dërgohet në blockchain duke përdorur një klient të lehtë (më shumë për këtë më poshtë). Por përpara se të publikoni, duhet të transferoni gram në adresën e gjeneruar, përndryshe kontrata smart nuk do të publikohet. Pas publikimit, mund të ndërveproni me kontratën inteligjente duke i dërguar asaj mesazhe nga jashtë (për shembull, duke përdorur një klient të lehtë) ose nga brenda (për shembull, një kontratë inteligjente i dërgon një tjetra një mesazh brenda TON).

Pasi të kuptojmë se si publikohet kodi, bëhet më e lehtë. Ne e dimë përafërsisht se çfarë duam të shkruajmë dhe si do të funksionojë programi ynë. Dhe ndërsa shkruajmë, ne kërkojmë se si kjo tashmë zbatohet në kontratat ekzistuese inteligjente, ose shikojmë kodin e zbatimit Fift и FunC në depo zyrtare, ose shikoni në dokumentacionin zyrtar.

Shumë shpesh kërkoja fjalë kyçe në bisedën e Telegram ku mblidheshin të gjithë pjesëmarrësit e konkursit dhe punonjësit e Telegram, dhe ndodhi që gjatë konkursit të gjithë u mblodhën atje dhe filluan të diskutojnë Fift dhe FunC. Linku në fund të artikullit.

Është koha për të kaluar nga teoria në praktikë.

Përgatitja e mjedisit për të punuar me TON

Bëra gjithçka që do të përshkruhet në artikullin mbi MacOS dhe e kontrollova dy herë në një mënyrë të pastër. Ubuntu 18.04 LTS në Docker.

Gjëja e parë që duhet të bëni është të shkarkoni dhe instaloni lite-client me të cilin mund të dërgoni kërkesa në TON.

Udhëzimet në faqen zyrtare të internetit e përshkruajnë procesin e instalimit mjaft hollësisht dhe qartë, duke lënë mënjanë disa detaje. Këtu ne ndjekim udhëzimet, duke instaluar çdo varësi që mungon gjatë procesit. Unë nuk e kompilova vetë çdo projekt, por e instalova nga depoja zyrtare. Ubuntu (në MacOS që përdora) brew).

apt -y install git 
apt -y install wget 
apt -y install cmake 
apt -y install g++ 
apt -y install zlib1g-dev 
apt -y install libssl-dev 

Pasi të jenë instaluar të gjitha varësitë, mund të instaloni lite-client, Fift, FunC.

Së pari, ne klonojmë depon e TON së bashku me varësitë e tij. Për lehtësi, ne do të bëjmë gjithçka në një dosje ~/TON.

cd ~/TON
git clone https://github.com/ton-blockchain/ton.git
cd ./ton
git submodule update --init --recursive

Depoja ruan gjithashtu zbatime Fift и FunC.

Tani jemi gati për të mbledhur projektin. Kodi i depove klonohet në një dosje ~/TON/ton. Në ~/TON krijoni një dosje build dhe mblidhni projektin në të.

mkdir ~/TON/build 
cd ~/TON/build
cmake ../ton

Meqenëse do të shkruajmë një kontratë të zgjuar, nuk na duhet vetëm lite-clientPor Fift с FunC, kështu që le të përpilojmë gjithçka. Nuk është një proces i shpejtë, ndaj jemi në pritje.

cmake --build . --target lite-client
cmake --build . --target fift
cmake --build . --target func

Më pas, shkarkoni skedarin e konfigurimit i cili përmban të dhëna për nyjen në të cilën lite-client do të lidhet.

wget https://test.ton.org/ton-lite-client-test1.config.json

Bërja e kërkesave të para në TON

Tani le të nisim lite-client.

cd ~/TON/build
./lite-client/lite-client -C ton-lite-client-test1.config.json

Nëse ndërtimi ishte i suksesshëm, atëherë pas nisjes do të shihni një regjistër të lidhjes së klientit të lehtë me nyjen.

[ 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)
...

Ju mund të ekzekutoni komandën help dhe shikoni se çfarë komandash janë të disponueshme.

help

Le të rendisim komandat që do të përdorim në këtë artikull.

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

last получает последний созданный блок с сервера. 

sendfile <filename> отправляет в TON файл с сообщением, именно с помощью этой команды публикуется смарт-контракт и запрсосы к нему. 

getaccount <addr> загружает текущее состояние смарт-контракта с указанным адресом. 

runmethod <addr> [<block-id-ext>] <method-id> <params>  запускает get-методы смартконтракта. 

Tani jemi gati të shkruajmë vetë kontratën.

Zbatimi

Ide

Siç shkrova më lart, kontrata e zgjuar që po shkruajmë është short.

Për më tepër, kjo nuk është një llotari në të cilën ju duhet të blini një biletë dhe të prisni një orë, ditë ose muaj, por një llotari e menjëhershme në të cilën përdoruesi transferon në adresën e kontratës N gram, dhe e merr atë menjëherë 2 * N gram ose humbet. Ne do të bëjmë probabilitetin për të fituar rreth 40%. Nëse nuk ka gram të mjaftueshëm për pagesë, atëherë ne do ta konsiderojmë transaksionin si një rimbushje.

Për më tepër, është e rëndësishme që bastet të shihen në kohë reale dhe në një formë të përshtatshme, në mënyrë që përdoruesi të kuptojë menjëherë nëse ai fitoi apo humbi. Prandaj, ju duhet të krijoni një faqe interneti që do të tregojë baste dhe rezultate direkt nga TON.

Shkrimi i një kontrate të zgjuar

Për lehtësi, kam theksuar kodin për FunC; shtojca mund të gjendet dhe të instalohet në kërkimin e kodit të Visual Studio; nëse papritur dëshironi të shtoni diçka, unë e kam bërë shtesën në dispozicion të publikut. Gjithashtu, dikush ka bërë më parë një shtojcë për të punuar me Fift, gjithashtu mund ta instaloni dhe ta gjeni në VSC.

Le të krijojmë menjëherë një depo ku do të kryejmë rezultatet e ndërmjetme.

Për ta bërë jetën tonë më të lehtë, ne do të shkruajmë një kontratë të zgjuar dhe do ta testojmë atë në nivel lokal derisa të jetë gati. Vetëm pas kësaj do ta publikojmë në TON.

Kontrata inteligjente ka dy metoda të jashtme që mund të aksesohen. Së pari, recv_external() ky funksion ekzekutohet kur një kërkesë për kontratë vjen nga bota e jashtme, domethënë jo nga TON, për shembull, kur ne vetë gjenerojmë një mesazh dhe e dërgojmë përmes klientit lite. Së dyti, recv_internal() kjo është kur, brenda vetë TON-it, çdo kontratë i referohet tonës. Në të dyja rastet, ju mund t'i kaloni parametrat funksionit.

Le të fillojmë me një shembull të thjeshtë që do të funksionojë nëse publikohet, por nuk ka asnjë ngarkesë funksionale në të.

() recv_internal(slice in_msg) impure {
    ;; TODO: implementation 
}

() recv_external(slice in_msg) impure {
    ;; TODO: implementation  
}

Këtu duhet të shpjegojmë se çfarë është slice. Të gjitha të dhënat e ruajtura në TON Blockchain janë një koleksion TVM cell ose thjesht cell, në një qelizë të tillë mund të ruani deri në 1023 bit të dhëna dhe deri në 4 lidhje me qeliza të tjera.

TVM cell slice ose slice kjo është pjesë e asaj ekzistuese cell përdoret për ta analizuar, do të bëhet e qartë më vonë. Gjëja kryesore për ne është që mund të transferohemi slice dhe në varësi të llojit të mesazhit, përpunoni të dhënat në recv_external() ose recv_internal().

impure — një fjalë kyçe që tregon se funksioni modifikon të dhënat e kontratës inteligjente.

Le ta ruajmë kodin e kontratës lottery-code.fc dhe përpiloni.

~/TON/build/crypto/func -APSR -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fc 

Kuptimi i flamujve mund të shihet duke përdorur komandën

~/TON/build/crypto/func -help

Ne kemi përpiluar kodin e asemblerit Fift në 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

Mund të lançohet në nivel lokal, për këtë do të përgatisim ambientin.

Vini re se linja e parë lidhet Asm.fif, ky është kodi i shkruar në Fift për montuesin Fift.

Meqenëse duam të ekzekutojmë dhe testojmë kontratën inteligjente në nivel lokal, do të krijojmë një skedar lottery-test-suite.fif dhe kopjoni kodin e përpiluar atje, duke zëvendësuar rreshtin e fundit në të, i cili shkruan kodin e kontratës inteligjente në një konstante codepër ta transferuar më pas në makinën virtuale:

"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

Deri më tani duket qartë, tani le të shtojmë në të njëjtin skedar kodin që do të përdorim për të nisur TVM.

0 tuple 0x076ef1ea , // magic
0 , 0 , // actions msg_sents
1570998536 , // unix_time
1 , 1 , 3 , // block_lt, trans_lt, rand_seed
0 tuple 100000000000000 , dictnew , , // remaining balance
0 , dictnew , // contract_address, global_config
1 tuple // wrap to another tuple
constant c7

0 constant recv_internal // to run recv_internal() 
-1 constant recv_external // to invoke recv_external()

В c7 ne regjistrojmë kontekstin, domethënë të dhënat me të cilat do të lëshohet TVM (ose gjendja e rrjetit). Edhe gjatë konkursit, një nga zhvilluesit tregoi se si të krijonte c7 dhe kopjova. Në këtë artikull mund të na duhet të ndryshojmë rand_seed meqenëse gjenerimi i një numri të rastësishëm varet nga ai dhe nëse nuk ndryshohet, i njëjti numër do të kthehet çdo herë.

recv_internal и recv_external konstantet me vlera 0 dhe -1 do të jenë përgjegjëse për thirrjen e funksioneve përkatëse në kontratën inteligjente.

Tani jemi gati të krijojmë testin e parë për kontratën tonë të zbrazët inteligjente. Për qartësi, tani për tani do t'i shtojmë të gjitha testet në të njëjtin skedar lottery-test-suite.fif.

Le të krijojmë një ndryshore storage dhe shkruani një bosh në të cell, kjo do të jetë ruajtja e kontratës inteligjente.

message Ky është mesazhi që ne do t'i transmetojmë kontaktit inteligjent nga jashtë. Ne gjithashtu do ta bëjmë bosh tani për tani.

variable storage 
<b b> storage ! 

variable message 
<b b> message ! 

Pasi të kemi përgatitur konstantat dhe variablat, nisim TVM duke përdorur komandën runvmctx dhe kalojini parametrat e krijuar në hyrje.

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

Në fund do t'ia dalim këtu është një kodi i ndërmjetëm për Fift.

Tani mund të ekzekutojmë kodin që rezulton.

export FIFTPATH=~/TON/ton/crypto/fift/lib // выполняем один раз для удобства 
~/TON/build/crypto/fift -s lottery-test-suite.fif 

Programi duhet të funksionojë pa gabime dhe në dalje do të shohim regjistrin e ekzekutimit:

execute SETCP 0
execute DICTPUSHCONST 19 (xC_,1)
execute DICTIGETJMPZ
execute DROP
execute implicit RET
[ 3][t 0][1582281699.325381279][vm.cpp:479]     steps: 5 gas: used=304, max=9223372036854775807, limit=9223372036854775807, credit=0

E shkëlqyeshme, ne kemi shkruar versionin e parë të punës të kontratës inteligjente.

Tani duhet të shtojmë funksionalitetin. Së pari le të merremi me mesazhet që vijnë nga bota e jashtme në recv_external()

Vetë zhvilluesi zgjedh formatin e mesazhit që mund të pranojë kontrata.

Por zakonisht

  • së pari, ne duam ta mbrojmë kontratën tonë nga bota e jashtme dhe ta bëjmë atë në mënyrë që vetëm pronari i kontratës t'i dërgojë mesazhe të jashtme.
  • së dyti, kur dërgojmë një mesazh të vlefshëm në TON, duam që kjo të ndodhë saktësisht një herë dhe kur dërgojmë përsëri të njëjtin mesazh, kontrata smart e refuzon atë.

Pra, pothuajse çdo kontratë i zgjidh këto dy probleme, pasi kontrata jonë pranon mesazhe të jashtme, duhet të kujdesemi edhe për këtë.

Ne do ta bëjmë atë në rend të kundërt. Së pari, le ta zgjidhim problemin me përsëritjen, nëse kontrata e ka marrë tashmë një mesazh të tillë dhe e ka përpunuar atë, nuk do ta ekzekutojë për herë të dytë. Dhe pastaj do ta zgjidhim problemin në mënyrë që vetëm një rreth i caktuar njerëzish të mund të dërgojnë mesazhe në kontratën inteligjente.

Ka mënyra të ndryshme për të zgjidhur problemin me mesazhe të kopjuara. Ja si do ta bëjmë. Në kontratën inteligjente, ne inicializojmë numëruesin e mesazheve të marra me vlerën fillestare 0. Në çdo mesazh në kontratën inteligjente, do të shtojmë vlerën e numëruesit aktual. Nëse vlera e numëruesit në mesazh nuk përputhet me vlerën në kontratën inteligjente, atëherë ne nuk e përpunojmë atë; nëse po, atëherë e përpunojmë atë dhe e rrisim numëruesin në kontratën inteligjente me 1.

Le të kthehemi në lottery-test-suite.fif dhe shtoni një test të dytë në të. Nëse dërgojmë një numër të pasaktë, kodi duhet të bëjë një përjashtim. Për shembull, lërini të dhënat e kontratës të ruajnë 166, dhe ne do të dërgojmë 165.

<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"

Le të nisim.

 ~/TON/build/crypto/fift -s lottery-test-suite.fif 

Dhe ne do të shohim që testi është ekzekutuar me një gabim.

[ 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

Në këtë fazë lottery-test-suite.fif duhet të duket si по ссылке.

Tani le të shtojmë logjikën kundër kontratës inteligjente 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 qëndron mesazhi që dërgojmë.

Gjëja e parë që bëjmë është të kontrollojmë nëse mesazhi përmban të dhëna, nëse jo, atëherë thjesht dalim.

Më pas ne analizojmë mesazhin. in_msg~load_uint(32) ngarkon numrin 165, 32-bit unsigned int nga mesazhi i transmetuar.

Më pas ngarkojmë 32 bit nga ruajtja e kontratës inteligjente. Kontrollojmë që numri i ngarkuar të përputhet me atë të kaluar; nëse jo, bëjmë një përjashtim. Në rastin tonë, duke qenë se po kalojmë një mosndeshje, duhet bërë një përjashtim.

Tani le të përpilojmë.

~/TON/build/crypto/func -APSR -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fc 

Kopjoni kodin që rezulton në lottery-test-suite.fif, duke mos harruar të zëvendësoni rreshtin e fundit.

Ne kontrollojmë që testi të kalojë:

~/TON/build/crypto/fift -s lottery-test-suite.fif

Pikërisht këtu Ju mund të shihni angazhimin përkatës me rezultatet aktuale.

Vini re se është e papërshtatshme të kopjoni vazhdimisht kodin e përpiluar të një kontrate inteligjente në një skedar me teste, kështu që ne do të shkruajmë një skript që do të shkruajë kodin në një konstante për ne, dhe thjesht do ta lidhim kodin e përpiluar me testet tona duke përdorur "include".

Krijoni një skedar në dosjen e projektit build.sh me përmbajtjen e mëposhtme.

#!/bin/bash

~/TON/build/crypto/func -SPA -R -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fc

Le ta bëjmë atë të ekzekutueshme.

chmod +x ./build.sh

Tani, thjesht ekzekutoni skriptin tonë për të përpiluar kontratën. Por përveç kësaj, ne duhet ta shkruajmë atë në një konstante code. Pra, ne do të krijojmë një skedar të ri lotter-compiled-for-test.fif, të cilin do ta përfshijmë në dosje lottery-test-suite.fif.

Le të shtojmë kodin e skajit në sh, i cili thjesht do të kopjojë skedarin e përpiluar lotter-compiled-for-test.fif dhe ndryshoni rreshtin e fundit në të.

# 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

Tani, për të kontrolluar, le të ekzekutojmë skriptin që rezulton dhe do të krijohet një skedar lottery-compiled-for-test.fif, të cilin do ta përfshijmë në tonë lottery-test-suite.fif

В lottery-test-suite.fif fshini kodin e kontratës dhe shtoni rreshtin "lottery-compiled-for-test.fif" include.

Ne kryejmë teste për të kontrolluar nëse ato kalojnë.

~/TON/build/crypto/fift -s lottery-test-suite.fif

E shkëlqyeshme, tani për të automatizuar nisjen e testeve, le të krijojmë një skedar test.sh, i cili fillimisht do të ekzekutohet build.sh, dhe më pas ekzekutoni testet.

touch test.sh
chmod +x test.sh

Ne shkruajmë brenda

./build.sh 

echo "nCompilation completedn"

export FIFTPATH=~/TON/ton/crypto/fift/lib
~/TON/build/crypto/fift -s lottery-test-suite.fif

Le ta bëjmë test.sh dhe drejtojeni për t'u siguruar që testet funksionojnë.

chmod +x ./test.sh
./test.sh

Ne kontrollojmë që kontrata të përpilohet dhe testet janë ekzekutuar.

E shkëlqyeshme, tani në fillim test.sh Testet do të përpilohen dhe do të ekzekutohen menjëherë. Këtu është lidhja për të angazhohen.

Mirë, përpara se të vazhdojmë, le të bëjmë edhe një gjë për lehtësi.

Le të krijojmë një dosje build ku do të ruajmë kontratën e kopjuar dhe klonin e saj të shkruar në një konstante lottery-compiled.fif, lottery-compiled-for-test.fif. Le të krijojmë gjithashtu një dosje test ku do të ruhet skedari i testit? lottery-test-suite.fif dhe potencialisht skedarë të tjerë mbështetës. Lidhje me ndryshimet përkatëse.

Le të vazhdojmë zhvillimin e kontratës inteligjente.

Më pas duhet të ketë një test që kontrollon nëse mesazhi është marrë dhe numëruesi është përditësuar në dyqan kur dërgojmë numrin e saktë. Por ne do ta bëjmë atë më vonë.

Tani le të mendojmë se çfarë strukture të dhënash dhe cilat të dhëna duhet të ruhen në kontratën inteligjente.

Unë do të përshkruaj gjithçka që ruajmë.

`seqno` 32-х битное целое положительное число счетчик. 

`pubkey` 256-ти битное целое положительное число публичный ключ, с помощью которого, мы будем проверять подпись отправленного извне сообщения, о чем ниже. 

`order_seqno` 32-х битное целое положительное число хранит счетчик количества ставок. 

`number_of_wins` 32-х битное целое положительное число хранит  количество побед. 

`incoming_amount` тип данных Gram (первые 4 бита отвечает за длину), хранит общее количество грамов, которые были отправлены на контртакт. 

`outgoing_amount` общее количество грамов, которое было отправлено победителям. 

`owner_wc` номер воркчейна, 32-х битное (в некоторых местах написано, что 8-ми битное) целое число. В данный момент всего два -1 и 0. 

`owner_account_id` 256-ти битное целое положительное число, адрес контракта в текущем воркчейне. 

`orders` переменная типа словарь, хранит последние двадцать ставок. 

Më pas duhet të shkruani dy funksione. Le ta quajmë të parën pack_state(), i cili do të paketojë të dhënat për ruajtjen e mëvonshme në ruajtjen e kontratës inteligjente. Le ta quajmë të dytën unpack_state() do të lexojë dhe kthejë të dhënat nga ruajtja.

_ 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;
}

Ne i shtojmë këto dy funksione në fillim të kontratës inteligjente. Do të funksionojë këtu është një rezultat i ndërmjetëm.

Për të ruajtur të dhënat, duhet të telefononi funksionin e integruar set_data() dhe do të shkruajë të dhëna nga pack_state() në ruajtjen e kontratës inteligjente.

cell packed_state = pack_state(arg_1, .., arg_n); 
set_data(packed_state);

Tani që kemi funksione të përshtatshme për shkrimin dhe leximin e të dhënave, mund të vazhdojmë.

Duhet të kontrollojmë që mesazhi që vjen nga jashtë është i nënshkruar nga pronari i kontratës (ose një përdorues tjetër që ka akses në çelësin privat).

Kur publikojmë një kontratë inteligjente, mund ta inicializojmë me të dhënat që na duhen në ruajtje, të cilat do të ruhen për përdorim në të ardhmen. Ne do të regjistrojmë çelësin publik atje në mënyrë që të mund të verifikojmë që mesazhi në hyrje është nënshkruar me çelësin privat përkatës.

Përpara se të vazhdojmë, le të krijojmë një çelës privat dhe ta shkruajmë atë test/keys/owner.pk. Për ta bërë këtë, le të hapim Fift në modalitetin interaktiv dhe të ekzekutojmë katër komanda.

`newkeypair` генерация публичного и приватного ключа и запись их в стек. 

`drop` удаления из стека верхнего элемента (в данном случае публичный ключ)  

`.s` просто посмотреть что лежит в стеке в данный момент 

`"owner.pk" B>file` запись приватного ключа в файл с именем `owner.pk`. 

`bye` завершает работу с Fift. 

Le të krijojmë një dosje keys brenda dosjes test dhe shkruani çelësin privat atje.

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

Ne shohim një skedar në dosjen aktuale owner.pk.

Ne e heqim çelësin publik nga pirgja dhe kur nevojitet mund ta marrim nga ai privat.

Tani duhet të shkruajmë një verifikim nënshkrimi. Le të fillojmë me testin. Së pari lexojmë çelësin privat nga skedari duke përdorur funksionin file>B dhe shkruajeni atë në një ndryshore owner_private_key, më pas duke përdorur funksionin priv>pub konvertoni çelësin privat në një çelës publik dhe shkruani rezultatin në të owner_public_key.

variable owner_private_key
variable owner_public_key 

"./keys/owner.pk" file>B owner_private_key !
owner_private_key @ priv>pub owner_public_key !

Do të na duhen të dy çelësat.

Ne inicializojmë ruajtjen e kontratës inteligjente me të dhëna arbitrare në të njëjtën sekuencë si në funksion pack_state()dhe shkruajeni atë në një ndryshore storage.

variable owner_private_key
variable owner_public_key 
variable orders
variable owner_wc
variable owner_account_id

"./keys/owner.pk" file>B owner_private_key !
owner_private_key @ priv>pub owner_public_key !
dictnew orders !
0 owner_wc !
0 owner_account_id !

<b 0 32 u, owner_public_key @ B, 0 32 u, 0 32 u, 0 Gram, 0 Gram, owner_wc @ 32 i, owner_account_id @ 256 u,  orders @ dict, b> storage !

Më pas, ne do të krijojmë një mesazh të nënshkruar, ai do të përmbajë vetëm nënshkrimin dhe vlerën e kundërt.

Fillimisht, krijojmë të dhënat që duam të transmetojmë, më pas i nënshkruajmë me një çelës privat dhe në fund gjenerojmë një mesazh të nënshkruar.

variable message_to_sign
variable message_to_send
variable signature
<b 0 32 u, b> message_to_sign !
message_to_sign @ hashu owner_private_key @ ed25519_sign_uint signature !
<b signature @ B, 0 32 u, b> <s  message_to_send !  

Si rezultat, mesazhi që do t'i dërgojmë kontratës inteligjente regjistrohet në një variabël message_to_send, në lidhje me funksionet hashu, ed25519_sign_uint ju mund të lexoni në dokumentacionin e pestë.

Dhe për të kryer testin ne e thërrasim përsëri.

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

Ja kështu Skedari me teste duhet të duket kështu në këtë fazë.

Le të bëjmë testin dhe do të dështojë, kështu që ne do të ndryshojmë kontratën inteligjente në mënyrë që ajo të marrë mesazhe të këtij formati dhe të verifikojë nënshkrimin.

Së pari, ne numërojmë 512 bit të nënshkrimit nga mesazhi dhe e shkruajmë atë në një variabël, pastaj numërojmë 32 bit të ndryshores numërues.

Meqenëse kemi një funksion për leximin e të dhënave nga ruajtja e kontratës inteligjente, do ta përdorim atë.

Tjetra është kontrollimi i numëruesit të transferuar me ruajtje dhe kontrollimi i nënshkrimit. Nëse diçka nuk përputhet, atëherë hedhim një përjashtim me kodin e duhur.

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));

Angazhimi përkatës këtu.

Le të ekzekutojmë testet dhe të shohim që testi i dytë dështon. Për dy arsye, nuk ka bit të mjaftueshëm në mesazh dhe nuk ka pjesë të mjaftueshme në ruajtje, kështu që kodi prishet kur analizohet. Ne duhet të shtojmë një nënshkrim në mesazhin që po dërgojmë dhe të kopjojmë hapësirën ruajtëse nga testi i fundit.

Në testin e dytë, ne do të shtojmë një nënshkrim mesazhi dhe do të ndryshojmë ruajtjen e kontratës inteligjente. Ja kështu dosja me teste duket si për momentin.

Le të shkruajmë një test të katërt, në të cilin do të dërgojmë një mesazh të nënshkruar me çelësin privat të dikujt tjetër. Le të krijojmë një çelës tjetër privat dhe ta ruajmë në një skedar not-owner.pk. Ne do ta nënshkruajmë mesazhin me këtë çelës privat. Le të kryejmë testet dhe të sigurohemi që të gjitha testet të kalojnë. Angazhohen ne kete moment.

Tani më në fund mund të kalojmë në zbatimin e logjikës së kontratës inteligjente.
В recv_external() do të pranojmë dy lloje mesazhesh.

Duke qenë se kontrata jonë do të grumbullojë humbjet e lojtarëve, këto para duhet t'i transferohen krijuesit të shortit. Adresa e portofolit të krijuesit të lotarisë regjistrohet në ruajtje kur krijohet kontrata.

Për çdo rast, na duhet aftësia për të ndryshuar adresën në të cilën dërgojmë gramat e humbësve. Ne gjithashtu duhet të jemi në gjendje të dërgojmë gramë nga lotaria në adresën e pronarit.

Le të fillojmë me të parën. Le të shkruajmë fillimisht një provë që do të kontrollojë nëse pas dërgimit të mesazhit, kontrata inteligjente ruajti adresën e re në ruajtje. Ju lutemi vini re se në mesazh, përveç sportelit dhe adresës së re, ne transmetojmë edhe action Një numër i plotë 7-bit jo negativ, në varësi të tij, ne do të zgjedhim se si të përpunojmë mesazhin në kontratën inteligjente.

<b 0 32 u, 1 @ 7 u, new_owner_wc @  32 i, new_owner_account_id @ 256 u, b> message_to_sign !

Në test mund të shihni se si deserializohet ruajtja e kontratave inteligjente storage në Pesë. Deserializimi i variablave përshkruhet në dokumentacionin Fift.

Angazhoni lidhjen me brumë të shtuar.

Le të bëjmë testin dhe të sigurohemi që të dështojë. Tani le të shtojmë logjikën për të ndryshuar adresën e pronarit të lotarisë.

Në kontratën inteligjente ne vazhdojmë të analizojmë message, lexoni në action. Ju kujtojmë se do të kemi dy action: ndërroni adresën dhe dërgoni gram.

Më pas lexojmë adresën e re të pronarit të kontratës dhe e ruajmë në ruajtje.
Ne kryejmë testet dhe shohim që testi i tretë dështon. Ai rrëzohet për shkak të faktit se kontrata tani analizon gjithashtu 7 bit nga mesazhi, të cilat mungojnë në test. Shtoni një mesazh që nuk ekziston action. Le të bëjmë testet dhe të shohim që gjithçka kalon. Këtu angazhohen për ndryshime. E madhe.

Tani le të shkruajmë logjikën për dërgimin e numrit të caktuar të gramëve në adresën e ruajtur më parë.

Së pari, le të shkruajmë një test. Do të shkruajmë dy teste, një kur nuk ka ekuilibër të mjaftueshëm, i dyti kur gjithçka duhet të kalojë me sukses. Testet mund të shikohen në këtë angazhim.

Tani le të shtojmë kodin. Së pari, le të shkruajmë dy metoda ndihmëse. Metoda e parë e marrjes është të zbuloni bilancin aktual të një kontrate inteligjente.

int balance() inline_ref method_id {
    return get_balance().pair_first();
}

Dhe e dyta është për dërgimin e gramëve në një kontratë tjetër smart. E kopjova plotësisht këtë metodë nga një kontratë tjetër inteligjente.

() 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
}

Le t'i shtojmë këto dy metoda në kontratën inteligjente dhe të shkruajmë logjikën. Së pari, analizojmë numrin e gramëve nga mesazhi. Më pas kontrollojmë balancën, nëse nuk mjafton hedhim një përjashtim. Nëse gjithçka është në rregull, atëherë ne i dërgojmë gramët në adresën e ruajtur dhe përditësojmë numëruesin.

int amount_to_send = message~load_grams();
throw_if(36, amount_to_send + 500000000 > balance());
accept_message();
send_grams(owner_wc, owner_account_id, amount_to_send);
set_data(pack_state(stored_seqno + 1, pubkey, order_seqno, number_of_wins, incoming_amount, outgoing_amount, owner_wc, owner_account_id, orders));

Ja kështu duket si kontrata e zgjuar për momentin. Le të bëjmë testet dhe të sigurohemi që ato të kalojnë.

Nga rruga, një komision zbritet nga kontrata smart çdo herë për një mesazh të përpunuar. Në mënyrë që mesazhet e kontratës inteligjente të ekzekutojnë kërkesën, pas kontrolleve bazë duhet të telefononi accept_message().

Tani le të kalojmë te mesazhet e brendshme. Në fakt, ne do të pranojmë vetëm gram dhe do t'i kthejmë dyfishin e shumës lojtarit nëse ai fiton dhe një të tretën te pronari nëse humbet.

Së pari, le të shkruajmë një test të thjeshtë. Për ta bërë këtë, na duhet një adresë provë e kontratës inteligjente nga e cila supozohet se dërgojmë gram në kontratën inteligjente.

Adresa e kontratës inteligjente përbëhet nga dy numra, një numër i plotë 32-bit përgjegjës për zinxhirin e punës dhe një numër i plotë jo-negativ 256-bit numër unik i llogarisë në këtë zinxhir pune. Për shembull, -1 dhe 12345, kjo është adresa që do të ruajmë në një skedar.

Kam kopjuar funksionin për ruajtjen e adresës nga 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

Le të shohim se si funksionon funksioni, kjo do të japë një kuptim se si funksionon Fift. Nisni Fift në modalitetin interaktiv.

~/TON/build/crypto/fift -i 

Së pari ne shtyjmë -1, 12345 dhe emrin e skedarit të ardhshëm "sender.addr" në pirg:

-1 12345 "sender.addr" 

Hapi tjetër është ekzekutimi i funksionit -rot, i cili e zhvendos pirgun në atë mënyrë që në krye të pirgut të ketë një numër unik të kontratës inteligjente:

"sender.addr" -1 12345

256 u>B konverton një numër të plotë jo-negativ 256-bit në bajt.

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap ndërron dy elementet e sipërme të pirgut.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

32 i>B konverton një numër të plotë 32-bit në bajt.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ lidh dy sekuenca bajtash.

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

Përsëri swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

Dhe në fund bajtet shkruhen në skedar B>file. Pas kësaj pirgja jonë është bosh. Ne ndalemi Fift. Një skedar është krijuar në dosjen aktuale sender.addr. Le ta zhvendosim skedarin në dosjen e krijuar test/addresses/.

Le të shkruajmë një test të thjeshtë që do të dërgojë gram në një kontratë inteligjente. Këtu është angazhimi.

Tani le të shohim logjikën e shortit.

Gjëja e parë që bëjmë është të kontrollojmë mesazhin bounced apo jo nëse bounced, atëherë ne e injorojmë atë. bounced do të thotë që kontrata do të kthejë gram nëse ndodh ndonjë gabim. Ne nuk do të kthejmë gram nëse ndodh një gabim papritmas.

Ne kontrollojmë nëse bilanci është më pak se gjysmë gram, atëherë thjesht e pranojmë mesazhin dhe e shpërfillim atë.

Më pas, analizojmë adresën e kontratës inteligjente nga e cila erdhi mesazhi.

Ne lexojmë të dhënat nga ruajtja dhe më pas fshijmë bastet e vjetra nga historia nëse ka më shumë se njëzet prej tyre. Për lehtësi, kam shkruar tre funksione shtesë pack_order(), unpack_order(), remove_old_orders().

Tjetra, ne shikojmë nëse bilanci nuk është i mjaftueshëm për pagesën, atëherë konsiderojmë se ky nuk është një bast, por një rimbushje dhe ruajmë rimbushjen në orders.

Pastaj më në fund thelbi i kontratës së zgjuar.

Së pari, nëse lojtari humbet, e ruajmë atë në historikun e basteve dhe nëse shuma është më shumë se 3 gram, ia dërgojmë 1/3 pronarit të kontratës smart.

Nëse lojtari fiton, atëherë ne dërgojmë dyfishin e shumës në adresën e lojtarit dhe më pas ruajmë informacionin rreth bastit në histori.

() 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));
}

Kjo është e gjitha. Angazhimi përkatës.

Tani gjithçka që mbetet është e thjeshtë, le të krijojmë metoda të marra në mënyrë që të marrim informacione për gjendjen e kontratës nga bota e jashtme (në fakt, lexoni të dhënat nga ruajtja e kontratës së tyre inteligjente).

Le të shtojmë metodat e marra. Ne do të shkruajmë më poshtë se si të merrni informacion në lidhje me një kontratë inteligjente.

Kam harruar gjithashtu të shtoj kodin që do të përpunojë kërkesën e parë që ndodh kur publikohet një kontratë inteligjente. Angazhimi përkatës... Dhe më tej korrigjohet defekt me dërgimin e 1/3 të shumës në llogarinë e pronarit.

Hapi tjetër është publikimi i kontratës inteligjente. Le të krijojmë një dosje requests.

Për bazë kam marrë kodin e botimit simple-wallet-code.fc который mund të gjeni në depon zyrtare.

Diçka që ia vlen t'i kushtohet vëmendje. Ne gjenerojmë një ruajtje të kontratës inteligjente dhe një mesazh hyrës. Pas kësaj, gjenerohet adresa e kontratës inteligjente, domethënë adresa dihet edhe para publikimit në TON. Tjetra, ju duhet të dërgoni disa gramë në këtë adresë, dhe vetëm pas kësaj ju duhet të dërgoni një skedar me vetë kontratën inteligjente, pasi rrjeti merr një komision për ruajtjen e kontratës inteligjente dhe operacionet në të (validuesit që ruajnë dhe ekzekutojnë smart kontratat). Kodi mund të shihet këtu.

Më pas ekzekutojmë kodin e publikimit dhe marrim lottery-query.boc dosjen dhe adresën e kontratës inteligjente.

~/TON/build/crypto/fift -s requests/new-lottery.fif 0

Mos harroni të ruani skedarët e krijuar: lottery-query.boc, lottery.addr, lottery.pk.

Ndër të tjera, adresën e kontratës inteligjente do ta shohim në regjistrat e ekzekutimit.

new wallet address = 0:044910149dbeaf8eadbb2b28722e7d6a2dc6e264ec2f1d9bebd6fb209079bc2a 
(Saving address to file lottery.addr)
Non-bounceable address (for init): 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd
Bounceable address (for later access): kQAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KpFY

Sa për qejf, le t'i bëjmë një kërkesë TON-it

$ ./lite-client/lite-client -C ton-lite-client-test1.config.json 
getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Dhe do të shohim që llogaria me këtë adresë është bosh.

account state is empty

Ne dërgojmë në adresën 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 gram dhe pas disa sekondash ekzekutojmë të njëjtën komandë. Për të dërguar gram unë përdor portofolin zyrtar, dhe mund t'i kërkoni dikujt nga chat-i për gram provë, për të cilin do të flas në fund të artikullit.

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Duket si e pa inicializuar (state:account_uninit) një kontratë inteligjente me të njëjtën adresë dhe një bilanc prej 1 000 000 000 nanogramësh.

account state is (account
  addr:(addr_std
    anycast:nothing workchain_id:0 address:x044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A)
  storage_stat:(storage_info
    used:(storage_used
      cells:(var_uint len:1 value:1)
      bits:(var_uint len:1 value:103)
      public_cells:(var_uint len:0 value:0)) last_paid:1583257959
    due_payment:nothing)
  storage:(account_storage last_trans_lt:3825478000002
    balance:(currencies
      grams:(nanograms
        amount:(var_uint len:4 value:2000000000))
      other:(extra_currencies
        dict:hme_empty))
    state:account_uninit))
x{C00044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A20259C2F2F4CB3800000DEAC10776091DCD650004_}
last transaction lt = 3825478000001 hash = B043616AE016682699477FFF01E6E903878CDFD6846042BA1BFC64775E7AC6C4
account balance is 2000000000ng

Tani le të publikojmë kontratën inteligjente. Le të hapim lite-client dhe të ekzekutojmë.

> sendfile lottery-query.boc
[ 1][t 2][1583008371.631410122][lite-client.cpp:966][!testnode] sending query from file lottery-query.boc
[ 3][t 1][1583008371.828550100][lite-client.cpp:976][!query]    external message status is 1 

Le të kontrollojmë që kontrata është publikuar.

> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Ndër të tjera marrim.

  storage:(account_storage last_trans_lt:3825499000002
    balance:(currencies
      grams:(nanograms
        amount:(var_uint len:4 value:1987150999))
      other:(extra_currencies
        dict:hme_empty))
    state:(account_active

Ne e shohim atë account_active.

Angazhimi përkatës me ndryshime këtu.

Tani le të krijojmë kërkesa për të bashkëvepruar me kontratën inteligjente.

Më saktë, të parën për ndërrimin e adresës do ta lëmë si punë të pavarur dhe të dytën për dërgimin e gramave në adresën e pronarit. Në fakt, do të na duhet të bëjmë të njëjtën gjë si në testin për dërgimin e grameve.

Ky është mesazhi që do t'i dërgojmë kontratës smart, ku msg_seqno 165, action 2 dhe 9.5 gram për dërgim.

<b 165 32 u, 2 7 u, 9500000000 Gram, b>

Mos harroni të nënshkruani mesazhin me çelësin tuaj privat lottery.pk, e cila u krijua më herët gjatë krijimit të kontratës inteligjente. Këtu është angazhimi përkatës.

Marrja e informacionit nga një kontratë inteligjente duke përdorur metodat e marra

Tani le të shohim se si të ekzekutojmë metodat e marrjes së kontratës inteligjente.

Nisja lite-client dhe ekzekutoni metodat e marra që kemi shkruar.

$ ./lite-client/lite-client -C ton-lite-client-test1.config.json
> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd balance
arguments:  [ 104128 ] 
result:  [ 64633878952 ] 
...

В result përmban vlerën që kthen funksioni balance() nga kontrata jonë e zgjuar.
Ne do të bëjmë të njëjtën gjë për disa metoda të tjera.

> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_seqno
...
arguments:  [ 77871 ] 
result:  [ 1 ] 

Le të kërkojmë historinë tuaj të basteve.

> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_orders
...
arguments:  [ 67442 ] 
result:  [ ([0 1 1583258284 10000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [1 3 1583258347 4000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [2 1 1583259901 50000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308]) ] 

Ne do të përdorim lite-client dhe do të marrim metoda për të shfaqur informacione në lidhje me kontratën inteligjente në sajt.

Shfaqja e të dhënave të kontratës inteligjente në faqen e internetit

Shkrova një faqe interneti të thjeshtë në Python për të shfaqur të dhënat nga kontrata inteligjente në një mënyrë të përshtatshme. Këtu nuk do të ndalem në të në detaje dhe do të publikoj faqen në një angazhim.

Kërkesat për TON bëhen nga Python me ndihmën e lite-client. Për lehtësi, faqja është e paketuar në Docker dhe e publikuar në Google Cloud. Lidhje.

Duke u përpjekur

Tani le të përpiqemi të dërgojmë gram atje për rimbushje nga qese. Ne do të dërgojmë 40 gram. Dhe le të bëjmë disa baste për qartësi. Ne shohim që faqja tregon historinë e basteve, përqindjen aktuale të fitimeve dhe informacione të tjera të dobishme.

Ne shohimse fituam të parën, humbëm të dytën.

pasthënje

Artikulli doli të ishte shumë më i gjatë nga sa prisja, mbase mund të ishte më i shkurtër, ose ndoshta vetëm për një person që nuk di asgjë për TON dhe dëshiron të shkruajë dhe publikojë një kontratë inteligjente jo aq të thjeshtë me aftësinë për të ndërvepruar me atë. Ndoshta disa gjëra mund të shpjegoheshin më thjeshtë.

Ndoshta disa aspekte të zbatimit mund të ishin bërë në mënyrë më efikase dhe elegante, por atëherë do të duhej edhe më shumë kohë për të përgatitur artikullin. Është gjithashtu e mundur që kam bërë një gabim diku ose nuk kam kuptuar diçka, kështu që nëse jeni duke bërë diçka serioze, duhet të mbështeteni në dokumentacionin zyrtar ose në depo zyrtare me kodin TON.

Duhet të theksohet se duke qenë se vetë TON është ende në fazën aktive të zhvillimit, mund të ndodhin ndryshime që do të thyejnë ndonjë nga hapat në këtë artikull (që ndodhi gjatë kohës që po shkruaja, tashmë është korrigjuar), por qasja e përgjithshme është nuk ka gjasa të ndryshojë.

Nuk do të flas për të ardhmen e TON. Ndoshta platforma do të bëhet diçka e madhe dhe ne duhet të kalojmë kohë duke e studiuar atë dhe të mbushim një vend me produktet tona tani.

Ekziston edhe Libra nga Facebook, e cila ka një audiencë potenciale përdoruesish më të madh se TON. Unë nuk di pothuajse asgjë për Libra, duke gjykuar nga forumi ka shumë më tepër aktivitet atje sesa në komunitetin TON. Edhe pse zhvilluesit dhe komuniteti i TON janë më shumë si nëntokë, gjë që është gjithashtu e lezetshme.

Referencat

  1. Dokumentacioni zyrtar TON: https://test.ton.org
  2. Depoja zyrtare e TON: https://github.com/ton-blockchain/ton
  3. Portofoli zyrtar për platforma të ndryshme: https://wallet.ton.org
  4. Depoja e kontratave inteligjente nga ky artikull: https://github.com/raiym/astonished
  5. Lidhja me faqen e internetit të kontratës inteligjente: https://ton-lottery.appspot.com
  6. Depoja për shtesën për Kodin Visual Studio për FunC: https://github.com/raiym/func-visual-studio-plugin
  7. Bisedoni për TON në Telegram, i cili vërtet ndihmoi për ta kuptuar atë në fazën fillestare. Unë mendoj se nuk do të jetë gabim nëse them se të gjithë ata që kanë shkruar diçka për TON janë atje. Aty mund të kërkosh edhe gram provë. https://t.me/tondev_ru
  8. Një bisedë tjetër rreth TON në të cilën gjeta informacione të dobishme: https://t.me/TONgramDev
  9. Faza e parë e konkursit: https://contest.com/blockchain
  10. Faza e dytë e konkursit: https://contest.com/blockchain-2

Burimi: www.habr.com

Bleni një host të besueshëm për faqet me mbrojtje DDoS, serverë VPS VDS 🔥 Bleni hosting të besueshëm të faqeve të internetit me mbrojtje DDoS, servera VPS VDS | ProHoster