Telegram Open Network тармагында акылдуу келишимди кантип жазуу жана жарыялоо керектиги жөнүндө (TON)

ТОНдо акылдуу келишимди кантип жазуу жана жарыялоо керектиги жөнүндө

Бул макала эмне жөнүндө?

Макалада мен биринчи (экиден) Telegram блокчейн сынагына кантип катышып, байгеге ээ болбогонум жана унутулуп калбашы үчүн жана балким, жардам бериши үчүн өз тажрыйбамды макалага жазууну чечтим. бирөө.

Мен абстракттуу кодду жазгым келбегендиктен, бирок бир нерсе кылуу үчүн, макала үчүн мен заматта лотерея үчүн акылдуу келишим жаздым жана ортолук сактагычты колдонбостон, акылдуу келишимдин маалыматтарын түздөн-түз TONдон көрсөткөн веб-сайт.

Макала ТОНдо биринчи акылдуу келишим түзүүнү каалагандар үчүн пайдалуу болот, бирок эмнеден баштоону билбейт.

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

Мелдешке катышуу жөнүндө

Өткөн жылдын октябрь айында Telegram жаңы тилдер менен блокчейн конкурсун жарыялаган Fift и FunC. Сунушталган беш акылдуу келишимдин каалаганын жазуудан тандоо керек болчу. Келечекте башка эч нерсе жазбасам да, башкача кылып, тил үйрөнүп, бир нерсе жасасам жакшы болмок деп ойлогом. Мындан тышкары, тема дайыма оозунда.

Мен акылдуу келишимдерди иштеп чыгуу боюнча эч кандай тажрыйбам жок деп айтууга болот.

Мүмкүн болгончо аягына чейин катышып, анан сын макала жазайын деп пландадым, бирок биринчисинде дароо ишке ашпай калдым. И капчык жазган көп кол коюу менен FunC жана ал жалпысынан иштеген. Мен негиз кылып алдым Solidity боюнча акылдуу келишим.

Ал кезде мен бул, жок дегенде, кандайдыр бир байгелүү орунга ээ болуу үчүн жетиштүү деп ойлочумун. Жыйынтыгында 40 катышуучунун 60ка жакыны байгелүү орундарга ээ болуп, мен алардын арасында жок болчумун. Негизинен бул жерде эч кандай жаман нерсе жок, бирок мени бир нерсе кыжаалат кылды. Натыйжалар жарыяланган учурда, менин келишимим боюнча тестти карап чыгуу жүргүзүлө элек болчу, мен чаттын катышуучуларынан башка бирөө барбы деп сурадым, андай жок.

Менин билдирүүлөрүмө көңүл бурган окшойт, эки күндөн кийин калыстар комментарий жазып чыгышты жана мен дагы деле түшүнө албай жатам, алар калыстар учурунда менин акылдуу келишимимди кокусунан өткөрүп жибериштиби же жөн гана комментарийге муктаж эмес деп ойлоштубу. Баракчада суроо бердим, бирок жооп алган жокмун. Ким соттогону сыр болбосо да, жеке билдирүүлөрдү жазууну керексиз деп эсептедим.

Түшүнүүгө көп убакыт сарпталгандыктан, макала жазууну чечишти. Азырынча көп маалымат жок болгондуктан, макала кызыккандардын бардыгына убакытты үнөмдөөгө жардам берет.

ТОНдо акылдуу келишимдер түшүнүгү

Бир нерсе жазуудан мурун бул нерсеге кайсы тараптан кайрылыш керек экенин аныкташ керек. Ошондуктан, азыр мен сизге система кандай бөлүктөрдөн тураарын айтып берем. Тагыраак айтканда, жок дегенде кандайдыр бир эмгек келишимин жазуу үчүн кандай бөлүктөрүн билишиңиз керек.

Биз акылдуу келишим жазууга жана аны менен иштөөгө басым жасайбыз TON Virtual Machine (TVM), Fift и FunC, ошондуктан макала кадимки программаны иштеп чыгуунун сүрөттөлүшүнө окшош. Биз бул жерде платформанын өзү кантип иштээри жөнүндө токтолбойбуз.

Жалпысынан ал кандайча иштейт TVM жана тил Fift жакшы расмий документтер бар. Сынакка катышып жүрүп, азыркы келишимди жазып жатканда да ага көп кайрылчумун.

акылдуу келишимдер жазылган негизги тил болуп саналат FunC. Учурда бул боюнча эч кандай документация жок, ошондуктан бир нерсе жазуу үчүн расмий репозиторийден акылдуу контракттардын мисалдарын жана ал жерде тилди ишке ашырууну үйрөнүшүңүз керек, ошондой эле акыркы экиден акылдуу келишимдердин мисалдарын карасаңыз болот. мелдештер. Макаланын аягындагы шилтемелер.

Биз буга чейин акылдуу келишим жаздык дейли FunC, андан кийин биз кодду Fift ассемблерине түзөбүз.

Түзүлгөн акылдуу келишим жарыяланышы керек. Бул үчүн сиз функцияны жазышыңыз керек Fift, ал акылдуу келишимдин кодун жана башка кээ бир параметрлерди киргизүү катары кабыл алат, ал эми чыгаруу кеңейтүүсү менен файл болот .boc (бул "клеткалардын баштыгы" дегенди билдирет) жана аны кантип жазганыбызга жараша, акылдуу келишим кодунун негизинде түзүлгөн купуя ачкыч жана дарек. Сиз буга чейин эле жарыялана элек акылдуу келишимдин дарегине грамм жөнөтө аласыз.

ТОНдо акылдуу келишимди жарыялоо үчүн .boc файл жеңил кардар аркылуу блокчейнге жөнөтүлүшү керек (төмөндө бул тууралуу көбүрөөк). Бирок жарыялоодон мурун граммдарды түзүлгөн дарекке которуу керек, антпесе акылдуу келишим жарыяланбайт. Жарыялангандан кийин, сиз акылдуу контрактка сырттан (мисалы, жеңил кардарды колдонуу) же ичинен (мисалы, бир акылдуу контракт башкасына TON ичинде билдирүү жөнөтөт) билдирүүлөрдү жөнөтүү менен өз ара аракеттене аласыз.

Код кандайча жарыяланганын түшүнгөндөн кийин, ал жеңилдейт. Биз болжол менен эмнени жазгыбыз келет жана программабыз кандай иштей турганын билебиз. Жана жазып жатып, биз бул учурдагы акылдуу контракттарда кандайча ишке ашырылганын издейбиз же ишке ашыруу кодун карайбыз Fift и FunC расмий репозиторийде, же расмий документтерди караңыз.

Сынактын бардык катышуучулары жана Telegram кызматкерлери чогулган Telegram чатынан мен ачкыч сөздөрдү көп издечүмүн жана конкурс учурунда баары ал жерге чогулуп, Fift жана FunCди талкуулай башташты. Макаланын аягындагы шилтеме.

Теориядан практикага өтүүгө убакыт жетти.

TON менен иштөө үчүн шарттарды даярдоо

Макалада сүрөттөлгөн нерселердин баарын MacOS боюнча жасадым жана аны Dockerдеги таза Ubuntu 18.04 LTSде эки жолу текшердим.

Биринчи нерсе - бул жүктөп алуу жана орнотуу lite-client анын жардамы менен сиз ТОНго суроо-талаптарды жөнөтө аласыз.

Расмий веб-сайттагы нускамалар орнотуу процессин толук жана так сүрөттөп, кээ бир деталдарды калтырган. Бул жерде биз нускамаларды аткарабыз, жолдо жетишпеген көз карандылыктарды орнотобуз. Мен ар бир долбоорду өзүм түзгөн эмесмин жана расмий 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

ТОНго биринчи суроо-талаптарды жасоо

Эми ишке киргизели 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% түзөт. Төлөө үчүн грамм жетишсиз болсо, анда биз транзакцияны толуктоо катары карайбыз.

Мындан тышкары, коюмдарды реалдуу убакыт режиминде жана ыңгайлуу формада көрүүгө болот, ошондуктан колдонуучу өзүнүн утуп алганын же утулганын дароо түшүнө алат. Ошондуктан, сиз түздөн-түз ТОНдон коюмдарды жана натыйжаларды көрсөтө турган веб-сайтты жасашыңыз керек.

Акылдуу келишим жазуу

Ыңгайлуу болуу үчүн, мен FunC кодун бөлүп койдум; плагинди Visual Studio Code издөөсүндө табууга жана орнотууга болот; эгер сиз күтүлбөгөн жерден бир нерсе кошкуңуз келсе, мен плагинди жалпыга ачык кылдым. Ошондой эле, кимдир бирөө мурда Fift менен иштөө үчүн плагин жасаган, сиз аны орнотуп, VSCден таба аласыз.

Келгиле, дароо репозиторий түзөлү, анда биз ортодогу жыйынтыктарды жасайбыз.

Жашообузду жеңилдетүү үчүн биз акылдуу келишим жазып, ал даяр болгонго чейин аны жергиликтүү деңгээлде сынап көрөбүз. Ошондон кийин гана ТОНдо чыгарабыз.

Акылдуу келишимде кире турган эки тышкы ыкма бар. Алгачкы, recv_external() бул функция келишимге суроо-талап тышкы дүйнөдөн келгенде, башкача айтканда, ТОНдон эмес, биз өзүбүз билдирүү жасап, аны lite-кардар аркылуу жөнөткөндө аткарылат. Экинчи, recv_internal() бул ТОНдун ичинде кандайдыр бир келишим биздикиге тиешелүү болгондо. Эки учурда тең функцияга параметрлерди өткөрө аласыз.

Жөнөкөй мисалдан баштайлы, эгер жарыяланган болсо иштей берет, бирок анда функционалдык жүк жок.

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

Иштеп чыгуучу өзү келишим кабыл ала турган билдирүү форматын тандайт.

Бирок адатта

  • биринчиден, биз келишимди тышкы дүйнөдөн коргогубуз келет жана аны келишимдин ээси гана ага тышкы билдирүүлөрдү жөнөтө ала тургандай кылгыбыз келет.
  • экинчиден, биз ТОНго жарактуу билдирүү жөнөткөндө, бул бир жолу болушун каалайбыз жана ошол эле билдирүүнү кайра жөнөткөнүбүздө, акылдуу келишим аны четке кагат.

Демек, дээрлик ар бир келишим бул эки маселени чечет, анткени биздин келишим тышкы билдирүүлөрдү кабыл алгандыктан, биз буга да кам көрүшүбүз керек.

Биз муну тескери тартипте жасайбыз. Биринчиден, маселени кайталоо менен чечели, эгерде келишим буга чейин мындай билдирүүнү алып, аны иштетсе, ал экинчи жолу аткарбайт. Анан акылдуу келишимге адамдардын белгилүү бир чөйрөсү гана билдирүүлөрдү жөнөтө тургандай кылып маселени чечебиз.

Кайталанма билдирүүлөр менен көйгөйдү чечүүнүн ар кандай жолдору бар. Муну кантип кылабыз. Акылдуу келишимде биз кабыл алынган билдирүүлөрдүн эсептегичти 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 кодуна skirpt кодун кошолу, ал жөн гана компиляцияланган файлды кайталайт 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 окуй аласыз беш документте.

Жана тестти өткөрүү үчүн биз кайра чалабыз.

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. Биз бул купуя ачкыч менен билдирүүгө кол коёбуз. Келгиле, тесттерди өткөрөлү жана бардык сыноолор өткөнүнө ынаналы. Commit азыркы учурда.

Эми биз акыры акылдуу контракт логикасын ишке ашырууга өтсөк болот.
В 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));
}

Болгону ушул. Тиешелүү милдеттенме.

Эми калганы жөнөкөй, келгиле, келишимдин абалы жөнүндө тышкы дүйнөдөн маалымат алуу үчүн алуу ыкмаларын түзөлү (чындыгында, алардын акылдуу контракт сактагычынан маалыматтарды окугула).

Келгиле, алуу ыкмаларын кошолу. Төмөндө акылдуу келишим тууралуу маалыматты кантип алуу керектиги жөнүндө жазабыз.

Мен ошондой эле акылдуу келишимди жарыялоодо пайда болгон эң биринчи суроону иштете турган кодду кошууну унутуп калдым. Тиешелүү милдеттенме. Жана андан ары оңдолду ээсинин эсебине сумманын 1/3 жөнөтүү менен ката.

Кийинки кадам - ​​акылдуу келишимди жарыялоо. Папканы түзөлү requests.

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

Көңүл бурууга арзырлык нерсе. Биз акылдуу келишим сактагычын жана киргизүү билдирүүсүн жаратабыз. Андан кийин, акылдуу келишимдин дареги түзүлөт, башкача айтканда, дарек ТОНдо жарыяланганга чейин эле белгилүү. Андан кийин, сиз бул дарекке бир нече грамм жөнөтүшүңүз керек жана андан кийин гана сиз смарт контракттын өзү менен файлды жөнөтүшүңүз керек, анткени тармак акылдуу келишимди жана андагы операцияларды сактоо үчүн комиссия алат (смартты сактаган жана аткарган валидаторлор). келишимдер). Кодду бул жерден көрсө болот.

Андан кийин биз жарыялоо кодун аткарабыз жана алабыз 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

Жөн эле көңүл ачуу үчүн, келгиле ТОНго өтүнүч кылалы

$ ./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-клиентти ишке киргизип, аткаралы.

> 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-кардарларды колдонобуз жана сайтта акылдуу келишим жөнүндө маалыматты көрсөтүү ыкмаларын алабыз.

Вебсайтта акылдуу келишим маалыматтарын көрсөтүү

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

TON үчүн суроо-талаптар жасалган Python жардамы менен lite-client. Ыңгайлуу болуу үчүн, сайт Dockerде топтолгон жана Google Cloud'та жарыяланган. Шилтеме.

Аракет кылууда

Эми ал жакка граммды толуктоо үчүн жөнөтүүгө аракет кылалы капчык. 40 грамм жиберебиз. Келгиле, түшүнүктүү болуу үчүн бир-эки коюм жасайлы. Биз сайт коюмдардын тарыхын, учурдагы утуш пайызын жана башка пайдалуу маалыматтарды көрсөтүп жатканын көрөбүз.

КөрөбүзБиринчиден утса, экинчисинде утулуп калганбыз.

аягы

Макала мен күткөндөн алда канча узун болуп чыкты, балким, ал кыскараак болушу мүмкүн, же жөн гана ТОН жөнүндө эч нерсе билбеген жана өз ара аракеттенүү жөндөмү менен жөнөкөй эмес акылдуу келишимди жазып, жарыялоону каалаган адам үчүн ал. Балким, кээ бир нерселерди жөнөкөйраак түшүндүрсө болмок.

Балким, ишке ашыруунун кээ бир аспектилери кыйла натыйжалуу жана көрктүү кылса болмок, бирок андан кийин макаланы даярдоо үчүн дагы көп убакыт талап кылынмак. Ошондой эле, мен бир жерден ката кетирген болушум же бир нерсени түшүнбөй калышым мүмкүн, андыктан олуттуу иш кылып жатсаңыз, анда расмий документтерге же TON коду бар расмий репозиторийге таянышыңыз керек.

Белгилей кетсек, TON өзү дагы эле активдүү өнүгүү стадиясында болгондуктан, бул макаладагы кадамдардын кайсынысын болбосун буза турган өзгөрүүлөр болушу мүмкүн (мен жазып жатканда болгон, ал буга чейин эле оңдолгон), бирок жалпы мамиле өзгөрүшү күмөн.

Мен ТОНдун келечеги тууралуу айтпай эле коёюн. Балким, платформа чоң нерсеге айланат жана биз аны изилдөөгө убакыт коротушубуз керек жана азыр биздин өнүмдөр менен орун толтурушубуз керек.

ТОНдон чоң колдонуучулардын потенциалдуу аудиториясы бар Facebookтан Libra да бар. Мен Libra жөнүндө дээрлик эч нерсе билбейм, форумга караганда, ал жерде 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. Телеграмдагы TON жөнүндө баарлашыңыз, бул аны баштапкы этапта аныктоого жардам берди. Мен ТОН үчүн бир нерсе жазгандардын баары ошол жерде десем жаңылышпайм деп ойлойм. Сиз ошол жерден тест граммдарын да сурасаңыз болот. https://t.me/tondev_ru
  8. TON жөнүндө дагы бир чат, анда мен пайдалуу маалымат таптым: https://t.me/TONgramDev
  9. Конкурстун биринчи этабы: https://contest.com/blockchain
  10. Сынактын экинчи этабы: https://contest.com/blockchain-2

Source: www.habr.com

Комментарий кошуу