Telegram Open Network (TON) жүйесінде смарт келісімшартты қалай жазу және жариялау туралы

TON-да смарт келісімшартты қалай жазу және жариялау туралы

Бұл мақала не туралы?

Мақалада мен Telegram блокчейнінің бірінші (екіден) байқауына қалай қатысқаным, жүлде алмағаным және ол ұмытылмас үшін және, мүмкін, көмектесу үшін өз тәжірибемді мақалаға жазуды шешкенім туралы айтатын боламын. біреу.

Мен дерексіз кодты жазғым келмегендіктен, бірақ жұмыс істейтін бірдеңе жасау үшін, мақала үшін мен жедел лотереяға ақылды келісім-шарт жаздым және аралық жадты пайдаланбай, смарт келісімшарт деректерін тікелей TON-дан көрсететін веб-сайт.

Мақала TON-да алғашқы смарт келісімшарт жасағысы келетіндерге пайдалы болады, бірақ неден бастау керектігін білмейді.

Мысал ретінде лотереяны қолдана отырып, мен ортаны орнатудан бастап смарт келісімшартты жариялауға, онымен өзара әрекеттесуге және деректерді қабылдауға және жариялауға арналған веб-сайтты жазуға дейін барамын.

Байқауға қатысу туралы

Өткен жылдың қазан айында Telegram жаңа тілдермен блокчейн байқауын жариялады Fift и FunC. Ұсынылған бес ақылды келісімшарттың кез келгенін жазудан таңдау керек болды. Болашақта басқа ештеңе жазудың қажеті болмаса да, басқаша істеп, тіл үйреніп, бірдеңе жасасам жақсы болар еді деп ойладым. Сонымен қатар, тақырып үнемі аузында.

Менің ақылды келісімшарттарды жасау тәжірибесі болмағанын айту керек.

Мен соңына дейін қатысуды жоспарладым, содан кейін шолу мақаласын жазуды жоспарладым, бірақ біріншісінде бірден сәтсіздікке ұшырадым. I әмиян жазды көп қолтаңба қосулы FunC және ол жалпы жұмыс істеді. Мен оны негізге алдым Solidity туралы ақылды келісім-шарт.

Ол кезде мен жүлделі орын алу үшін бұл жеткілікті деп ойладым. Нәтижесінде 40 қатысушының 60-қа жуығы жүлдегер атанып, мен олардың қатарында болмадым. Жалпы, бұл жерде ешнәрсе жоқ, бірақ мені бір нәрсе алаңдатты. Нәтижелерді жариялау кезінде менің келісімшартым бойынша тестілеуді қарау жасалмады, мен чатқа қатысушылардан басқа біреу жоқ па деп сұрадым, жоқ жоқ.

Менің хабарламаларыма назар аударған сияқты, екі күннен кейін судьялар түсініктеме жариялады және мен олар қазылар алқасы кезінде менің ақылды келісім-шартымды байқаусызда өткізіп алды ма, әлде бұл өте нашар, сондықтан түсініктеме қажет емес деп ойладым ба әлі түсінбеймін. Парақшада сұрақ қойдым, бірақ жауап алмадым. Кім баға бергені құпия болмаса да, жеке хабарлама жазудың қажеті жоқ деп санадым.

Түсінуге көп уақыт жұмсалды, сондықтан мақала жазуды жөн көрді. Әзірге ақпарат көп болмағандықтан, мақала барлық қызығушылық танытқандар үшін уақытты үнемдеуге көмектеседі.

TON-дағы смарт келісімшарттар тұжырымдамасы

Бірдеңе жазбас бұрын, бұл нәрсеге қай жағынан келу керектігін анықтау керек. Сондықтан қазір жүйенің қандай бөліктерден тұратынын айтып беремін. Дәлірек айтқанда, кем дегенде қандай да бір еңбек шартын жазу үшін қандай бөліктерді білу керек.

Біз ақылды келісімшарт жазуға және онымен жұмыс істеуге назар аударамыз TON Virtual Machine (TVM), Fift и FunC, сондықтан мақала кәдімгі бағдарламаның дамуының сипаттамасына көбірек ұқсайды. Біз бұл жерде платформаның өзі қалай жұмыс істейтініне тоқталмаймыз.

Жалпы оның қалай жұмыс істейтіні туралы TVM және тіл Fift жақсы ресми құжаттама бар. Байқауға қатысып, қазіргі келісім-шартты жазу барысында мен оған жиі жүгінетінмін.

Смарт келісімшарттар жазылатын негізгі тіл FunC. Қазіргі уақытта бұл туралы ешқандай құжаттама жоқ, сондықтан бірдеңе жазу үшін ресми репозиторийден смарт-келісімшарттардың мысалдарын және сол жерде тілдің өзін енгізуін зерттеу керек, сонымен қатар соңғы екі смарт келісімшарттардың мысалдарын қарауға болады. жарыстар. Мақаланың соңындағы сілтемелер.

Біз қазірдің өзінде ақылды келісімшарт жазды делік FunC, содан кейін біз кодты Fift ассемблеріне құрастырамыз.

Құрастырылған смарт келісімшарт әлі жариялануы керек. Мұны істеу үшін сізге функция жазу керек Fift, ол кіріс ретінде смарт келісімшарт кодын және кейбір басқа параметрлерді қабылдайды, ал шығыс кеңейтімі бар файл болады. .boc («ұяшықтар қапшығы» дегенді білдіреді) және оны қалай жазуымызға байланысты смарт келісімшарт коды негізінде жасалған жеке кілт пен мекенжай. Сіз әлі жарияланбаған смарт келісімшарттың мекенжайына грамм жібере аласыз.

Смарт келісімшартты TON-да жариялау үшін алынды .boc файл жеңіл клиент арқылы блокчейнге жіберілуі керек (төменде бұл туралы толығырақ). Бірақ жарияламас бұрын граммдарды жасалған мекенжайға тасымалдау керек, әйтпесе смарт келісімшарт жарияланбайды. Жарияланғаннан кейін смарт келісімшартқа сырттан (мысалы, жеңіл клиентті пайдалану) немесе ішінен хабарламалар жіберу арқылы (мысалы, бір смарт келісімшарт екіншісіне TON ішінде хабарлама жібереді) әрекеттесе аласыз.

Кодтың қалай жарияланғанын түсінгеннен кейін, ол оңайырақ болады. Біз не жазғымыз келетінін және бағдарламамыздың қалай жұмыс істейтінін шамамен білеміз. Жазу кезінде біз мұның бұрыннан бар смарт келісім-шарттарда қалай енгізілгенін іздейміз немесе іске асыру кодын қарастырамыз Fift и FunC ресми репозиторийде немесе ресми құжаттамадан қараңыз.

Мен жарыстың барлық қатысушылары мен Telegram қызметкерлері жиналған Telegram чатында кілт сөздерді жиі іздедім, сондықтан жарыс кезінде барлығы сонда жиналып, Fift пен FunC-ті талқылай бастады. Мақаланың соңындағы сілтеме.

Теориядан практикаға көшетін кез келді.

TON-мен жұмыс істеу үшін ортаны дайындау

Мен MacOS жүйесіндегі мақалада сипатталғанның бәрін жасадым және оны Docker жүйесіндегі таза Ubuntu 18.04 LTS жүйесінде екі рет тексердім.

Сізге қажет бірінші нәрсе - жүктеп алу және орнату lite-client оның көмегімен сіз TON-қа сұрау жібере аласыз.

Ресми веб-сайттағы нұсқаулар орнату процесін егжей-тегжейлі және анық сипаттайды және кейбір мәліметтерді өткізіп жібереді. Мұнда біз нұсқауларды орындаймыз, жол бойында жетіспейтін тәуелділіктерді орнатамыз. Мен әр жобаны өзім құрастырған жоқпын және ресми Ubuntu репозиторийінен орнатқан жоқпын (MacOS жүйесінде мен пайдаландым 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 

Барлық тәуелділіктер орнатылғаннан кейін орнатуға болады lite-client, Fift, FunC.

Біріншіден, біз TON репозиторийін оның тәуелділіктерімен бірге клондаймыз. Ыңғайлы болу үшін біз бәрін қалтада жасаймыз ~/TON.

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

Репозиторий іске асыруларды да сақтайды Fift и FunC.

Енді жобаны құрастыруға дайынбыз. Репозиторий коды қалтаға клондалады ~/TON/ton. The ~/TON қалта жасаңыз build және оған жобаны жинаңыз.

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

Біз ақылды келісім-шарт жазатын болғандықтан, бізге тек қана қажет емес lite-clientбірақ Fift с FunC, сондықтан бәрін құрастырайық. Бұл жылдам процесс емес, сондықтан біз күтеміз.

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

Әрі қарай, түйін туралы деректерді қамтитын конфигурация файлын жүктеп алыңыз lite-client қосылатын болады.

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

TON-ға алғашқы сұраныстарды жасау

Енді іске қосайық lite-client.

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

Егер құрастыру сәтті болса, іске қосқаннан кейін сіз жеңіл клиенттің түйінге қосылу журналын көресіз.

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

Пәрменді іске қосуға болады help және қандай пәрмендердің қолжетімді екенін қараңыз.

help

Осы мақалада қолданатын пәрмендерді тізіп көрейік.

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-методы смартконтракта. 

Енді шарттың өзін жазуға дайынбыз.

Реализация

Идея

Жоғарыда жазғанымдай, біз жазып жатқан смарт келісімшарт лотерея.

Сонымен қатар, бұл билет сатып алып, бір сағат, күн немесе ай күту керек лотерея емес, пайдаланушы келісім-шарт мекенжайына аударатын лезде ойын. N грамм, және оны бірден қайтарады 2 * N грамм немесе жоғалтады. Біз ұту ықтималдығын шамамен 40% жасаймыз. Егер төлеуге грамм жеткіліксіз болса, онда біз транзакцияны толықтыру ретінде қарастырамыз.

Сонымен қатар, ұтыс тігулерді нақты уақыт режимінде және ыңғайлы түрде көруге болатыны маңызды, сондықтан пайдаланушы өзінің ұтқанын немесе ұтылғанын бірден түсіне алады. Сондықтан сізге тікелей TON-дан ставкалар мен нәтижелерді көрсететін веб-сайт жасау керек.

Ақылды келісімшартты жазу

Ыңғайлы болу үшін мен FunC кодын бөлектедім; плагинді Visual Studio Code іздеуінде табуға және орнатуға болады; кенеттен бірдеңе қосқыңыз келсе, мен плагинді жалпыға қолжетімді еттім. Сондай-ақ, біреу бұрын Fift-пен жұмыс істеу үшін плагин жасаған, сіз оны орнатып, оны VSC ішінен таба аласыз.

Аралық нәтижелерді беретін репозиторийді дереу жасайық.

Өмірімізді жеңілдету үшін біз смарт келісімшартты жазып, оны дайын болғанша жергілікті жерде сынаймыз. Осыдан кейін ғана біз оны ТОН-да шығарамыз.

Смарт келісімшартта қол жеткізуге болатын екі сыртқы әдіс бар. Біріншіден, recv_external() бұл функция келісім-шартқа сұрау сыртқы әлемнен келгенде орындалады, яғни TON емес, мысалы, біз өзіміз хабарлама жасап, оны lite-клиент арқылы жіберген кезде орындалады. Екіншіден, recv_internal() Бұл TON ішінде кез келген келісімшарт біздікіне қатысты. Екі жағдайда да функцияға параметрлерді беруге болады.

Жарияланған жағдайда жұмыс істейтін қарапайым мысалдан бастайық, бірақ онда функционалдық жүктеме жоқ.

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

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

Мұнда біз оның не екенін түсіндіруіміз керек slice. TON Blockchain жүйесінде сақталған барлық деректер жинақ болып табылады TVM cell немесе қарапайым cell, мұндай ұяшықта 1023 битке дейін деректерді және басқа ұяшықтарға 4 сілтемеге дейін сақтауға болады.

TVM cell slice немесе slice бұл бар бір бөлігі cell талдау үшін пайдаланылады, ол кейінірек анық болады. Біз үшін ең бастысы трансфер жасай аламыз slice және хабарлама түріне байланысты деректерді өңдеңіз recv_external() немесе recv_internal().

impure — функцияның смарт келісімшарт деректерін өзгертетінін көрсететін кілт сөз.

Келісімшарт кодын сақтайық lottery-code.fc және құрастыру.

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

Жалаушалардың мағынасын пәрмен арқылы көруге болады

~/TON/build/crypto/func -help

Біз Fift ассемблер кодын құрастырдық 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

Оны жергілікті жерде іске қосуға болады, ол үшін біз қоршаған ортаны дайындаймыз.

Бірінші жолдың қосылатынын ескеріңіз Asm.fif, бұл Fift ассемблері үшін Fift тілінде жазылған код.

Біз смарт келісімшартты жергілікті түрде іске қосып, сынағымыз келгендіктен, біз файл жасаймыз lottery-test-suite.fif және құрастырылған кодты көшіріп, ондағы соңғы жолды ауыстырыңыз, ол смарт келісімшарт кодын тұрақты мәнге жазады. codeсодан кейін оны виртуалды машинаға тасымалдау үшін:

"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

Әзірге түсінікті сияқты, енді сол файлға 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 біз мәтінмәнді, яғни TVM (немесе желі күйі) іске қосылатын деректерді жазамыз. Тіпті байқау барысында әзірлеушілердің бірі қалай жасау керектігін көрсетті c7 және көшіріп алдым. Бұл мақалада бізге өзгерту қажет болуы мүмкін rand_seed кездейсоқ санның генерациясы оған байланысты болғандықтан және өзгертілмесе, сол сан әр уақытта қайтарылады.

recv_internal и recv_external 0 және -1 мәндері бар тұрақтылар смарт келісімшарттағы сәйкес функцияларды шақыруға жауапты болады.

Енді біз бос смарт келісімшартымыз үшін бірінші сынақты жасауға дайынбыз. Түсінікті болу үшін қазір біз барлық сынақтарды бір файлға қосамыз lottery-test-suite.fif.

Айнымалыны жасайық storage және оған бос біреуін жазыңыз cell, бұл смарт келісімшарт қоймасы болады.

message Бұл смарт контактіге сырттан жіберетін хабарлама. Оны да әзірше бос қыламыз.

variable storage 
<b b> storage ! 

variable message 
<b b> message ! 

Тұрақтылар мен айнымалыларды дайындап болған соң, пәрмен арқылы TVM іске қосамыз runvmctx және жасалған параметрлерді енгізуге жіберіңіз.

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

Соңында біз жетістікке жетеміз бұл сияқты үшін аралық код Fift.

Енді алынған кодты іске қоса аламыз.

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

Бағдарлама қатесіз жұмыс істеуі керек және нәтижеде біз орындау журналын көреміз:

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

Керемет, біз смарт келісімшарттың бірінші жұмыс нұсқасын жаздық.

Енді біз функционалдылықты қосуымыз керек. Алдымен сыртқы әлемнен келетін хабарламаларды қарастырайық recv_external()

Әзірлеуші ​​өзі келісім-шарт қабылдай алатын хабарлама пішімін таңдайды.

Бірақ әдетте

  • біріншіден, біз келісім-шартымызды сыртқы әлемнен қорғағымыз келеді және оны тек келісімшарт иесі оған сыртқы хабарламалар жібере алатындай етіп жасағымыз келеді.
  • екіншіден, біз TON-ға жарамды хабарлама жіберген кезде, біз мұның дәл бір рет болғанын қалаймыз және сол хабарламаны қайта жіберген кезде, смарт келісімшарт оны қабылдамайды.

Сонымен, әрбір дерлік келісімшарт осы екі мәселені шешеді, өйткені біздің келісім-шарт сыртқы хабарламаларды қабылдайды, біз онымен де айналысуымыз керек.

Біз мұны кері тәртіпте жасаймыз. Біріншіден, мәселені қайталау арқылы шешейік, егер келісім-шарт мұндай хабарламаны алып, оны өңдеген болса, ол оны екінші рет орындамайды. Содан кейін біз мәселені тек белгілі бір адамдар тобы смарт келісімшартқа хабарлама жібере алатындай шешеміз.

Қайталанатын хабарламалармен мәселені шешудің әртүрлі жолдары бар. Міне, біз мұны қалай жасаймыз. Смарт келісім-шартта біз 0 бастапқы мәні бар қабылданған хабарлардың есептегішін инициализациялаймыз. Смарт келісімшартқа әрбір хабарламада ағымдағы есептегіш мәнді қосамыз. Хабарламадағы санауыш мәні смарт келісімшарттағы мәнге сәйкес келмесе, біз оны өңдемейміз, егер солай болса, біз оны өңдеп, смарт келісімдегі есептегішті 1-ге көбейтеміз.

дегенге оралайық lottery-test-suite.fif және оған екінші сынақты қосыңыз. Егер біз қате нөмірді жіберсек, код ерекше жағдайды тудыруы керек. Мысалы, келісім-шарт деректерінде 166 сақталсын, ал біз 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"

Іске кірісейік.

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

Және тест қатемен орындалғанын көреміз.

[ 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

Бұл кезеңде lottery-test-suite.fif ұқсауы керек байланыс.

Енді смарт келісімшартқа қарсы логиканы қосамыз 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 біз жіберген хабарлама жатыр.

Біз жасайтын бірінші нәрсе - хабарламада деректер бар-жоғын тексеру, егер жоқ болса, біз жай ғана шығамыз.

Әрі қарай біз хабарламаны талдаймыз. in_msg~load_uint(32) 165, 32-биттік нөмірді жүктейді unsigned int жіберілген хабарламадан.

Содан кейін біз смарт келісімшарт қоймасынан 32 бит жүктейміз. Жүктелген санның өткенге сәйкес келетінін тексереміз, егер жоқ болса, біз ерекшелік жасаймыз. Біздің жағдайда, біз матчтан өтіп жатқандықтан, ерекше жағдайды тастау керек.

Енді компиляция жасайық.

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

Алынған кодты келесіге көшіріңіз lottery-test-suite.fif, соңғы жолды ауыстыруды ұмытпаңыз.

Біз сынақтан өткенін тексереміз:

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

Мұнда Ағымдағы нәтижелермен сәйкес міндеттемені көре аласыз.

Смарт келісім-шарттың құрастырылған кодын сынақтары бар файлға үнемі көшіру ыңғайсыз екенін ескеріңіз, сондықтан біз кодты біз үшін тұрақты мәнге жазатын сценарий жазамыз және біз құрастырылған кодты тесттерімізге қосамыз. "include".

Жоба қалтасында файл жасаңыз build.sh келесі мазмұнмен.

#!/bin/bash

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

Оны орындалатын етіп жасайық.

chmod +x ./build.sh

Енді келісімшартты құрастыру үшін сценарийді іске қосыңыз. Бірақ бұған қоса, біз оны тұрақтыға жазуымыз керек code. Сондықтан біз жаңа файл жасаймыз lotter-compiled-for-test.fif, біз оны файлға қосамыз lottery-test-suite.fif.

sh-ге скрипт кодын қосамыз, ол жай ғана құрастырылған файлды қайталайды lotter-compiled-for-test.fif және ондағы соңғы жолды өзгертіңіз.

# 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

Енді тексеру үшін алынған сценарийді іске қосамыз және файл жасалады lottery-compiled-for-test.fif, біз оны өзімізге қосамыз lottery-test-suite.fif

В lottery-test-suite.fif келісімшарт кодын жойып, жолды қосыңыз "lottery-compiled-for-test.fif" include.

Біз олардың өткенін тексеру үшін сынақтарды жүргіземіз.

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

Керемет, енді сынақтарды іске қосуды автоматтандыру үшін файлды жасайық test.sh, ол алдымен орындалады build.sh, содан кейін сынақтарды орындаңыз.

touch test.sh
chmod +x test.sh

Ішінде жазамыз

./build.sh 

echo "nCompilation completedn"

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

Қанекей мынаны істейік test.sh және сынақтардың жұмыс істейтініне көз жеткізу үшін оны іске қосыңыз.

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

Біз келісім-шарттың құрастырылғанын және сынақтардың орындалғанын тексереміз.

Тамаша, қазір іске қосуда test.sh Тесттер құрастырылады және дереу орындалады. Міне сілтемесі міндеттеу.

Жарайды, жалғастырмас бұрын, ыңғайлы болу үшін тағы бір нәрсе жасайық.

Қалта жасайық build онда біз көшірілген келісім-шартты және оның тұрақтыға жазылған клонын сақтаймыз lottery-compiled.fif, lottery-compiled-for-test.fif. Сонымен қатар қалта жасайық test сынақ файлы қайда сақталады? lottery-test-suite.fif және ықтимал басқа қолдау көрсететін файлдар. Тиісті өзгерістерге сілтеме.

Смарт келісімшартты дамытуды жалғастырайық.

Содан кейін біз дұрыс нөмірді жіберген кезде хабарламаның қабылданғанын және есептегіштің дүкенде жаңартылғанын тексеретін сынақ болуы керек. Бірақ біз мұны кейінірек жасаймыз.

Енді смарт келісімшартта қандай деректер құрылымын және қандай деректерді сақтау керек екенін ойластырайық.

Мен біз сақтайтын барлық нәрсені сипаттаймын.

`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` переменная типа словарь, хранит последние двадцать ставок. 

Әрі қарай екі функцияны жазу керек. Біріншісін шақырайық pack_state(), ол кейіннен смарт келісімшарт қоймасында сақтау үшін деректерді жинайды. Екіншісін шақырайық unpack_state() жадтан деректерді оқиды және қайтарады.

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

Біз бұл екі функцияны смарт келісімшарттың басына қосамыз. Бұл нәтиже береді бұл сияқты аралық нәтиже.

Деректерді сақтау үшін кірістірілген функцияны шақыру керек set_data() және ол деректерді жазады pack_state() смарт келісімшарт қоймасында.

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

Енді бізде деректерді жазу және оқу үшін ыңғайлы функциялар бар, біз әрі қарай жүре аламыз.

Сырттан келетін хабарламаға келісім-шарт иесінің (немесе жабық кілтке рұқсаты бар басқа пайдаланушы) қол қойғанын тексеру керек.

Смарт келісім-шартты жариялағанда, біз оны болашақта пайдалану үшін сақталатын сақтаудағы қажетті деректермен инициализациялай аламыз. Кіріс хабарламаға сәйкес жеке кілтпен қол қойылғанын тексеру үшін біз ашық кілтті сол жерде жазамыз.

Жалғастырмас бұрын жеке кілт жасап, оны жазайық test/keys/owner.pk. Ол үшін Fift бағдарламасын интерактивті режимде іске қосып, төрт команданы орындаймыз.

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

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

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

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

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

Қалта жасайық keys қалтаның ішінде test және сол жерге жеке кілтті жазыңыз.

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

Ағымдағы қалтадағы файлды көреміз owner.pk.

Біз ашық кілтті стектен алып тастаймыз және қажет болғанда оны жеке кілттен аламыз.

Енді қолтаңбаны тексеруді жазуымыз керек. Тесттен бастайық. Алдымен біз функцияны пайдаланып файлдан жеке кілтті оқимыз file>B және оны айнымалыға жазыңыз owner_private_key, содан кейін функцияны пайдаланыңыз priv>pub жеке кілтті ашық кілтке түрлендіріңіз және нәтижені жазыңыз 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 !

Бізге екі кілт керек болады.

Функциядағыдай реттілікпен ерікті деректермен смарт келісімшарт қоймасын инициализациялаймыз pack_state()және оны айнымалыға жазыңыз 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 !

Әрі қарай, біз қол қойылған хабарламаны құрастырамыз, онда тек қолтаңба мен есептегіш мәні болады.

Алдымен біз жібергіміз келетін деректерді жасаймыз, содан кейін оған жеке кілтпен қол қоямыз және соңында қол қойылған хабарламаны жасаймыз.

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 !  

Нәтижесінде біз смарт келісімшартқа жіберетін хабар айнымалыға жазылады message_to_send, функциялар туралы hashu, ed25519_sign_uint оқи аласыз Fift құжаттамасында.

Ал сынақты орындау үшін біз қайтадан қоңырау шаламыз.

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

Міне осылай Бұл кезеңде сынақтары бар файл келесідей болуы керек.

Сынақты іске қосып көрейік және ол сәтсіз болады, сондықтан біз смарт келісімшартты осы пішімдегі хабарларды қабылдап, қолтаңбаны тексере алатындай етіп өзгертеміз.

Алдымен хабарламадан қолтаңбаның 512 биттерін санап, оны айнымалыға жазамыз, содан кейін санауыш айнымалының 32 битін санаймыз.

Бізде смарт келісімшарт қоймасынан деректерді оқу функциясы болғандықтан, біз оны қолданамыз.

Одан әрі жадпен тасымалданатын есептегішті тексеру және қолтаңбаны тексеру. Егер бірдеңе сәйкес келмесе, біз сәйкес кодпен ерекше жағдайды шығарамыз.

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

Тиісті міндеттеме мұнда.

Тесттерді орындап көрейік және екінші сынақ сәтсіз аяқталды. Екі себепке байланысты хабарда бит жеткіліксіз және жадта жеткіліксіз, сондықтан талдау кезінде код бұзылады. Біз жіберіп жатқан хабарға қолтаңба қосып, соңғы сынақтан сақтауды көшіруіміз керек.

Екінші сынақта біз хабарлама қолтаңбасын қосамыз және смарт келісімшарт қоймасын өзгертеміз. Міне осылай сынақтары бар файл қазіргі уақытта сияқты.

Төртінші сынақты жазайық, онда біз басқа біреудің жеке кілтімен қол қойылған хабарлама жібереміз. Басқа жеке кілт жасап, оны файлға сақтайық not-owner.pk. Біз хабарламаға осы жеке кілтпен қол қоямыз. Тесттерді орындап, барлық сынақтардың өткеніне көз жеткізейік. Міндеттеме беру осы сәтте.

Енді біз ақылды келісімшарт логикасын енгізуге көшеміз.
В recv_external() біз хабарлардың екі түрін қабылдаймыз.

Біздің келісімшартта ойыншылардың шығыны жинақталатындықтан, бұл ақша лотереяны жасаушыға аударылуы керек. Лотереяны жасаушының әмиян мекен-жайы шарт жасалған кезде қоймада жазылады.

Қалай болғанда да, біз жоғалтқандардың граммдарын жіберетін мекенжайды өзгерту мүмкіндігі қажет. Біз сондай-ақ лотереядан иесінің мекен-жайына грамм жібере алуымыз керек.

Біріншіден бастайық. Алдымен хабарды жібергеннен кейін смарт келісімшарт жаңа мекенжайды жадта сақтағанын тексеретін сынақ жазайық. Хабарламада есептегіш пен жаңа мекен-жайдан басқа біз жіберетінімізді ескеріңіз action 7-биттік бүтін теріс емес сан, оған байланысты біз смарт келісім-шартта хабарламаны өңдеу жолын таңдаймыз.

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

Сынақта смарт-контракт қоймасының сериядан қалай шығарылғанын көруге болады storage бесте. Айнымалыларды сериядан шығару Fift құжаттамасында сипатталған.

Сілтемені бекіту қосылған қамырмен.

Сынақты іске қосып, оның сәтсіздігіне көз жеткізейік. Енді лотерея иесінің мекен-жайын өзгерту логикасын қосайық.

Смарт келісімшартта біз талдауды жалғастырамыз message, оқыңыз action. Естеріңізге сала кетейік, бізде екі болады action: мекенжайды өзгерту және грамм жіберу.

Содан кейін біз келісімшарт иесінің жаңа мекенжайын оқып, оны қоймаға сақтаймыз.
Біз сынақтарды орындаймыз және үшінші сынақтың сәтсіз екенін көреміз. Келісімшарт енді сынақта жетіспейтін хабарламадан 7 бит қосымша талдайтынына байланысты ол бұзылады. Хабарға жоқты қосыңыз action. Тесттерді орындап, бәрі өткенін көрейік. осында өзгерістер енгізуге міндеттенеді. Тамаша.

Енді бұрын сақталған мекенжайға көрсетілген грамм санын жіберу логикасын жазайық.

Алдымен тест жазып алайық. Біз екі сынақ жазамыз, біреуі теңгерім жеткіліксіз болғанда, екіншісі бәрі сәтті өтуі керек. Тесттерді көруге болады осы міндеттемеде.

Енді кодты қосамыз. Алдымен екі көмекші әдісті жазайық. Бірінші алу әдісі - смарт келісімшарттың ағымдағы балансын білу.

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

Ал екіншісі басқа смарт келісім-шартқа грамм жіберуге арналған. Мен бұл әдісті басқа смарт келісімшарттан толығымен көшіріп алдым.

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

Осы екі әдісті смарт келісімшартқа қосып, логиканы жазайық. Алдымен біз хабарламадағы грамм санын талдаймыз. Содан кейін біз балансты тексереміз, егер ол жеткіліксіз болса, біз ерекшелік жасаймыз. Егер бәрі жақсы болса, онда біз граммдарды сақталған мекенжайға жібереміз және есептегішті жаңартамыз.

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

Міне осылай қазіргі уақытта ақылды келісімшартқа ұқсайды. Тесттерді орындап, олардың өткеніне көз жеткізейік.

Айтпақшы, өңделген хабарлама үшін смарт келісімшарттан комиссия алынады. Смарт келісімшарт хабарламалары сұрауды орындау үшін негізгі тексерулерден кейін қоңырау шалу керек accept_message().

Енді ішкі хабарламаларға көшейік. Шындығында, біз тек грамды ғана қабылдаймыз және егер ол жеңсе, ойыншыға екі есе соманы, ал ұтылған жағдайда иесіне үштен бір соманы қайтарамыз.

Алдымен қарапайым тест жазайық. Мұны істеу үшін бізге смарт келісімшартқа грамм жіберетін смарт келісімшарттың сынақ мекенжайы қажет.

Смарт келісімшарт мекенжайы екі саннан, жұмыс тізбегіне жауапты 32 биттік бүтін саннан және осы жұмыс тізбегіндегі 256 биттік теріс емес бүтін бірегей шот нөмірінен тұрады. Мысалы, -1 және 12345, бұл біз файлға сақтайтын мекенжай.

Мен мекенжайды сақтауға арналған функцияны көшірдім 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

Функцияның қалай жұмыс істейтінін қарастырайық, бұл Fift қалай жұмыс істейтіні туралы түсінік береді. Fift қолданбасын интерактивті режимде іске қосыңыз.

~/TON/build/crypto/fift -i 

Алдымен стекке -1, 12345 және болашақ файлдың "sender.addr" атауын басамыз:

-1 12345 "sender.addr" 

Келесі қадам функцияны орындау болып табылады -rot, ол стектің жоғарғы жағында бірегей смарт келісімшарт нөмірі болатындай етіп жылжытады:

"sender.addr" -1 12345

256 u>B 256-биттік теріс емес бүтін санды байтқа түрлендіреді.

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap стектің жоғарғы екі элементін ауыстырады.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

32 i>B 32-биттік бүтін санды байтқа түрлендіреді.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ байттардың екі тізбегін қосады.

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

Қайтадан swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

Соңында байт файлға жазылады B>file. Осыдан кейін біздің стек бос. Біз тоқтаймыз Fift. Ағымдағы қалтада файл жасалды sender.addr. Файлды жасалған қалтаға жылжытайық test/addresses/.

Смарт келісімшартқа грамм жіберетін қарапайым тест жазайық. Міне, міндеттеме.

Енді лотереяның логикасын қарастырайық.

Біз жасайтын бірінші нәрсе - хабарламаны тексеру bounced немесе егер жоқ bounced, содан кейін біз оны елемейміз. bounced қандай да бір қате орын алса, келісімшарт граммдарды қайтарады дегенді білдіреді. Егер кенеттен қате орын алса, граммдарды қайтармаймыз.

Біз тексереміз, егер теңгерім жарты грамнан аз болса, біз хабарламаны қабылдап, оны елемейміз.

Әрі қарай, біз хабарлама келген смарт келісімшарттың мекенжайын талдаймыз.

Біз жадтағы деректерді оқимыз, содан кейін олар жиырмадан астам болса, ескі ставкаларды тарихтан жоямыз. Ыңғайлы болу үшін мен үш қосымша функция жаздым pack_order(), unpack_order(), remove_old_orders().

Әрі қарай, баланс төлем үшін жеткіліксіз болса, онда біз бұл ставка емес, толықтыру деп есептейміз және толықтыруды сақтаймыз. orders.

Содан кейін ақылды келісімшарттың мәні.

Біріншіден, егер ойыншы ұтылса, біз оны ставкалар тарихында сақтаймыз және егер сома 3 граммнан асса, біз смарт келісімшарттың иесіне 1/3 жібереміз.

Ойыншы ұтқан жағдайда, біз екі есе соманы ойыншының мекенжайына жібереміз, содан кейін ставка туралы ақпаратты тарихта сақтаймыз.

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

Осымен болды. Сәйкес міндеттеме.

Енді бәрі қарапайым, келісім-шарттың күйі туралы ақпаратты сыртқы әлемнен алу үшін алу әдістерін жасайық (шын мәнінде, олардың смарт келісімшарт қоймасынан деректерді оқыңыз).

Get әдістерін қосамыз. Смарт келісімшарт туралы ақпаратты қалай алуға болатыны туралы төменде жазамыз.

Мен сондай-ақ смарт келісімшартты жариялау кезінде пайда болатын ең бірінші сұрауды өңдейтін кодты қосуды ұмытып кеттім. Сәйкес міндеттеме. Және одан әрі түзетілді соманың 1/3 бөлігін иесінің шотына жіберу қатесі.

Келесі қадам - ​​смарт келісімшартты жариялау. Қалта жасайық requests.

Мен басылым кодын негізге алдым simple-wallet-code.fc ол таба аласыз ресми репозиторийде.

Назар аударуға тұрарлық нәрсе. Біз смарт келісімшарт қоймасын және кіріс хабарламасын жасаймыз. Осыдан кейін смарт келісімшарттың мекенжайы жасалады, яғни мекенжай TON-да жарияланғанға дейін белгілі. Әрі қарай, осы мекенжайға бірнеше грамм жіберу керек, содан кейін ғана смарт келісім-шартпен файлды жіберу керек, өйткені желі смарт келісім-шартты және ондағы операцияларды сақтау үшін комиссия алады (смартты сақтайтын және орындайтын валидаторлар). келісім-шарттар). Кодты осы жерден көруге болады.

Содан кейін біз жариялау кодын орындаймыз және аламыз lottery-query.boc смарт келісімшарт файлы мен мекенжайы.

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

Жасалған файлдарды сақтауды ұмытпаңыз: lottery-query.boc, lottery.addr, lottery.pk.

Басқа нәрселермен қатар, біз орындау журналдарында смарт келісімшарттың мекенжайын көреміз.

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

Тек көңіл көтеру үшін TON-ға өтініш жасайық

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

Және бұл мекенжайы бар аккаунт бос екенін көреміз.

account state is empty

мекен-жайына жібереміз 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 грамм және бірнеше секундтан кейін біз бірдей пәрменді орындаймыз. Грамдарды жіберу үшін мен қолданамын ресми әмиян, және сіз чатта біреуден сынақ граммдарын сұрай аласыз, мен бұл туралы мақаланың соңында айтатын боламын.

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Бақыланбаған сияқты (state:account_uninit) мекенжайы бірдей және балансы 1 000 000 000 нанограмм болатын смарт келісімшарт.

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

Енді смарт келісімшартты жариялайық. Lite-client іске қосып, орындаймыз.

> 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 

Келісімшарттың жарияланғанын тексерейік.

> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Басқа нәрселермен қатар біз аламыз.

  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

Біз мұны көреміз account_active.

Өзгерістерге сәйкес міндеттеме мұнда.

Енді смарт келісімшартпен әрекеттесу үшін сұрауларды жасайық.

Дәлірек айтсақ, біріншісін мекенжайды өзгертуге дербес жұмыс ретінде қалдырамыз, ал екіншісін иесінің мекенжайына грамм жіберу үшін жасаймыз. Шын мәнінде, біз грамм жіберуге арналған сынақтағыдай әрекетті орындауымыз керек.

Бұл біз смарт келісім-шартқа жіберетін хабарлама msg_seqno 165, action Жіберу үшін 2 және 9.5 грамм.

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

Хабарламаға жеке кілтіңізбен қол қоюды ұмытпаңыз lottery.pk, ол смарт келісімшартты жасау кезінде бұрын жасалған. Міне, тиісті міндеттеме.

Get әдістерін пайдалана отырып, смарт келісімшарттан ақпарат алу

Енді смарт келісімшартты алу әдістерін қалай іске қосу керектігін қарастырайық.

Іске қосу lite-client және біз жазған алу әдістерін іске қосыңыз.

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

В result функция қайтаратын мәнді қамтиды balance() ақылды келісімшартымыздан.
Біз тағы бірнеше әдіс үшін де солай істейміз.

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

Сіздің бәс тігулер тарихыңызды сұрайық.

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

Біз lite-client қолданамыз және сайтта смарт келісімшарт туралы ақпаратты көрсету әдістерін аламыз.

Веб-сайтта смарт келісімшарт деректерін көрсету

Мен смарт келісімшарттағы деректерді ыңғайлы түрде көрсету үшін Python-да қарапайым веб-сайт жаздым. Бұл жерде мен оған егжей-тегжейлі тоқталмай, сайтты жариялаймын бір міндеттемеде.

TON сұраулары мына жерден жасалады Python көмегімен lite-client. Ыңғайлы болу үшін сайт Docker-те жинақталған және Google Cloud-та жарияланған. Сілтеме.

Тырысып жатыр

Енді сол жерден толықтыру үшін грамм жіберуге тырысайық әмияныңызда. Біз 40 грамм жібереміз. Түсінікті болу үшін бірнеше ставка жасайық. Сайт ставкалардың тарихын, ағымдағы ұтыс пайызын және басқа да пайдалы ақпаратты көрсететінін көреміз.

Біз көріп тұрмызбірінші ұтқанымыз, екіншісінде жеңілгеніміз.

Кейінгі сөз

Мақала мен күткеннен әлдеқайда ұзағырақ болды, мүмкін ол қысқа болуы мүмкін немесе TON туралы ештеңе білмейтін және өзара әрекеттесу мүмкіндігі бар қарапайым емес смарт келісімшартты жазып, жариялағысы келетін адамға арналған шығар. ол. Мүмкін кейбір нәрселерді қарапайымырақ түсіндіруге болар еді.

Мүмкін, іске асырудың кейбір аспектілері тиімдірек және талғампаз түрде жасалуы мүмкін еді, бірақ содан кейін мақаланы дайындау үшін одан да көп уақыт қажет болар еді. Сондай-ақ, мен бір жерде қателескен шығармын немесе бірдеңені түсінбедім, сондықтан егер сіз маңызды нәрсе істеп жатсаңыз, ресми құжаттамаға немесе TON коды бар ресми репозиторийге сену керек.

Айта кету керек, TON өзі әлі де белсенді даму сатысында болғандықтан, осы мақаладағы кез келген қадамды бұзатын өзгерістер болуы мүмкін (бұл мен жазып жатқан кезде болды, ол түзетілді), бірақ жалпы көзқарас өзгеруі екіталай.

Мен TON-ның болашағы туралы айтпаймын. Мүмкін платформа үлкен нәрсеге айналады және біз оны зерттеуге уақыт бөліп, өз өнімдерімізбен тауашаны қазір толтыруымыз керек.

Сондай-ақ Facebook-тен Libra бар, оның әлеуетті аудиториясы TON-нан асатын пайдаланушылар бар. Мен Libra туралы ештеңе білмеймін, форумға қарағанда, онда TON қауымдастығына қарағанда белсенділік әлдеқайда көп. TON әзірлеушілері мен қауымдастығы жер астына көбірек ұқсайды, бұл да керемет.

сілтемелер

  1. Ресми TON құжаттамасы: https://test.ton.org
  2. Ресми TON репозиторийі: https://github.com/ton-blockchain/ton
  3. Түрлі платформаларға арналған ресми әмиян: https://wallet.ton.org
  4. Осы мақаладағы смарт келісімшарт репозиторийі: https://github.com/raiym/astonished
  5. Смарт келісімшарт веб-сайтына сілтеме: https://ton-lottery.appspot.com
  6. FunC үшін Visual Studio Code кеңейтіміне арналған репозиторий: https://github.com/raiym/func-visual-studio-plugin
  7. Telegram-да TON туралы сөйлесіңіз, бұл оны бастапқы кезеңде анықтауға көмектесті. Менің ойымша, ТОН үшін бірдеңе жазғандардың бәрі сонда деп айтсам қателеспеймін. Сондай-ақ сынақ граммдарын сол жерден сұрай аласыз. https://t.me/tondev_ru
  8. TON туралы тағы бір чат, онда мен пайдалы ақпарат таптым: https://t.me/TONgramDev
  9. Байқаудың бірінші кезеңі: https://contest.com/blockchain
  10. Байқаудың екінші кезеңі: https://contest.com/blockchain-2

Ақпарат көзі: www.habr.com

пікір қалдыру