Telegram Açıq Şəbəkəsində (TON) ağıllı müqaviləni necə yazmaq və dərc etmək haqqında

TON-da ağıllı müqavilə yazmaq və dərc etmək haqqında

Bu məqalə nədən bəhs edir?

Məqalədə ilk (iki) Telegram blokçeyn müsabiqəsində necə iştirak etdiyimdən, mükafat almadığımdan və təcrübəmi məqalədə qeyd etmək qərarına gəldiyimdən danışacağam ki, unudulmasın və bəlkə də kömək etsin. kimsə.

Mücərrəd kod yazmaq istəmədiyim üçün, amma işləyən bir şey etmək üçün məqalə üçün ani lotereya və aralıq yaddaşdan istifadə etmədən ağıllı müqavilə məlumatlarını birbaşa TON-dan göstərən veb sayt üçün ağıllı müqavilə yazdım.

Məqalə TON-da ilk ağıllı müqaviləsini etmək istəyən, lakin haradan başlayacağını bilməyənlər üçün faydalı olacaq.

Nümunə olaraq lotereyadan istifadə edərək, mühiti quraşdırmaqdan ağıllı müqavilə dərc etməyə, onunla qarşılıqlı əlaqə qurmağa və məlumatların qəbulu və dərc edilməsi üçün veb-sayt yazmağa keçəcəyəm.

Müsabiqədə iştirak haqqında

Keçən oktyabr ayında Telegram yeni dillərlə blokçeyn müsabiqəsi elan etdi Fift и FunC. Təklif olunan beş ağıllı müqavilədən hər hansı birini seçmək lazım idi. Düşündüm ki, gələcəkdə başqa bir şey yazmamalı olsam da, fərqli bir şey etmək, dil öyrənmək və nəsə etmək yaxşı olardı. Üstəlik, mövzu daima dodaqlardadır.

Ağıllı müqavilələr hazırlamaq təcrübəm olmadığını söyləməyə dəyər.

İmkanım çatana qədər sona qədər iştirak etməyi və sonra rəy yazısı yazmağı planlaşdırdım, amma birincisində dərhal uğursuz oldum. I pul kisəsi yazdı çox imza ilə FunC və ümumiyyətlə işlədi. Mən bunu əsas götürdüm Solidity üzrə ağıllı müqavilə.

O zaman düşünürdüm ki, bu, heç olmasa, mükafatlı yer tutmaq üçün kifayətdir. Nəticədə 40 iştirakçıdan 60-a yaxını mükafatçı oldu və mən onların arasında deyildim. Ümumiyyətlə, bunda qəbahət yoxdur, amma bir şey məni narahat etdi. Nəticələri elan edəndə, mənim müqaviləm üçün testin nəzərdən keçirilməsi edilməmişdi, söhbətdə iştirak edənlərdən soruşdum ki, başqası yoxdur, yox idi.

Görünür, mesajlarıma diqqət yetirərək, iki gün sonra hakimlər bir şərh dərc etdilər və mən hələ də başa düşə bilmirəm ki, onlar mühakimə zamanı təsadüfən mənim ağıllı müqaviləmi qaçırıblar, yoxsa sadəcə fikirləşiblər ki, o qədər pis olub ki, şərhə ehtiyac yoxdur. Səhifədə sual verdim, cavab almadım. Kimin mühakimə etdiyi sirr olmasa da, şəxsi mesajlar yazmağı lazımsız hesab etdim.

Anlamaq üçün çox vaxt sərf olundu, ona görə də məqalə yazmaq qərara alındı. Hələ çox məlumat olmadığı üçün bu məqalə maraqlanan hər kəs üçün vaxta qənaət etməyə kömək edəcəkdir.

TON-da ağıllı müqavilələr konsepsiyası

Bir şey yazmazdan əvvəl bu işə hansı tərəfdən yanaşmaq lazım olduğunu anlamaq lazımdır. Ona görə də indi sizə sistemin hansı hissələrdən ibarət olduğunu söyləyəcəyəm. Daha doğrusu, ən azı bir növ əmək müqaviləsi yazmaq üçün hansı hissələri bilmək lazımdır.

Ağıllı müqavilə yazmağa və onunla işləməyə diqqət edəcəyik TON Virtual Machine (TVM), Fift и FunC, belə ki, məqalə daha çox adi proqramın inkişafının təsvirinə bənzəyir. Burada platformanın özünün necə işlədiyinə toxunmayacağıq.

Ümumiyyətlə, necə işlədiyi haqqında TVM və dil Fift yaxşı rəsmi sənədləri var. Müsabiqədə iştirak edəndə və indi hazırkı müqaviləni yazarkən tez-tez ona müraciət edirdim.

Ağıllı müqavilələrin yazıldığı əsas dildir FunC. Hal-hazırda bununla bağlı heç bir sənəd yoxdur, buna görə də bir şey yazmaq üçün rəsmi depodan ağıllı müqavilələrin nümunələrini və orada dilin özünün tətbiqini öyrənməlisiniz, üstəlik, son ikisindən ağıllı müqavilələrin nümunələrinə baxa bilərsiniz. yarışlar. Məqalənin sonundakı bağlantılar.

Deyək ki, biz artıq ağıllı müqavilə yazmışıq FunC, bundan sonra kodu Fift assembler-ə yığırıq.

Tərtib edilmiş ağıllı müqavilə dərc edilməkdədir. Bunu etmək üçün bir funksiya yazmalısınız Fift, giriş kimi ağıllı müqavilə kodunu və bəzi digər parametrləri götürəcək və çıxış uzantılı bir fayl olacaq .boc (bu, “hüceyrə çantası” deməkdir) və onu necə yazdığımızdan asılı olaraq, ağıllı müqavilə kodu əsasında yaradılan şəxsi açar və ünvan. Hələ dərc olunmamış ağıllı müqavilənin ünvanına artıq qram göndərə bilərsiniz.

TON-da ağıllı bir müqavilə dərc etmək alındı .boc fayl yüngül müştəridən istifadə edərək blokçeynə göndərilməlidir (aşağıda daha ətraflı). Ancaq dərc etməzdən əvvəl qramları yaradılan ünvana köçürməlisiniz, əks halda smart müqavilə dərc olunmayacaq. Yayımlandıqdan sonra siz xaricdən (məsələn, yüngül müştəridən istifadə etməklə) və ya daxildən (məsələn, bir smart müqavilə digərinə TON daxilində mesaj göndərir) mesajlar göndərməklə ağıllı müqavilə ilə əlaqə saxlaya bilərsiniz.

Kodun necə dərc edildiyini başa düşdükdən sonra, bu daha asan olur. Nə yazmaq istədiyimizi və proqramımızın necə işləyəcəyini təxminən bilirik. Və yazarkən, bunun artıq mövcud ağıllı müqavilələrdə necə tətbiq olunduğunu axtarırıq və ya icra koduna baxırıq Fift и FunC rəsmi depoda və ya rəsmi sənədlərə baxın.

Çox tez-tez bütün müsabiqə iştirakçılarının və Telegram işçilərinin toplaşdığı Telegram çatında açar sözlər axtarırdım və elə oldu ki, müsabiqə zamanı hamı oraya toplaşaraq Fift və FunC-ni müzakirə etməyə başladı. Məqalənin sonundakı link.

Nəzəriyyədən praktikaya keçməyin vaxtıdır.

TON ilə işləmək üçün mühitin hazırlanması

MacOS-da məqalədə təsvir ediləcək hər şeyi etdim və Docker-də təmiz Ubuntu 18.04 LTS-də iki dəfə yoxladım.

Etməli olduğunuz ilk şey yükləmək və quraşdırmaqdır lite-client TON-a sorğu göndərə bilərsiniz.

Rəsmi veb saytındakı təlimatlar quraşdırma prosesini olduqca ətraflı və aydın şəkildə təsvir edir və bəzi detalları buraxır. Burada təlimatlara əməl edirik, yol boyu çatışmayan asılılıqları quraşdırırıq. Mən hər bir layihəni özüm tərtib etmədim və rəsmi Ubuntu repozitoriyasından quraşdırdım (istifadə etdiyim MacOS-da 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 

Bütün asılılıqlar quraşdırıldıqdan sonra quraşdıra bilərsiniz lite-client, Fift, FunC.

Əvvəlcə TON deposunu asılılıqları ilə birlikdə klonlayırıq. Rahatlıq üçün hər şeyi bir qovluqda edəcəyik ~/TON.

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

Repozitoriya həmçinin tətbiqləri saxlayır Fift и FunC.

İndi layihəni yığmağa hazırıq. Repozitor kodu qovluğa klonlanır ~/TON/ton. Ilə ~/TON qovluq yaradın build və layihəni orada toplayın.

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

Ağıllı bir müqavilə yazacağımız üçün nəinki ehtiyacımız var lite-clientLakin Fift с FunC, buna görə də hər şeyi tərtib edək. Bu sürətli proses deyil, ona görə də gözləyirik.

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

Sonra, daxil olduğu node haqqında məlumatları ehtiva edən konfiqurasiya faylını yükləyin lite-client birləşdirəcək.

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

TON-a ilk müraciətlər edilir

İndi başlayaq lite-client.

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

Quraşdırma uğurlu olarsa, işə salındıqdan sonra işıq müştərisinin qovşaqla əlaqəsinin qeydini görəcəksiniz.

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

Komandanı işlədə bilərsiniz help və hansı əmrlərin mövcud olduğuna baxın.

help

Bu yazıda istifadə edəcəyimiz əmrləri sadalayaq.

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

İndi biz müqavilənin özünü yazmağa hazırıq.

Tətbiq

Fikir

Yuxarıda yazdığım kimi, yazdığımız ağıllı müqavilə lotereyadır.

Üstəlik, bu, bilet almaq və bir saat, gün və ya ay gözləməli olduğunuz bir lotereya deyil, istifadəçinin müqavilə ünvanına köçürdüyü ani bir lotereyadır. N qram və dərhal geri qaytarır 2 * N qram və ya itirir. Qazanma ehtimalını təxminən 40% edəcəyik. Ödəniş üçün kifayət qədər qram yoxdursa, əməliyyatı əlavə hesab edəcəyik.

Üstəlik, mərclərin real vaxt rejimində və rahat formada görünməsi vacibdir ki, istifadəçi qalib və ya uduzduğunu dərhal anlaya bilsin. Buna görə də, birbaşa TON-dan mərc və nəticələri göstərəcək bir veb sayt yaratmalısınız.

Ağıllı müqavilə yazmaq

Rahatlıq üçün FunC kodunu vurğuladım; plaqini Visual Studio Code axtarışında tapmaq və quraşdırmaq olar; birdən nəsə əlavə etmək istəsəniz, mən plaqini ictimaiyyətə açıq etdim. Bundan əlavə, kimsə əvvəllər Fift ilə işləmək üçün bir plagin hazırladı, siz də onu quraşdıra və VSC-də tapa bilərsiniz.

Gəlin dərhal aralıq nəticələri verəcəyimiz bir anbar yaradaq.

Həyatımızı asanlaşdırmaq üçün ağıllı bir müqavilə yazacağıq və hazır olana qədər onu yerli olaraq sınaqdan keçirəcəyik. Yalnız bundan sonra biz onu TON-da dərc edəcəyik.

Ağıllı müqavilədə əldə edilə bilən iki xarici üsul var. Birinci, recv_external() bu funksiya müqaviləyə sorğu xarici dünyadan gələndə, yəni TON-dan deyil, məsələn, biz özümüz mesaj yaradıb onu lite-client vasitəsilə göndərdiyimiz zaman yerinə yetirilir. İkinci, recv_internal() TON-un özündə hər hansı bir müqavilə bizim müqaviləmizə aiddir. Hər iki halda parametrləri funksiyaya ötürə bilərsiniz.

Nəşr olunarsa işləyəcək sadə bir nümunə ilə başlayaq, lakin orada heç bir funksional yük yoxdur.

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

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

Burada bunun nə olduğunu izah etməliyik slice. TON Blockchain-də saxlanılan bütün məlumatlar topludur TVM cell və ya sadəcə cell, belə bir xanada 1023 bitə qədər məlumat və digər hüceyrələrə 4-ə qədər keçid saxlaya bilərsiniz.

TVM cell slice və ya slice bu mövcud olanın bir hissəsidir cell təhlil etmək üçün istifadə olunur, sonra aydın olacaq. Bizim üçün əsas odur ki, transfer edə bilək slice və mesajın növündən asılı olaraq məlumatları emal edin recv_external() və ya recv_internal().

impure — funksiyanın ağıllı müqavilə məlumatlarını dəyişdirdiyini göstərən açar söz.

Gəlin müqavilə kodunu saxlayaq lottery-code.fc və tərtib edin.

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

Komandadan istifadə edərək bayraqların mənasına baxmaq olar

~/TON/build/crypto/func -help

Fift assembler kodunu tərtib etdik 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

Yerli olaraq işə salına bilər, bunun üçün mühit hazırlayacağıq.

Qeyd edək ki, birinci sətir bağlanır Asm.fif, bu Fift assembler üçün Fift-də yazılmış koddur.

Ağıllı müqaviləni yerli olaraq işə salıb sınaqdan keçirmək istədiyimiz üçün fayl yaradacağıq lottery-test-suite.fif və ağıllı müqavilə kodunu sabitə yazan sonuncu sətri əvəz edərək tərtib edilmiş kodu oraya köçürün. codesonra onu virtual maşına köçürmək üçün:

"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

İndiyə qədər aydın görünür, indi eyni fayla TVM-i işə salmaq üçün istifadə edəcəyimiz kodu əlavə edək.

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 konteksti, yəni TVM-nin (və ya şəbəkə vəziyyətinin) işə salınacağı məlumatları qeyd edirik. Hətta müsabiqə zamanı tərtibatçılardan biri necə yaratmağı göstərdi c7 və köçürdüm. Bu yazıda biz dəyişməli ola bilərik rand_seed təsadüfi ədədin yaranması ondan asılı olduğundan və dəyişdirilməsə, hər dəfə eyni nömrə qaytarılacaq.

recv_internal и recv_external 0 və -1 dəyərləri olan sabitlər smart müqavilədə müvafiq funksiyaların çağırılmasına cavabdeh olacaqlar.

İndi boş ağıllı müqaviləmiz üçün ilk testi yaratmağa hazırıq. Aydınlıq üçün hələlik bütün testləri eyni fayla əlavə edəcəyik lottery-test-suite.fif.

Gəlin dəyişən yaradaq storage və içinə boş birini yazın cell, bu ağıllı müqavilə yaddaşı olacaq.

message Bu, kənardan ağıllı kontakta ötürəcəyimiz mesajdır. Onu da hələlik boş edəcəyik.

variable storage 
<b b> storage ! 

variable message 
<b b> message ! 

Sabitləri və dəyişənləri hazırladıqdan sonra əmrdən istifadə edərək TVM-i işə salırıq runvmctx və yaradılmış parametrləri girişə ötürün.

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

Sonda biz uğur qazanacağıq bu üçün ara kod Fift.

İndi əldə edilən kodu işlədə bilərik.

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

Proqram səhvsiz işləməlidir və çıxışda icra jurnalını görəcəyik:

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

Əla, biz ağıllı müqavilənin ilk işçi versiyasını yazdıq.

İndi funksionallıq əlavə etməliyik. Əvvəlcə xarici dünyadan gələn mesajlarla məşğul olaq recv_external()

Müqavilənin qəbul edə biləcəyi mesaj formatını tərtibatçı özü seçir.

Amma adətən

  • birincisi, biz müqaviləmizi xarici aləmdən qorumaq və elə etmək istəyirik ki, yalnız müqavilə sahibi ona xarici mesajlar göndərə bilsin.
  • ikincisi, biz TON-a etibarlı bir mesaj göndərdiyimiz zaman bunun tam olaraq bir dəfə baş verməsini istəyirik və eyni mesajı yenidən göndərdiyimiz zaman ağıllı müqavilə bunu rədd edir.

Beləliklə, demək olar ki, hər bir müqavilə bu iki problemi həll edir, çünki müqaviləmiz xarici mesajları qəbul edir, buna da diqqət yetirməliyik.

Biz bunu tərs qaydada edəcəyik. Birincisi, problemi təkrarla həll edək, əgər müqavilə artıq belə bir mesaj alıbsa və onu işləyibsə, ikinci dəfə icra etməyəcək. Və sonra problemi həll edəcəyik ki, yalnız müəyyən bir insan dairəsi ağıllı müqaviləyə mesaj göndərə bilsin.

Dublikat mesajlarla problemi həll etməyin müxtəlif yolları var. Bunu necə edəcəyik. Ağıllı müqavilədə biz qəbul edilmiş mesajların sayğacını ilkin dəyəri 0 ilə işə salırıq. Ağıllı müqaviləyə hər mesajda cari sayğac dəyərini əlavə edəcəyik. Mesajdakı sayğac dəyəri smart müqavilədəki dəyərə uyğun gəlmirsə, biz onu emal etmirik, əgər varsa, biz onu emal edirik və smart müqavilədəki sayğacı 1 artırırıq.

qayıdaq lottery-test-suite.fif və ona ikinci bir test əlavə edin. Səhv bir nömrə göndərsək, kod bir istisna atmalıdır. Məsələn, müqavilə məlumatları 166 saxlasın, biz isə 165 göndərək.

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

başlayaq.

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

Və testin səhvlə icra olunduğunu görəcəyik.

[ 1][t 0][1582283084.210902214][words.cpp:3046] lottery-test-suite.fif:67: abort": Test #2 Not passed
[ 1][t 0][1582283084.210941076][fift-main.cpp:196]      Error interpreting file `lottery-test-suite.fif`: error interpreting included file `lottery-test-suite.fif` : lottery-test-suite.fif:67: abort": Test #2 Not passed

Bu mərhələdə lottery-test-suite.fif kimi görünməlidir по ссылке.

İndi ağıllı müqaviləyə əks məntiqi əlavə edək 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 göndərdiyimiz mesajdır.

Etdiyimiz ilk şey mesajda məlumatların olub olmadığını yoxlamaqdır, əgər yoxdursa, sadəcə çıxırıq.

Sonra mesajı təhlil edirik. in_msg~load_uint(32) 165, 32-bit nömrəsini yükləyir unsigned int ötürülən mesajdan.

Sonra ağıllı müqavilə yaddaşından 32 bit yükləyirik. Yüklənmiş nömrənin keçənə uyğun olduğunu yoxlayırıq, yoxsa, istisna edirik. Bizim vəziyyətimizdə qeyri-matç ötürmə apardığımız üçün istisna atılmalıdır.

İndi kompilyasiya edək.

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

Yaranan kodu kopyalayın lottery-test-suite.fif, son sətri əvəz etməyi unutmadan.

Testin keçdiyini yoxlayırıq:

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

Burada Siz cari nəticələrlə müvafiq öhdəliyi görə bilərsiniz.

Qeyd edək ki, ağıllı müqavilənin tərtib edilmiş kodunu daim testləri olan bir fayla köçürmək əlverişsizdir, ona görə də kodu bizim üçün sabitə yazacaq bir skript yazacağıq və sadəcə tərtib edilmiş kodu istifadə edərək testlərimizə bağlayacağıq. "include".

Layihə qovluğunda bir fayl yaradın build.sh aşağıdakı məzmunla.

#!/bin/bash

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

Gəlin onu icra edilə bilən hala gətirək.

chmod +x ./build.sh

İndi müqaviləni tərtib etmək üçün sadəcə skriptimizi işə salın. Ancaq bundan başqa, onu sabitə yazmalıyıq code. Beləliklə, yeni bir fayl yaradacağıq lotter-compiled-for-test.fiffayla daxil edəcəyik lottery-test-suite.fif.

Gəlin sh-ə skirpt kodu əlavə edək ki, bu da sadəcə olaraq tərtib edilmiş faylı təkrarlayacaq lotter-compiled-for-test.fif və içindəki son sətri dəyişdirin.

# 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

İndi yoxlamaq üçün nəticədə skripti işə salaq və fayl yaradılacaq lottery-compiled-for-test.fif, biz özümüzə daxil edəcəyik lottery-test-suite.fif

В lottery-test-suite.fif müqavilə kodunu silin və xətti əlavə edin "lottery-compiled-for-test.fif" include.

Onların keçdiyini yoxlamaq üçün testlər keçiririk.

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

Əla, indi testlərin işə salınmasını avtomatlaşdırmaq üçün bir fayl yaradaq test.sh, ilk icra edəcək build.sh, və sonra testləri işə salın.

touch test.sh
chmod +x test.sh

İçəridə yazırıq

./build.sh 

echo "nCompilation completedn"

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

Gəl edək test.sh və testlərin işlədiyinə əmin olmaq üçün onu işə salın.

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

Müqavilənin tərtib edildiyini və sınaqların aparıldığını yoxlayırıq.

Əla, indi başlanğıcda test.sh Testlər dərhal tərtib olunacaq və həyata keçiriləcək. Budur link törətmək.

Tamam, davam etməzdən əvvəl, rahatlıq üçün daha bir şey edək.

Qovluq yaradaq build kopyalanan müqaviləni və onun sabitə yazılmış klonunu burada saxlayacağıq lottery-compiled.fif, lottery-compiled-for-test.fif. Gəlin bir qovluq da yaradaq test test faylı harada saxlanacaq? lottery-test-suite.fif və potensial olaraq digər dəstəkləyici fayllar. Müvafiq dəyişikliklərə keçid.

Gəlin ağıllı müqaviləni inkişaf etdirməyə davam edək.

Sonra mesajın alındığını və düzgün nömrəni göndərdiyimiz zaman mağazada sayğacın yeniləndiyini yoxlayan bir test olmalıdır. Amma bunu sonra edəcəyik.

İndi ağıllı müqavilədə hansı məlumat strukturunun və hansı məlumatların saxlanması lazım olduğunu düşünək.

Saxladığımız hər şeyi təsvir edəcəyəm.

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

Sonra iki funksiya yazmalısınız. Birinciyə zəng edək pack_state(), sonradan ağıllı müqavilə yaddaşında saxlamaq üçün məlumatları yığacaq. İkincini çağıraq unpack_state() yaddaşdan məlumatları oxuyacaq və qaytaracaq.

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

Bu iki funksiyanı ağıllı müqavilənin başlanğıcına əlavə edirik. Bu nəticə verəcək bu ara nəticə.

Məlumatları saxlamaq üçün daxili funksiyanı çağırmalısınız set_data() və məlumat yazacaq pack_state() ağıllı müqavilə anbarında.

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

İndi məlumatların yazılması və oxunması üçün əlverişli funksiyalarımız olduğundan, davam edə bilərik.

Kənardan gələn mesajın müqavilə sahibi (və ya şəxsi açara çıxışı olan başqa bir istifadəçi) tərəfindən imzalandığını yoxlamaq lazımdır.

Ağıllı müqaviləni dərc etdikdə, onu gələcək istifadə üçün saxlanacaq yaddaşda lazım olan məlumatlarla işə sala bilərik. Biz orada açıq açarı qeyd edəcəyik ki, daxil olan mesajın müvafiq şəxsi açarla imzalandığını yoxlaya bilək.

Davam etməzdən əvvəl şəxsi açar yaradaq və ona yazaq test/keys/owner.pk. Bunun üçün interaktiv rejimdə Fift-i işə salaq və dörd əmri yerinə yetirək.

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

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

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

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

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

Qovluq yaradaq keys qovluğun içərisində test və orada şəxsi açarı yazın.

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

Cari qovluqda bir fayl görürük owner.pk.

Açıq açarı yığından çıxarırıq və lazım olduqda şəxsi açardan əldə edə bilərik.

İndi imza yoxlaması yazmalıyıq. Testdən başlayaq. Əvvəlcə funksiyadan istifadə edərək fayldan şəxsi açarı oxuyuruq file>B və onu dəyişənə yazın owner_private_key, sonra funksiyadan istifadə edin priv>pub şəxsi açarı açıq açara çevirin və nəticəni daxil edin 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 !

Hər iki açara ehtiyacımız olacaq.

Biz ağıllı müqavilə yaddaşını funksiyada olduğu kimi eyni ardıcıllıqla ixtiyari məlumatlarla işə salırıq pack_state()və onu dəyişənə yazın 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 !

Sonra, imzalanmış bir mesaj tərtib edəcəyik, o, yalnız imza və sayğac dəyərini ehtiva edəcəkdir.

Əvvəlcə ötürmək istədiyimiz məlumatları yaradırıq, sonra onu şəxsi açarla imzalayırıq və nəhayət imzalanmış mesaj yaradırıq.

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 !  

Nəticədə smart müqaviləyə göndərəcəyimiz mesaj dəyişəndə ​​qeyd olunur message_to_send, funksiyalar haqqında hashu, ed25519_sign_uint oxuya bilərsiniz Fift sənədlərində.

Və sınaqdan keçmək üçün yenidən zəng edirik.

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

Burada belədir Testləri olan fayl bu mərhələdə belə görünməlidir.

Testi keçirək və o, uğursuz olacaq, ona görə də ağıllı müqaviləni dəyişəcəyik ki, o, bu formatda mesajları qəbul edə və imzanı yoxlaya bilsin.

Əvvəlcə mesajdan imzanın 512 bitini sayırıq və onu dəyişənə yazırıq, sonra isə sayğac dəyişəninin 32 bitini hesab edirik.

Ağıllı müqavilə yaddaşından məlumatları oxumaq funksiyamız olduğundan, biz ondan istifadə edəcəyik.

Sonra saxlama ilə köçürülən sayğacın yoxlanılması və imzanın yoxlanılmasıdır. Bir şey uyğun gəlmirsə, müvafiq kodla bir istisna atırıq.

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

Müvafiq öhdəlik burada.

Testləri keçirək və ikinci testin uğursuz olduğunu görək. İki səbəbə görə, mesajda kifayət qədər bit yoxdur və yaddaşda kifayət qədər bit yoxdur, buna görə də təhlil zamanı kod çökür. Göndərdiyimiz mesaja imza əlavə etməliyik və yaddaşı son sınaqdan kopyalamalıyıq.

İkinci testdə bir mesaj imzası əlavə edəcəyik və ağıllı müqavilə yaddaşını dəyişdirəcəyik. Burada belədir testləri olan fayl indiki kimi görünür.

Dördüncü testi yazaq, orada başqasının şəxsi açarı ilə imzalanmış bir mesaj göndərəcəyik. Gəlin başqa şəxsi açar yaradaq və onu faylda saxlayaq not-owner.pk. Mesajı bu şəxsi açarla imzalayacağıq. Testləri keçirək və bütün testlərin keçdiyinə əmin olaq. öhdəsindən gəlmək bu dəqiqə.

İndi nəhayət ağıllı müqavilə məntiqinin tətbiqinə keçə bilərik.
В recv_external() iki növ mesaj qəbul edəcəyik.

Müqaviləmizdə oyunçuların itkiləri toplanacağı üçün bu pul lotereyanın yaradıcısına köçürülməlidir. Lotereya yaradıcısının pul kisəsinin ünvanı müqavilə yaradılarkən anbarda qeyd olunur.

Hər halda, itirənlərin qramlarını göndərdiyimiz ünvanı dəyişdirmək qabiliyyətinə ehtiyacımız var. Biz həmçinin lotereyadan sahibinin ünvanına qram göndərə bilməliyik.

Birincidən başlayaq. Əvvəlcə mesajı göndərdikdən sonra smart müqavilənin yeni ünvanı yaddaşda saxladığını yoxlayacaq bir test yazaq. Nəzərə alın ki, mesajda sayğac və yeni ünvandan əlavə biz də ötürürük action 7 bitlik tam qeyri-mənfi nömrə, ondan asılı olaraq smart müqavilədə mesajı necə emal edəcəyimizi seçəcəyik.

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

Testdə smart-kontrakt yaddaşının necə sıradan çıxarıldığını görə bilərsiniz storage Beşdə. Dəyişənlərin sıradan çıxarılması Fift sənədlərində təsvir edilmişdir.

Linki təhvil verin əlavə xəmir ilə.

Testi keçirək və uğursuz olduğuna əmin olun. İndi lotereya sahibinin ünvanını dəyişmək üçün məntiq əlavə edək.

Ağıllı müqavilədə təhlil etməyə davam edirik message, oxuyun action. Nəzərinizə çatdıraq ki, ikimiz olacaq action: ünvanı dəyişdirin və qram göndərin.

Sonra müqavilə sahibinin yeni ünvanını oxuyub anbarda saxlayırıq.
Testləri keçiririk və üçüncü testin uğursuz olduğunu görürük. Müqavilənin testdə çatışmayan mesajdan 7 biti əlavə olaraq təhlil etməsi səbəbindən qəzaya uğradı. Mesaja mövcud olmayanı əlavə edin action. Testləri keçirək və hər şeyin keçdiyini görək. Burada dəyişikliklərə əməl etmək. Əla.

İndi gəlin qeyd olunmuş sayda qramın əvvəllər saxlanmış ünvana göndərilməsinin məntiqini yazaq.

Əvvəlcə bir test yazaq. İki test yazacağıq, biri kifayət qədər balans olmadıqda, ikincisi hər şey uğurla keçməlidir. Testlərə baxmaq olar bu öhdəlikdə.

İndi kodu əlavə edək. Əvvəlcə iki köməkçi üsul yazaq. İlk əldə etmə üsulu ağıllı müqavilənin cari balansını tapmaqdır.

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

İkincisi isə başqa bir ağıllı müqaviləyə qram göndərmək üçündür. Bu üsulu başqa bir ağıllı müqavilədən tamamilə köçürdüm.

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

Gəlin bu iki üsulu ağıllı müqaviləyə əlavə edək və məntiqi yazaq. Əvvəlcə mesajdan qramların sayını təhlil edirik. Sonra balansı yoxlayırıq, kifayət deyilsə, istisna edirik. Hər şey qaydasındadırsa, o zaman qramları qeyd olunan ünvana göndəririk və sayğacı yeniləyirik.

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

Burada belədir hal-hazırda ağıllı müqavilə kimi görünür. Testləri keçirək və keçdiyinə əmin olaq.

Yeri gəlmişkən, hər dəfə işlənmiş mesaj üçün smart müqavilədən komissiya tutulur. Ağıllı müqavilə mesajlarının sorğunu yerinə yetirməsi üçün əsas yoxlamalardan sonra zəng etməlisiniz accept_message().

İndi daxili mesajlara keçək. Əslində, biz yalnız qramları qəbul edəcəyik və oyunçu qalib gələrsə, ikiqat məbləği, uduzsa, üçdə birini sahibinə geri göndərəcəyik.

Əvvəlcə sadə bir test yazaq. Bunu etmək üçün bizə ağıllı müqavilənin qramlarını göndərdiyimiz smart müqavilənin sınaq ünvanı lazımdır.

Ağıllı müqavilə ünvanı iki rəqəmdən, iş zəncirinə cavabdeh olan 32 bitlik tam ədəddən və bu iş zəncirindəki 256 bitlik qeyri-mənfi tam ədəd unikal hesab nömrəsindən ibarətdir. Məsələn, -1 və 12345, bu faylda saxlayacağımız ünvandır.

Ünvanı saxlamaq üçün funksiyanı kopyaladım 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

Gəlin funksiyanın necə işlədiyinə baxaq, bu, Fiftin necə işlədiyini başa düşəcək. Fift-i interaktiv rejimdə işə salın.

~/TON/build/crypto/fift -i 

Əvvəlcə yığına -1, 12345 və gələcək faylın "sender.addr" adını basırıq:

-1 12345 "sender.addr" 

Növbəti addım funksiyanı yerinə yetirməkdir -rot, bu, yığını elə dəyişdirir ki, yığının yuxarı hissəsində unikal ağıllı müqavilə nömrəsi var:

"sender.addr" -1 12345

256 u>B 256 bitlik mənfi olmayan tam ədədi bayta çevirir.

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap yığının yuxarı iki elementini dəyişdirir.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

32 i>B 32 bitlik tam ədədi bayta çevirir.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ iki bayt ardıcıllığını birləşdirir.

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

Yenə də swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

Və nəhayət baytlar fayla yazılır B>file. Bundan sonra yığınımız boşdur. Dayanırıq Fift. Cari qovluqda fayl yaradılıb sender.addr. Faylı yaradılmış qovluğa köçürək test/addresses/.

Ağıllı müqaviləyə qram göndərəcək sadə bir test yazaq. Budur öhdəlik.

İndi isə lotereyanın məntiqinə nəzər salaq.

Etdiyimiz ilk şey mesajı yoxlamaqdır bounced ya yoxsa bounced, onda biz buna məhəl qoymuruq. bounced o deməkdir ki, hansısa xəta baş verərsə, müqavilə qramları qaytaracaq. Birdən xəta baş verərsə, qramları qaytarmayacağıq.

Yoxlayırıq, əgər balans yarım qramdan azdırsa, o zaman mesajı sadəcə qəbul edirik və ona məhəl qoymuruq.

Sonra, mesajın gəldiyi ağıllı müqavilənin ünvanını təhlil edirik.

Yaddaşdakı məlumatları oxuyuruq və iyirmidən çox olan köhnə mərcləri tarixdən silirik. Rahatlıq üçün üç əlavə funksiya yazdım pack_order(), unpack_order(), remove_old_orders().

Sonra, balansın ödəniş üçün kifayət etmədiyinə baxırıq, onda hesab edirik ki, bu bir mərc deyil, doldurmadır və doldurmanı saxlaya bilərsiniz. orders.

Sonra nəhayət ağıllı müqavilənin mahiyyəti.

Birincisi, oyunçu uduzsa, biz bunu mərc tarixçəsində saxlayırıq və məbləğ 3 qramdan çox olarsa, smart müqavilənin sahibinə 1/3 göndəririk.

Əgər oyunçu qalib gələrsə, biz ikiqat məbləği oyunçunun ünvanına göndəririk və sonra mərc haqqında məlumatı tarixdə saxlayırıq.

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

Vəssalam. Müvafiq öhdəlik.

İndi qalan şey sadədir, gəlin əldə üsulları yaradaq ki, müqavilənin vəziyyəti haqqında xarici dünyadan məlumat ala bilək (əslində, onların ağıllı müqavilə yaddaşından məlumatları oxuyun).

Get metodlarını əlavə edək. Ağıllı müqavilə haqqında məlumatı necə almaq barədə aşağıda yazacağıq.

Ağıllı müqavilə dərc edərkən baş verən ilk sorğunu emal edəcək kodu da əlavə etməyi unutdum. Müvafiq öhdəlik. Və daha da düzəldildi məbləğin 1/3 hissəsinin sahibinin hesabına göndərilməsi ilə bağlı səhv.

Növbəti addım ağıllı müqaviləni dərc etməkdir. Qovluq yaradaq requests.

Nəşr kodunu əsas götürdüm simple-wallet-code.fc olan tapa bilərsiniz rəsmi depoda.

Diqqət yetirməyə dəyər bir şey. Ağıllı müqavilə yaddaşı və giriş mesajı yaradırıq. Bundan sonra ağıllı müqavilənin ünvanı yaradılır, yəni ünvan TON-da dərc edilməzdən əvvəl də məlumdur. Bundan sonra, bu ünvana bir neçə qram göndərməlisiniz və yalnız bundan sonra ağıllı müqavilənin özü ilə bir fayl göndərməlisiniz, çünki şəbəkə smart müqaviləni və ondakı əməliyyatları saxlamaq üçün komissiya alır (ağıllı saxlayan və icra edən təsdiqləyicilər). müqavilələr). Koda burada baxmaq olar.

Sonra nəşr kodunu icra edirik və alırıq lottery-query.boc ağıllı müqavilə faylı və ünvanı.

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

Yaradılmış faylları yadda saxlamağı unutmayın: lottery-query.boc, lottery.addr, lottery.pk.

Digər şeylər arasında, icra qeydlərində ağıllı müqavilənin ünvanını görəcəyik.

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

Sadəcə əylənmək üçün TON-a müraciət edək

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

Və bu ünvanla hesabın boş olduğunu görəcəyik.

account state is empty

ünvana göndəririk 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 Gram və bir neçə saniyədən sonra eyni əmri yerinə yetiririk. Qramları göndərmək üçün istifadə edirəm rəsmi pul kisəsi, və məqalənin sonunda danışacağım test qramları üçün söhbətdən kimsədən soruşa bilərsiniz.

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Başlanmamış kimi görünür (state:account_uninit) eyni ünvana və 1 nanoqramlıq balansa malik ağıllı müqavilə.

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

İndi ağıllı müqaviləni dərc edək. Lite-client-i işə salaq və icra edək.

> 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 

Müqavilənin dərc olunduğunu yoxlayaq.

> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Digər şeylər arasında alırıq.

  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

Biz bunu görürük account_active.

Dəyişikliklərə uyğun olaraq öhdəlik götürün burada.

İndi ağıllı müqavilə ilə qarşılıqlı əlaqə üçün sorğular yaradaq.

Daha doğrusu, birincisini müstəqil iş olaraq ünvanı dəyişmək üçün, ikincisini isə sahibinin ünvanına qram göndərmək üçün edəcəyik. Əslində, qram göndərmək üçün testdə olduğu kimi eyni şeyi etməliyik.

Bu, ağıllı müqaviləyə göndərəcəyimiz mesajdır msg_seqno 165, action Göndərmək üçün 2 və 9.5 qram.

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

Mesajı şəxsi açarınızla imzalamağı unutmayın lottery.pkAğıllı müqavilə yaratarkən əvvəllər yaradılmışdır. Budur müvafiq öhdəlik.

Get metodlarından istifadə edərək ağıllı müqavilədən məlumat almaq

İndi ağıllı müqavilə almaq üsullarını necə işlətməyə baxaq.

Başlat lite-client və yazdığımız get metodlarını işə salın.

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

В result funksiyanın qaytardığı dəyəri ehtiva edir balance() ağıllı müqaviləmizdən.
Daha bir neçə üsul üçün də eyni şeyi edəcəyik.

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

Gəlin mərc tarixçənizi soruşaq.

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

Biz lite-client-dən istifadə edəcəyik və saytda smart müqavilə haqqında məlumatı göstərmək üçün üsullar əldə edəcəyik.

Veb saytında ağıllı müqavilə məlumatlarının göstərilməsi

Ağıllı müqavilədəki məlumatları rahat şəkildə göstərmək üçün Python-da sadə veb sayt yazdım. Burada onun üzərində ətraflı dayanmayacağam və saytı dərc edəcəyəm bir öhdəlikdə.

TON üçün sorğular edilir Python köməyi ilə lite-client. Rahatlıq üçün sayt Docker-də paketlənmiş və Google Cloud-da dərc edilmişdir. Link.

Çalışıram

İndi qramları doldurmaq üçün ora göndərməyə çalışaq cüzdan. 40 qram göndərəcəyik. Və aydınlıq üçün bir neçə bahis edək. Saytın mərclərin tarixini, cari uduş faizini və digər faydalı məlumatları göstərdiyini görürük.

GörürükBirincini qazandıq, ikincini itirdik.

Sözündən sonra

Məqalə gözlədiyimdən xeyli uzun oldu, bəlkə də daha qısa ola bilərdi və ya sadəcə TON haqqında heç nə bilməyən və onunla qarşılıqlı əlaqə qura bilən o qədər də sadə olmayan ağıllı müqavilə yazıb dərc etmək istəyən şəxs üçün o. Bəlkə də bəzi şeyləri daha sadə izah etmək olardı.

Bəlkə də icranın bəzi aspektləri daha səmərəli və zərif şəkildə həyata keçirilə bilərdi, lakin o zaman məqaləni hazırlamaq daha çox vaxt aparardı. Ola bilər ki, mən haradasa səhv etmişəm və ya nəyisə başa düşməmişəm, ona görə də ciddi bir iş görürsünüzsə, rəsmi sənədlərə və ya TON kodu olan rəsmi depoya etibar etməlisiniz.

Qeyd etmək lazımdır ki, TON özü hələ də aktiv inkişaf mərhələsində olduğundan, bu məqalədəki hər hansı bir addımı pozacaq dəyişikliklər baş verə bilər (bu, mən yazarkən baş verdi, artıq düzəldildi), lakin ümumi yanaşma belədir. dəyişmək ehtimalı azdır.

TON-un gələcəyi haqqında danışmayacağam. Ola bilsin ki, platforma böyük bir şeyə çevriləcək və biz onu öyrənməyə vaxt sərf etməliyik və indi məhsullarımızla yeri doldurmalıyıq.

TON-dan daha böyük istifadəçilərin potensial auditoriyası olan Facebook-dan Libra da var. Mən Tərəzi haqqında demək olar ki, heç nə bilmirəm, foruma görə orada TON icmasından daha çox fəaliyyət var. TON-un tərtibatçıları və icması daha çox yeraltı kimi olsa da, bu da gözəldir.

References

  1. Rəsmi TON sənədləri: https://test.ton.org
  2. Rəsmi TON deposu: https://github.com/ton-blockchain/ton
  3. Müxtəlif platformalar üçün rəsmi pul kisəsi: https://wallet.ton.org
  4. Bu məqalədən ağıllı müqavilə deposu: https://github.com/raiym/astonished
  5. Ağıllı müqavilə saytına keçid: https://ton-lottery.appspot.com
  6. FunC üçün Visual Studio Kodunun genişləndirilməsi üçün depo: https://github.com/raiym/func-visual-studio-plugin
  7. Telegram-da TON haqqında söhbət edin, bu, həqiqətən ilkin mərhələdə onu anlamağa kömək etdi. Düşünürəm ki, TON üçün nəsə yazanların hamısı oradadır desəm, səhv olmaz. Orada test qramlarını da istəyə bilərsiniz. https://t.me/tondev_ru
  8. TON haqqında faydalı məlumat tapdığım başqa bir söhbət: https://t.me/TONgramDev
  9. Müsabiqənin birinci mərhələsi: https://contest.com/blockchain
  10. Müsabiqənin ikinci mərhələsi: https://contest.com/blockchain-2

Mənbə: www.habr.com

Добавить комментарий