O tome kako napisati i objaviti pametni ugovor u Telegram otvorenoj mreži (TON)

O tome kako napisati i objaviti pametni ugovor u TON-u

O čemu je ovaj članak?

U članku ću pričati o tome kako sam učestvovao u prvom (od dva) Telegram blockchain natjecanja, nisam dobio nagradu i odlučio da svoje iskustvo zabilježim u članku kako ne bi potonuo u zaborav i, možda, pomogao nekoga.

Pošto nisam želio da pišem apstraktni kod, već da nešto radim, za članak sam napisao pametni ugovor za instant lutriju i web stranicu koja prikazuje podatke pametnog ugovora direktno iz TON-a bez korištenja međuskladišta.

Članak će biti koristan onima koji žele sklopiti svoj prvi pametni ugovor u TON-u, ali ne znaju odakle da počnu.

Koristeći lutriju kao primjer, preći ću od instaliranja okruženja do objavljivanja pametnog ugovora, interakcije s njim i pisanja web stranice za primanje i objavljivanje podataka.

O učešću na takmičenju

Prošlog oktobra, Telegram je najavio blockchain takmičenje sa novim jezicima Fift и FunC. Bilo je potrebno izabrati bilo koji od pet predloženih pametnih ugovora. Mislio sam da bi bilo lijepo napraviti nešto drugačije, naučiti jezik i napraviti nešto, čak i ako neću morati ništa drugo pisati u budućnosti. Osim toga, tema je stalno na usnama.

Vrijedi reći da nisam imao iskustva u razvoju pametnih ugovora.

Planirao sam da učestvujem do samog kraja dok ne budem mogao pa da napišem pregledni članak, ali nisam uspeo odmah u prvom. I napisao novčanik sa uključenim višestrukim potpisom FunC i generalno je funkcionisalo. Uzeo sam to kao osnovu pametni ugovor na Solidityju.

Tada sam mislio da je ovo sasvim dovoljno da zauzmem barem neko nagradno mjesto. Kao rezultat toga, oko 40 od ​​60 učesnika je postalo nagrađeno, a ja nisam bio među njima. Generalno, u ovome nema ništa loše, ali jedna stvar me je zasmetala. U trenutku objavljivanja rezultata nije urađen pregled testa za moj ugovor, pitao sam učesnike u ćaskanju da li ima još neko ko ga nema, nije bilo.

Očigledno obraćajući pažnju na moje poruke, dva dana kasnije sudije su objavile komentar i još uvijek ne razumijem da li su slučajno propustili moj pametni ugovor tokom suđenja ili su jednostavno pomislili da je toliko loš da mu nije potreban komentar. Postavio sam pitanje na stranici, ali nisam dobio odgovor. Iako nije tajna ko je sudio, smatrao sam da je nepotrebno pisati lične poruke.

Mnogo vremena je potrošeno na razumijevanje, pa je odlučeno da se napiše članak. S obzirom da još nema puno informacija, ovaj će članak svima koji su zainteresirani pomoći uštedjeti vrijeme.

Koncept pametnih ugovora u TON-u

Pre nego što bilo šta napišete, morate da shvatite sa koje strane da pristupite ovoj stvari. Stoga ću vam sada reći od kojih dijelova se sastoji sistem. Tačnije, koje dijelove trebate znati da biste napisali makar kakav ugovor o radu.

Fokusiraćemo se na pisanje pametnog ugovora i rad sa njima TON Virtual Machine (TVM), Fift и FunC, pa je članak više kao opis razvoja redovnog programa. Ovdje se nećemo zadržavati na tome kako sama platforma funkcionira.

Općenito o tome kako funkcionira TVM i jezik Fift postoji dobra zvanična dokumentacija. Dok sam učestvovao na takmičenju i sada dok sam pisao aktuelni ugovor, često sam joj se obraćao.

Glavni jezik na kojem su pametni ugovori napisani je FunC. Trenutno ne postoji dokumentacija o tome, pa da biste nešto napisali morate proučiti primjere pametnih ugovora iz službenog repozitorija i implementaciju samog jezika tamo, plus možete pogledati primjere pametnih ugovora iz prethodna dva takmičenja. Linkovi na kraju članka.

Recimo da smo već napisali pametni ugovor za FunC, nakon toga kompajliramo kod u Fift asembler.

Sastavljeni pametni ugovor ostaje za objavljivanje. Da biste to učinili, morate upisati funkciju Fift, koji će uzeti kod pametnog ugovora i neke druge parametre kao ulaz, a izlaz će biti datoteka s ekstenzijom .boc (što znači „vreća ćelija“), i, u zavisnosti od toga kako to napišemo, privatni ključ i adresa, koji se generišu na osnovu koda pametnog ugovora. Već sada možete poslati gram na adresu pametnog ugovora koji još nije objavljen.

Za objavljivanje pametnog ugovora u TON primljeno .boc fajl će se morati poslati u blockchain pomoću laganog klijenta (više o tome u nastavku). Ali prije objavljivanja, morate prenijeti gram na generiranu adresu, inače pametni ugovor neće biti objavljen. Nakon objavljivanja, možete stupiti u interakciju sa pametnim ugovorom tako što ćete mu poslati poruke izvana (na primjer, korištenjem lakog klijenta) ili iznutra (na primjer, jedan pametni ugovor šalje drugom poruku unutar TON).

Kada shvatimo kako se kod objavljuje, postaje lakše. Otprilike znamo šta želimo napisati i kako će naš program funkcionirati. I dok pišemo, tražimo kako je to već implementirano u postojećim pametnim ugovorima, ili gledamo u implementacijski kod Fift и FunC u zvaničnom repozitoriju, ili pogledajte u službenoj dokumentaciji.

Vrlo često sam tražio ključne riječi u Telegram chatu gdje su se okupili svi učesnici takmičenja i zaposleni u Telegramu, i dogodilo se da su se tokom takmičenja svi okupili i počeli da razgovaraju o Fiftu i FunC-u. Link na kraju članka.

Vrijeme je da pređemo s teorije na praksu.

Priprema okoline za rad sa TON-om

Uradio sam sve što će biti opisano u članku o MacOS-u i još jednom sam to provjerio u čistom Ubuntu 18.04 LTS na Dockeru.

Prva stvar koju trebate učiniti je preuzeti i instalirati lite-client sa kojim možete slati zahtjeve TON-u.

Upute na službenoj web stranici vrlo detaljno i jasno opisuju proces instalacije i izostavljaju neke detalje. Ovdje slijedimo upute, usput instalirajući ovisnosti koje nedostaju. Nisam sam kompajlirao svaki projekat i instalirao ga iz zvaničnog Ubuntu repozitorija (na MacOS-u koji sam koristio 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 

Nakon što su sve zavisnosti instalirane, možete instalirati lite-client, Fift, FunC.

Prvo, kloniramo TON spremište zajedno sa njegovim zavisnostima. Radi praktičnosti, sve ćemo raditi u fascikli ~/TON.

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

Repozitorijum takođe čuva implementacije Fift и FunC.

Sada smo spremni za montažu projekta. Kod spremišta se klonira u folder ~/TON/ton. The ~/TON kreirajte folder build i prikupiti projekat u njemu.

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

Pošto ćemo napisati pametni ugovor, ne treba nam samo lite-clientAli Fift с FunC, pa hajde da kompajliramo sve. Nije brz proces, pa čekamo.

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

Zatim preuzmite konfiguracijsku datoteku koja sadrži podatke o čvoru na koji lite-client će se povezati.

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

Upućivanje prvih zahtjeva TON-u

Sada krenimo lite-client.

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

Ako je gradnja bila uspješna, nakon pokretanja vidjet ćete dnevnik veze lakog klijenta s čvorom.

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

Možete pokrenuti naredbu help i pogledajte koje su komande dostupne.

help

Hajde da navedemo naredbe koje ćemo koristiti u ovom članku.

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

Sada smo spremni za pisanje samog ugovora.

Реализация

Ideja

Kao što sam gore napisao, pametni ugovor koji pišemo je lutrija.

Štaviše, ovo nije lutrija u kojoj morate kupiti tiket i čekati sat, dan ili mjesec, već instant u kojoj korisnik prelazi na adresu ugovora N grama, i odmah ga dobije nazad 2 * N grama ili gubi. Napravit ćemo vjerovatnoću pobjede oko 40%. Ako nema dovoljno grama za plaćanje, transakciju ćemo smatrati dopunom.

Osim toga, važno je da se opklade mogu vidjeti u realnom vremenu iu prikladnom obliku, tako da korisnik može odmah shvatiti da li je dobio ili izgubio. Stoga morate napraviti web stranicu koja će prikazivati ​​opklade i rezultate direktno iz TON-a.

Pisanje pametnog ugovora

Radi praktičnosti, istaknuo sam kod za FunC; dodatak se može pronaći i instalirati u Visual Studio Code pretrazi; ako iznenada poželite nešto dodati, učinio sam dodatak javno dostupnim. Takođe, neko je prethodno napravio dodatak za rad sa Fiftom, možete ga takođe instalirati i pronaći u VSC-u.

Kreirajmo odmah spremište u koje ćemo urezati međurezultate.

Da bismo sebi olakšali život, napisat ćemo pametni ugovor i testirati ga lokalno dok ne bude spreman. Tek nakon toga ćemo to objaviti u TON-u.

Pametni ugovor ima dvije eksterne metode kojima se može pristupiti. prvo, recv_external() ova funkcija se izvršava kada zahtjev za ugovorom dolazi iz vanjskog svijeta, odnosno ne iz TON-a, na primjer, kada sami generišemo poruku i šaljemo je preko lite-klijenta. Sekunda, recv_internal() ovo je kada se, unutar samog TON-a, bilo koji ugovor odnosi na naš. U oba slučaja, možete proslijediti parametre funkciji.

Počnimo s jednostavnim primjerom koji će raditi ako je objavljen, ali u njemu nema funkcionalnog opterećenja.

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

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

Ovdje moramo objasniti šta je to slice. Svi podaci pohranjeni u TON Blockchain-u su zbirka TVM cell ili jednostavno cell, u takvu ćeliju možete pohraniti do 1023 bita podataka i do 4 veze s drugim ćelijama.

TVM cell slice ili slice ovo je dio postojećeg cell se koristi za raščlanjivanje, kasnije će postati jasno. Najvažnije nam je da možemo da se prebacimo slice i ovisno o vrsti poruke, obraditi podatke u recv_external() ili recv_internal().

impure — ključna riječ koja označava da funkcija mijenja podatke pametnog ugovora.

Sačuvajmo šifru ugovora lottery-code.fc i kompajlirati.

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

Značenje zastavica može se vidjeti pomoću naredbe

~/TON/build/crypto/func -help

Sastavili smo Fift asemblerski kod 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

Može se pokrenuti lokalno, za to ćemo pripremiti okruženje.

Imajte na umu da se prva linija povezuje Asm.fif, ovo je kod napisan u Fiftu za Fift asembler.

Budući da želimo pokrenuti i testirati pametni ugovor lokalno, kreirat ćemo datoteku lottery-test-suite.fif i kopirajte prevedeni kod tamo, zamjenjujući zadnji red u njemu, koji upisuje kod pametnog ugovora u konstantu codeda biste ga zatim prebacili na virtuelnu mašinu:

"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

Za sada se čini jasnim, sada dodajmo istoj datoteci kod koji ćemo koristiti za pokretanje TVM-a.

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 snimamo kontekst, odnosno podatke s kojima će se TVM (ili stanje mreže) pokrenuti. Čak i tokom takmičenja, jedan od programera je pokazao kako se kreira c7 i kopirao sam. U ovom članku možda ćemo morati promijeniti rand_seed budući da generiranje slučajnog broja ovisi o tome i ako se ne promijeni, isti broj će biti vraćen svaki put.

recv_internal и recv_external konstante sa vrijednostima 0 i -1 bit će odgovorne za pozivanje odgovarajućih funkcija u pametnom ugovoru.

Sada smo spremni za kreiranje prvog testa za naš prazan pametni ugovor. Radi jasnoće, za sada ćemo dodati sve testove u istu datoteku lottery-test-suite.fif.

Kreirajmo varijablu storage i upišite praznu u nju cell, ovo će biti skladište pametnih ugovora.

message Ovo je poruka koju ćemo prenijeti pametnom kontaktu izvana. Za sada ćemo ga također učiniti praznim.

variable storage 
<b b> storage ! 

variable message 
<b b> message ! 

Nakon što smo pripremili konstante i varijable, pokrećemo TVM pomoću naredbe runvmctx i proslediti kreirane parametre na ulaz.

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

Na kraju ćemo uspjeti Volim ovo srednji kod za Fift.

Sada možemo pokrenuti rezultirajući kod.

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

Program bi trebao raditi bez grešaka i u izlazu ćemo vidjeti zapisnik izvršenja:

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

Odlično, napisali smo prvu radnu verziju pametnog ugovora.

Sada moramo dodati funkcionalnost. Prvo se pozabavimo porukama koje dolaze iz vanjskog svijeta u recv_external()

Programer sam bira format poruke koji ugovor može prihvatiti.

Ali obično

  • prvo, želimo zaštititi naš ugovor od vanjskog svijeta i učiniti ga tako da mu samo vlasnik ugovora može slati eksterne poruke.
  • drugo, kada pošaljemo ispravnu poruku TON-u, želimo da se to dogodi tačno jednom, a kada ponovo pošaljemo istu poruku, pametni ugovor je odbije.

Dakle, skoro svaki ugovor rješava ova dva problema, budući da naš ugovor prihvata eksterne poruke, moramo se pobrinuti i za to.

Uradićemo to obrnutim redosledom. Prvo, riješimo problem s ponavljanjem; ako je ugovor već primio takvu poruku i obradio je, neće je izvršiti drugi put. A onda ćemo riješiti problem tako da samo određeni krug ljudi može slati poruke pametnom ugovoru.

Postoje različiti načini za rješavanje problema s dupliranim porukama. Evo kako ćemo to uraditi. U pametnom ugovoru inicijaliziramo brojač primljenih poruka sa početnom vrijednošću 0. U svakoj poruci pametnom ugovoru ćemo dodati trenutnu vrijednost brojača. Ako se vrijednost brojača u poruci ne poklapa s vrijednošću u pametnom ugovoru, onda ga ne obrađujemo; ako ima, onda ga obrađujemo i povećavamo brojač u pametnom ugovoru za 1.

Vratimo se na lottery-test-suite.fif i dodajte mu drugi test. Ako pošaljemo pogrešan broj, kod bi trebao izbaciti izuzetak. Na primjer, neka podaci o ugovoru pohranjuju 166, a mi ćemo poslati 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"

Hajdemo.

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

I vidjet ćemo da je test izvršen sa greškom.

[ 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

U ovoj fazi lottery-test-suite.fif trebalo bi da izgleda link.

Sada dodajmo logiku brojača u pametni ugovor 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 leži poruka koju šaljemo.

Prvo što radimo je da provjerimo da li poruka sadrži podatke, ako ne, onda jednostavno izlazimo.

Zatim analiziramo poruku. in_msg~load_uint(32) učitava broj 165, 32-bitni unsigned int iz poslate poruke.

Zatim učitavamo 32 bita iz memorije pametnog ugovora. Provjeravamo da li se učitani broj podudara s proslijeđenim; ako ne, bacamo izuzetak. U našem slučaju, pošto prenosimo nepodudaranje, trebalo bi baciti izuzetak.

Sada da kompajliramo.

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

Kopirajte rezultirajući kod na lottery-test-suite.fif, ne zaboravljajući zamijeniti posljednji red.

Provjeravamo da li je test prošao:

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

Ovde Možete vidjeti odgovarajuće urezivanje sa trenutnim rezultatima.

Imajte na umu da je nezgodno stalno kopirati kompajlirani kod pametnog ugovora u datoteku sa testovima, pa hajde da napišemo skriptu koja će za nas upisati kod u konstantu, a mi ćemo jednostavno povezati kompajlirani kod sa našim testovima koristeći "include".

Kreirajte datoteku u folderu projekta build.sh sa sljedećim sadržajem.

#!/bin/bash

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

Učinimo ga izvršnim.

chmod +x ./build.sh

Sada samo pokrenite našu skriptu da sastavite ugovor. Ali pored ovoga, moramo to zapisati u konstantu code. Tako ćemo kreirati novu datoteku lotter-compiled-for-test.fif, koji ćemo uključiti u datoteku lottery-test-suite.fif.

Dodajmo skirpt kod u sh, koji će jednostavno duplicirati kompajlirani fajl lotter-compiled-for-test.fif i promijenite zadnji red u njemu.

# 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

Sada, da provjerimo, pokrenimo rezultirajuću skriptu i datoteka će biti generirana lottery-compiled-for-test.fif, koje ćemo uključiti u naše lottery-test-suite.fif

В lottery-test-suite.fif obrišite šifru ugovora i dodajte red "lottery-compiled-for-test.fif" include.

Pokrećemo testove kako bismo provjerili da li prolaze.

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

Odlično, sada da automatiziramo pokretanje testova, napravimo datoteku test.sh, koji će se prvo izvršiti build.sh, a zatim pokrenite testove.

touch test.sh
chmod +x test.sh

Pišemo unutra

./build.sh 

echo "nCompilation completedn"

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

Hajde da to uradimo test.sh i pokrenite ga kako biste bili sigurni da testovi rade.

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

Provjeravamo da li je ugovor sastavljen i da li su testovi izvršeni.

Odlično, sada na startu test.sh Testovi će biti sastavljeni i pokrenuti odmah. Evo linka za počiniti.

U redu, prije nego što nastavimo, učinimo još jednu stvar radi pogodnosti.

Kreirajmo folder build gdje ćemo pohraniti kopirani ugovor i njegov klon upisan u konstantu lottery-compiled.fif, lottery-compiled-for-test.fif. Kreirajmo i folder test gdje će biti pohranjena test datoteka? lottery-test-suite.fif i potencijalno druge prateće datoteke. Link do relevantnih promjena.

Nastavimo sa razvojem pametnog ugovora.

Zatim bi trebao biti test koji provjerava da li je poruka primljena i da li se brojač ažurira u prodavnici kada pošaljemo tačan broj. Ali to ćemo uraditi kasnije.

Sada razmislimo o tome koju strukturu podataka i koje podatke treba pohraniti u pametni ugovor.

Opisaću sve što skladištimo.

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

Zatim morate napisati dvije funkcije. Pozovimo prvog pack_state(), koji će spakovati podatke za naknadno pohranjivanje u memoriju pametnog ugovora. Pozovimo drugog unpack_state() će čitati i vraćati podatke iz skladišta.

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

Ove dvije funkcije dodajemo na početak pametnog ugovora. To će uspjeti Volim ovo srednji rezultat.

Za spremanje podataka morat ćete pozvati ugrađenu funkciju set_data() i pisaće podatke iz pack_state() u skladištu pametnih ugovora.

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

Sada kada imamo zgodne funkcije za pisanje i čitanje podataka, možemo krenuti dalje.

Moramo provjeriti da li je poruka koja dolazi izvana potpisana od strane vlasnika ugovora (ili drugog korisnika koji ima pristup privatnom ključu).

Kada objavimo pametni ugovor, možemo ga inicijalizirati s podacima koji su nam potrebni u skladištu, koji će biti sačuvani za buduću upotrebu. Tamo ćemo snimiti javni ključ kako bismo mogli provjeriti da li je dolazna poruka potpisana odgovarajućim privatnim ključem.

Prije nego što nastavimo, napravimo privatni ključ i upišemo ga test/keys/owner.pk. Da bismo to uradili, pokrenimo Fift u interaktivnom režimu i izvršimo četiri komande.

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

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

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

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

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

Kreirajmo folder keys unutar foldera test i tamo upišite privatni ključ.

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

Vidimo fajl u trenutnom folderu owner.pk.

Uklanjamo javni ključ iz steka i kada je potrebno možemo ga dobiti iz privatnog.

Sada treba da napišemo verifikaciju potpisa. Počnimo sa testom. Prvo čitamo privatni ključ iz datoteke koristeći funkciju file>B i zapišite ga u varijablu owner_private_key, a zatim pomoću funkcije priv>pub konvertujte privatni ključ u javni ključ i upišite rezultat 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 !

Trebat će nam oba ključa.

Inicijaliziramo memoriju pametnog ugovora sa proizvoljnim podacima istim redoslijedom kao u funkciji pack_state()i upišite ga u varijablu 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 !

Zatim ćemo sastaviti potpisanu poruku, ona će sadržavati samo potpis i vrijednost brojača.

Prvo kreiramo podatke koje želimo prenijeti, zatim ih potpisujemo privatnim ključem i na kraju generiramo potpisanu poruku.

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 !  

Kao rezultat, poruka koju ćemo poslati pametnom ugovoru se bilježi u varijablu message_to_send, o funkcijama hashu, ed25519_sign_uint možete čitati u dokumentaciji Fifta.

I ponovo pozivamo da izvršimo test.

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

Evo tako Fajl sa testovima bi u ovoj fazi trebao izgledati ovako.

Pokrenimo test i neće uspjeti, pa ćemo promijeniti pametni ugovor tako da može primati poruke ovog formata i provjeravati potpis.

Prvo izbrojimo 512 bita potpisa iz poruke i upišemo ga u varijablu, a zatim izbrojimo 32 bita varijable brojača.

Pošto imamo funkciju za čitanje podataka iz memorije pametnog ugovora, koristit ćemo je.

Sljedeća je provjera šaltera prenesenog sa skladištem i provjera potpisa. Ako se nešto ne podudara, onda bacimo izuzetak s odgovarajućim kodom.

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

Relevantno urezivanje ovde.

Pokrenimo testove i vidimo da drugi test nije uspio. Iz dva razloga, nema dovoljno bitova u poruci i nema dovoljno bitova u memoriji, pa se kod ruši prilikom raščlanjivanja. Moramo dodati potpis poruci koju šaljemo i kopirati memoriju iz posljednjeg testa.

U drugom testu ćemo dodati potpis poruke i promijeniti pohranu pametnog ugovora. Evo tako fajl sa testovima izgleda kao u ovom trenutku.

Napišimo četvrti test, u kojem ćemo poslati poruku potpisanu tuđim privatnim ključem. Kreirajmo drugi privatni ključ i spremimo ga u datoteku not-owner.pk. Poruku ćemo potpisati ovim privatnim ključem. Pokrenimo testove i uvjerimo se da svi testovi prođu. Počinite u ovom momentu.

Sada konačno možemo preći na implementaciju logike pametnog ugovora.
В recv_external() prihvatit ćemo dvije vrste poruka.

Pošto će naš ugovor akumulirati gubitke igrača, ovaj novac se mora prenijeti kreatoru lutrije. Adresa novčanika kreatora lutrije se bilježi u memoriji prilikom kreiranja ugovora.

Za svaki slučaj treba nam mogućnost promjene adrese na koju šaljemo gram gubitnika. Također bismo trebali moći slati grame sa lutrije na adresu vlasnika.

Počnimo s prvim. Napišimo prvo test koji će provjeriti da je nakon slanja poruke pametni ugovor sačuvao novu adresu u memoriji. Napominjemo da u poruci osim šaltera i nove adrese prenosimo i podatke action 7-bitni cijeli nenegativan broj, ovisno o njemu, birat ćemo kako ćemo obraditi poruku u pametnom ugovoru.

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

U testu možete vidjeti kako je smartcontract pohrana deserijalizirana storage Fift. Deserijalizacija varijabli je opisana u dokumentaciji Fift.

Veza za urezivanje sa dodatkom testa.

Pokrenimo test i uvjerimo se da ne uspije. Sada dodajmo logiku za promjenu adrese vlasnika lutrije.

U pametnom ugovoru nastavljamo raščlanjivanje message, pročitaj action. Podsjetimo da ćemo imati dva action: promijeniti adresu i poslati gram.

Zatim čitamo novu adresu vlasnika ugovora i spremamo je u skladište.
Pokrećemo testove i vidimo da treći test nije uspio. Ruši se zbog činjenice da ugovor sada dodatno analizira 7 bitova iz poruke, koji nedostaju u testu. Dodajte nepostojeću poruku action. Pokrenimo testove i vidimo da li je sve prošlo. ovdje posvetite se promjenama. Odlično.

Sada napišimo logiku slanja navedenog broja grama na prethodno sačuvanu adresu.

Prvo, hajde da napišemo test. Napisaćemo dva testa, jedan kada nema dovoljno balansa, drugi kada sve treba da prođe uspešno. Testovi se mogu pogledati u ovom urezivanju.

Sada dodajmo kod. Prvo, napišimo dvije pomoćne metode. Prva metoda dobivanja je saznanje trenutnog stanja pametnog ugovora.

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

A drugi je za slanje grama na drugi pametni ugovor. Potpuno sam kopirao ovu metodu iz drugog pametnog ugovora.

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

Dodajmo ove dvije metode pametnom ugovoru i napišemo logiku. Prvo analiziramo broj grama iz poruke. Zatim provjeravamo saldo, ako nije dovoljno bacamo izuzetak. Ako je sve u redu, šaljemo gram na sačuvanu adresu i ažuriramo brojač.

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

Evo tako izgleda kao pametni ugovor u ovom trenutku. Pokrenimo testove i uvjerimo se da su prošli.

Inače, provizija se oduzima od pametnog ugovora svaki put za obrađenu poruku. Da bi poruke pametnog ugovora izvršile zahtjev, nakon osnovnih provjera morate nazvati accept_message().

Sada pređimo na interne poruke. U stvari, prihvatit ćemo samo grame i vratiti dupli iznos igraču ako pobijedi i trećinu vlasniku ako izgubi.

Prvo, napišimo jednostavan test. Da bismo to učinili, potrebna nam je probna adresa pametnog ugovora sa koje navodno šaljemo gramove na pametni ugovor.

Adresa pametnog ugovora sastoji se od dva broja, 32-bitnog cijelog broja odgovornog za radni lanac i 256-bitnog nenegativnog cijelog jedinstvenog broja računa u ovom radnom lancu. Na primjer, -1 i 12345, ovo je adresa koju ćemo sačuvati u datoteku.

Kopirao sam funkciju za čuvanje adrese iz 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

Pogledajmo kako funkcija funkcionira, ovo će dati razumijevanje kako Fift radi. Pokrenite Fift u interaktivnom načinu.

~/TON/build/crypto/fift -i 

Prvo gurnemo -1, 12345 i ime buduće datoteke "sender.addr" na stog:

-1 12345 "sender.addr" 

Sljedeći korak je izvršavanje funkcije -rot, koji pomiče stog na takav način da se na vrhu hrpe nalazi jedinstveni broj pametnog ugovora:

"sender.addr" -1 12345

256 u>B pretvara 256-bitni nenegativni cijeli broj u bajtove.

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap mijenja gornja dva elementa steka.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

32 i>B pretvara 32-bitni cijeli broj u bajtove.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ povezuje dva niza bajtova.

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

Opet swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

I konačno se bajtovi upisuju u datoteku B>file. Nakon ovoga naš stog je prazan. Stajemo Fift. Fajl je kreiran u trenutnoj fascikli sender.addr. Premjestimo datoteku u kreirani folder test/addresses/.

Napišimo jednostavan test koji će poslati grame pametnom ugovoru. Evo polaganja.

Pogledajmo sada logiku lutrije.

Prvo što radimo je da provjerimo poruku bounced ili ne ako bounced, onda to ignorišemo. bounced znači da će ugovor vratiti gram ako dođe do greške. Nećemo vratiti gram ako se iznenada dogodi greška.

Provjeravamo, ako je stanje manje od pola grama, onda jednostavno prihvaćamo poruku i ignoriramo je.

Zatim analiziramo adresu pametnog ugovora s kojeg je stigla poruka.

Čitamo podatke iz skladišta, a zatim brišemo stare opklade iz historije ako ih ima više od dvadeset. Radi praktičnosti, napisao sam tri dodatne funkcije pack_order(), unpack_order(), remove_old_orders().

Zatim gledamo da li stanje nije dovoljno za plaćanje, onda smatramo da ovo nije opklada, već dopuna i čuvamo dopunu u orders.

Zatim konačno suština pametnog ugovora.

Prvo, ako igrač izgubi, pohranjujemo ga u historiju klađenja, a ako je iznos veći od 3 grama, 1/3 šaljemo vlasniku pametnog ugovora.

Ako igrač dobije, tada šaljemo dupli iznos na adresu igrača, a zatim pohranjujemo podatke o opkladi u historiji.

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

To je sve. Odgovarajuće urezivanje.

Sada ostaje samo jednostavno, kreirajmo get-metode kako bismo mogli dobiti informacije o stanju ugovora iz vanjskog svijeta (zapravo, pročitati podatke iz njihove memorije pametnih ugovora).

Hajde da dodamo metode get. U nastavku ćemo pisati o tome kako dobiti informacije o pametnom ugovoru.

Također sam zaboravio dodati kod koji će obraditi prvi zahtjev koji se pojavi prilikom objavljivanja pametnog ugovora. Odgovarajuće urezivanje. I dalje ispravljeno greška sa slanjem 1/3 iznosa na račun vlasnika.

Sljedeći korak je objavljivanje pametnog ugovora. Kreirajmo folder requests.

Uzeo sam šifru publikacije kao osnovu simple-wallet-code.fc što mogu naći u zvaničnom repozitoriju.

Nešto na šta vredi obratiti pažnju. Generiramo skladište pametnog ugovora i ulaznu poruku. Nakon toga se generiše adresa pametnog ugovora, odnosno adresa je poznata i prije objave u TON-u. Zatim na ovu adresu treba poslati nekoliko grama, a tek nakon toga treba poslati datoteku sa samim pametnim ugovorom, jer mreža uzima proviziju za pohranjivanje pametnog ugovora i operacije u njemu (validatori koji pohranjuju i izvršavaju smart ugovor ugovori). Kod možete pogledati ovdje.

Zatim izvršavamo kod za objavljivanje i dobivamo lottery-query.boc fajl pametnog ugovora i adresa.

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

Ne zaboravite da sačuvate generisane fajlove: lottery-query.boc, lottery.addr, lottery.pk.

Između ostalog, u evidenciji izvršenja vidjet ćemo adresu pametnog ugovora.

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

Iz zabave, uputimo zahtjev TON-u

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

I vidjet ćemo da je račun sa ovom adresom prazan.

account state is empty

Šaljemo na adresu 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 grama i nakon nekoliko sekundi izvršimo istu komandu. Za slanje grama koristim službeni novčanik, a možete zamoliti nekoga iz chata za test grame, o čemu ću govoriti na kraju članka.

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Izgleda kao neinicijalizirana (state:account_uninit) pametni ugovor sa istom adresom i stanjem od 1 nanograma.

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

Sada objavimo pametni ugovor. Pokrenimo lite-client i izvršimo.

> 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 

Provjerimo da li je ugovor objavljen.

> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Između ostalog dobijamo.

  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

Vidimo to account_active.

Odgovarajuće urezivanje s promjenama ovde.

Sada kreirajmo zahtjeve za interakciju sa pametnim ugovorom.

Tačnije, prvu ćemo ostaviti za promjenu adrese kao samostalan posao, a drugu ćemo uraditi za slanje grama na adresu vlasnika. U stvari, moraćemo da uradimo istu stvar kao u testu za slanje grama.

Ovo je poruka koju ćemo poslati pametnom ugovoru, gdje msg_seqno 165, action 2 i 9.5 grama za slanje.

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

Ne zaboravite da potpišete poruku svojim privatnim ključem lottery.pk, koji je generiran ranije prilikom kreiranja pametnog ugovora. Evo odgovarajućeg urezivanja.

Primanje informacija iz pametnog ugovora pomoću metoda get

Sada pogledajmo kako pokrenuti metode dobivanja pametnog ugovora.

Pokreni lite-client i pokrenite get metode koje smo napisali.

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

В result sadrži vrijednost koju funkcija vraća balance() iz našeg pametnog ugovora.
Isto ćemo učiniti za još nekoliko metoda.

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

Pitajmo vas za istoriju opklada.

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

Koristit ćemo lite-client i dobiti metode za prikaz informacija o pametnom ugovoru na web stranici.

Prikazivanje podataka pametnog ugovora na web stranici

Napisao sam jednostavnu web stranicu u Pythonu da prikažem podatke iz pametnog ugovora na zgodan način. Ovdje se neću zadržavati na tome detaljno i objavit ću stranicu u jednom urezivanju.

Zahtjevi prema TON-u su napravljeni od Python uz pomoć lite-client. Radi praktičnosti, stranica je upakovana u Docker i objavljena na Google Cloud-u. Veza.

Pokušavam

Pokušajmo sada poslati grame tamo za dopunu novčanik. Šaljemo 40 grama. I napravimo par opklada radi jasnoće. Vidimo da sajt prikazuje istoriju opklada, trenutni procenat dobitaka i druge korisne informacije.

Vidimoda smo prvu dobili, drugu izgubili.

Posle reči

Članak je ispao mnogo duži nego što sam očekivao, možda je mogao biti kraći, ili možda samo za osobu koja ne zna ništa o TON-u i želi napisati i objaviti ne tako jednostavan pametni ugovor sa mogućnošću interakcije sa to. Možda su se neke stvari mogle jednostavnije objasniti.

Možda su neki aspekti implementacije mogli biti urađeni efikasnije i elegantnije, ali bi tada bilo potrebno još više vremena za pripremu članka. Također je moguće da sam negdje pogriješio ili nešto nisam razumio, pa ako radite nešto ozbiljno, trebate se osloniti na zvaničnu dokumentaciju ili službeni repozitorij sa TON kodom.

Treba napomenuti da s obzirom da je sam TON još uvijek u aktivnoj fazi razvoja, može doći do promjena koje će prekinuti bilo koji od koraka u ovom članku (što se dogodilo dok sam pisao, već je ispravljeno), ali opći pristup je malo je vjerovatno da će se promijeniti.

Neću pričati o budućnosti TON-a. Možda će platforma postati nešto veliko i trebali bismo potrošiti vrijeme proučavajući je i popuniti nišu našim proizvodima sada.

Tu je i Libra iz Facebooka, koja ima potencijalnu publiku korisnika veću od TON-a. Ne znam skoro ništa o Vagi, sudeći po forumu tamo je mnogo više aktivnosti nego u TON zajednici. Iako su programeri i zajednica TON-a više kao underground, što je također cool.

reference

  1. Zvanična TON dokumentacija: https://test.ton.org
  2. Zvanični TON repozitorij: https://github.com/ton-blockchain/ton
  3. Službeni novčanik za različite platforme: https://wallet.ton.org
  4. Spremište pametnih ugovora iz ovog članka: https://github.com/raiym/astonished
  5. Link na web stranicu pametnog ugovora: https://ton-lottery.appspot.com
  6. Repozitorijum za ekstenziju za Visual Studio Code za FunC: https://github.com/raiym/func-visual-studio-plugin
  7. Razgovarajte o TON-u u Telegramu, što je zaista pomoglo da se to shvati u početnoj fazi. Mislim da neće biti greška ako kažem da su svi koji su nešto napisali za TON tu. Tamo možete tražiti i test grama. https://t.me/tondev_ru
  8. Još jedan razgovor o TON-u u kojem sam našao korisne informacije: https://t.me/TONgramDev
  9. Prva faza takmičenja: https://contest.com/blockchain
  10. Druga faza takmičenja: https://contest.com/blockchain-2

izvor: www.habr.com

Dodajte komentar