O tem, kako napisati in objaviti pametno pogodbo v odprtem omrežju Telegram (TON)

O tem, kako napisati in objaviti pametno pogodbo v TON

O čem govori ta članek?

V članku bom govoril o tem, kako sem sodeloval v prvem (od dveh) tekmovanju Telegram blockchain, nisem prejel nagrade in sem se odločil, da svojo izkušnjo zapišem v članek, da ne pade v pozabo in morda pomaga nekdo.

Ker nisem želel pisati abstraktne kode, ampak narediti nekaj delujočega, sem za članek napisal pametno pogodbo za takojšnjo loterijo in spletno mesto, ki prikazuje podatke pametne pogodbe neposredno iz TON brez uporabe vmesnega pomnilnika.

Članek bo koristen za tiste, ki želijo skleniti svojo prvo pametno pogodbo v TON, vendar ne vedo, kje začeti.

Če uporabim loterijo kot primer, bom šel od namestitve okolja do objave pametne pogodbe, interakcije z njo in pisanja spletne strani za prejemanje in objavo podatkov.

O sodelovanju na tekmovanju

Oktobra lani je Telegram napovedal tekmovanje v blockchainu z novimi jeziki Fift и FunC. Izbirati je bilo treba med pisanjem katere koli od petih predlaganih pametnih pogodb. Mislil sem, da bi bilo lepo narediti nekaj drugačnega, se naučiti jezika in narediti nekaj, tudi če mi v prihodnosti ne bo treba pisati ničesar drugega. Poleg tega je tema nenehno na ustih.

Treba je povedati, da nisem imel izkušenj z razvojem pametnih pogodb.

Načrtoval sem sodelovati do samega konca, dokler mi ne bo uspelo in nato napisati recenzentski članek, a mi je takoj pri prvem spodletelo. jaz napisal denarnico z vključenim večpodpisom FunC in na splošno je delovalo. Vzel sem ga za osnovo pametna pogodba na Solidity.

Takrat sem mislil, da je to zagotovo dovolj za vsaj kakšno nagradno mesto. Posledično je približno 40 od ​​60 udeležencev postalo nagrajencev in mene ni bilo med njimi. Na splošno s tem ni nič narobe, zmotila pa me je ena stvar. V času objave rezultatov pregled testa za mojo pogodbo še ni bil opravljen, udeležence klepeta sem vprašal, če je še kdo, ki ga nima, ni ga bilo.

Očitno pozorni na moja sporočila so sodniki čez dva dni objavili komentar in še vedno ne razumem, ali so med ocenjevanjem slučajno spregledali mojo pametno pogodbo ali pa so preprosto mislili, da je tako slaba, da ne potrebuje komentarja. Na strani sem postavil vprašanje, vendar nisem prejel odgovora. Čeprav ni skrivnost, kdo je sodil, se mi je zdelo nepotrebno pisati osebna sporočila.

Veliko časa je bilo porabljenega za razumevanje, zato je bilo odločeno napisati članek. Ker še ni veliko informacij, bo ta članek pomagal prihraniti čas vsem zainteresiranim.

Koncept pametnih pogodb v TON

Preden karkoli napišete, morate ugotoviti, s katere strani se lotiti te stvari. Zato vam bom zdaj povedal, iz katerih delov je sestavljen sistem. Natančneje, katere dele morate poznati, da napišete vsaj kakšno pogodbo o delu.

Osredotočili se bomo na pisanje pametne pogodbe in delo z TON Virtual Machine (TVM), Fift и FunC, zato je članek bolj kot opis razvoja običajnega programa. Tukaj se ne bomo ukvarjali s tem, kako platforma sama deluje.

Na splošno o tem, kako deluje TVM in jezik Fift obstaja dobra uradna dokumentacija. Med sodelovanjem v natečaju in zdaj med pisanjem trenutne pogodbe sem se pogosto obračala nanjo.

Glavni jezik, v katerem so napisane pametne pogodbe, je FunC. O tem trenutno ni nobene dokumentacije, zato, da bi kaj napisali, morate preučiti primere pametnih pogodb iz uradnega repozitorija in implementacijo samega jezika tam, poleg tega pa si lahko pogledate primere pametnih pogodb iz zadnjih dveh tekmovanja. Povezave na koncu članka.

Recimo, da smo že napisali pametno pogodbo za FunC, nato kodo prevedemo v Fift assembler.

Sestavljeno pametno pogodbo je treba še objaviti. Če želite to narediti, morate vpisati funkcijo Fift, ki bo kot vhod vzel kodo pametne pogodbe in nekatere druge parametre, izhod pa bo datoteka s pripono .boc (kar pomeni »vreča celic«), ter glede na to, kako zapišemo, zasebni ključ in naslov, ki se generira na podlagi kode pametne pogodbe. Grame že lahko pošljete na naslov pametne pogodbe, ki še ni objavljena.

Za objavo pametne pogodbe v TON prejeli .boc datoteko bo treba poslati v blockchain z uporabo lahkega odjemalca (več o tem spodaj). Toda pred objavo morate prenesti grame na generirani naslov, sicer pametna pogodba ne bo objavljena. Po objavi lahko komunicirate s pametno pogodbo tako, da ji pošiljate sporočila od zunaj (na primer z uporabo lahkega odjemalca) ali od znotraj (na primer ena pametna pogodba drugi pošlje sporočilo znotraj TON).

Ko razumemo, kako je koda objavljena, postane lažje. Približno vemo, kaj želimo napisati in kako bo naš program deloval. In med pisanjem iščemo, kako je to že implementirano v obstoječih pametnih pogodbah, ali pa pogledamo implementacijsko kodo Fift и FunC v uradnem repozitoriju ali poglejte v uradno dokumentacijo.

Zelo pogosto sem iskal ključne besede v klepetu Telegram, kjer so se zbrali vsi udeleženci tekmovanja in zaposleni v Telegramu, in zgodilo se je, da so se med tekmovanjem vsi zbrali tam in začeli razpravljati o Fiftu in FunC-u. Povezava na koncu članka.

Čas je, da preidemo od teorije k praksi.

Priprava okolja za delo s TON

Naredil sem vse, kar bo opisano v članku o MacOS-u, in dvakrat preveril v čistem Ubuntu 18.04 LTS na Dockerju.

Prva stvar, ki jo morate storiti, je prenesti in namestiti lite-client s katerim lahko pošiljate zahteve na TON.

Navodila na uradni spletni strani opisujejo postopek namestitve precej natančno in jasno ter izpuščajo nekatere podrobnosti. Tukaj sledimo navodilom in med potjo namestimo manjkajoče odvisnosti. Vsakega projekta nisem sam prevedel in namestil iz uradnega repozitorija Ubuntu (na MacOS, ki sem ga uporabljal 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 

Ko so vse odvisnosti nameščene, lahko namestite lite-client, Fift, FunC.

Najprej kloniramo repozitorij TON skupaj z njegovimi odvisnostmi. Zaradi udobja bomo vse naredili v mapi ~/TON.

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

Repozitorij shranjuje tudi izvedbe Fift и FunC.

Zdaj smo pripravljeni sestaviti projekt. Koda repozitorija je klonirana v mapo ~/TON/ton. V ~/TON ustvarite mapo build in vanjo zbrati projekt.

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

Ker bomo napisali pametno pogodbo, ne potrebujemo samo lite-clientVendar Fift с FunC, torej sestavimo vse. To ni hiter postopek, zato čakamo.

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

Nato prenesite konfiguracijsko datoteko, ki vsebuje podatke o vozlišču, na katerega lite-client se bo povezal.

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

Pošiljanje prvih zahtev TON

Zdaj pa zaženimo lite-client.

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

Če je bila gradnja uspešna, boste po zagonu videli dnevnik povezave lahkega odjemalca z vozliščem.

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

Lahko zaženete ukaz help in si oglejte, kateri ukazi so na voljo.

help

Naštejmo ukaze, ki jih bomo uporabili v tem č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-методы смартконтракта. 

Zdaj smo pripravljeni napisati samo pogodbo.

Реализация

Ideja

Kot sem napisal zgoraj, je pametna pogodba, ki jo pišemo, loterija.

Poleg tega to ni loterija, pri kateri morate kupiti listek in počakati eno uro, dan ali mesec, ampak takojšnja, pri kateri uporabnik nakaže na pogodbeni naslov N gramov in ga takoj dobi nazaj 2 * N gramov ali izgubi. Verjetnost zmage bomo naredili približno 40-odstotno. Če za plačilo ni dovolj gramov, bomo transakcijo obravnavali kot polnjenje.

Poleg tega je pomembno, da so stave vidne v realnem času in v priročni obliki, tako da lahko uporabnik takoj razume, ali je zmagal ali izgubil. Zato morate narediti spletno stran, ki bo prikazovala stave in rezultate neposredno iz TON.

Pisanje pametne pogodbe

Za udobje sem izpostavil kodo za FunC; vtičnik je mogoče najti in namestiti v iskalniku Visual Studio Code; če nenadoma želite nekaj dodati, sem vtičnik dal javno dostopen. Prav tako je nekdo prej naredil plugin za delo s Fiftom, lahko ga tudi namestite in najdete v VSC.

Takoj ustvarimo repozitorij, kamor bomo objavili vmesne rezultate.

Da bi nam olajšali življenje, bomo napisali pametno pogodbo in jo testirali lokalno, dokler ne bo pripravljena. Šele po tem ga bomo objavili v TON.

Pametna pogodba ima dve zunanji metodi, do katerih je mogoče dostopati. Prvič, recv_external() ta funkcija se izvede, ko pride zahteva za pogodbo iz zunanjega sveta, torej ne iz TON-a, na primer, ko sami generiramo sporočilo in ga pošljemo prek lite-klienta. Drugič, recv_internal() to je takrat, ko se znotraj samega TON katera koli pogodba nanaša na našo. V obeh primerih lahko funkciji posredujete parametre.

Začnimo s preprostim primerom, ki bo deloval, če bo objavljen, vendar v njem ni funkcionalne obremenitve.

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

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

Tukaj moramo pojasniti, kaj je to slice. Vsi podatki, shranjeni v TON Blockchain, so zbirka TVM cell ali pa preprosto cell, v tako celico lahko shranite do 1023 bitov podatkov in do 4 povezave do drugih celic.

TVM cell slice ali slice ta je del obstoječega cell se uporablja za njegovo razčlenjevanje, bo jasno kasneje. Za nas je glavno, da lahko prestopimo slice in glede na vrsto sporočila obdela podatke v recv_external() ali recv_internal().

impure — ključna beseda, ki označuje, da funkcija spreminja podatke pametne pogodbe.

Shranimo kodo pogodbe lottery-code.fc in sestavite.

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

Pomen zastavic si lahko ogledate z ukazom

~/TON/build/crypto/func -help

V sistem smo prevedli kodo 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

Lahko se lansira lokalno, za to bomo pripravili okolje.

Upoštevajte, da je prva vrstica povezana Asm.fif, to je koda, napisana v Fiftu za zbirnik Fift.

Ker želimo pametno pogodbo izvajati in testirati lokalno, bomo ustvarili datoteko lottery-test-suite.fif in tja kopirajte prevedeno kodo, tako da zamenjate zadnjo vrstico v njej, ki zapiše kodo pametne pogodbe v konstanto codeda ga nato prenesete v virtualni stroj:

"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

Zaenkrat se zdi jasno, zdaj pa v isto datoteko dodamo kodo, ki jo bomo uporabili za zagon 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 zabeležimo kontekst, torej podatke, s katerimi se bo TVM (ali stanje omrežja) zagnal. Že med tekmovanjem je eden od razvijalcev pokazal, kako se ustvarja c7 in sem kopiral. V tem članku bomo morda morali spremeniti rand_seed ker je generiranje naključnega števila odvisno od tega in če se ne spremeni, bo vsakič vrnjeno isto število.

recv_internal и recv_external konstante z vrednostmi 0 in -1 bodo odgovorne za klicanje ustreznih funkcij v pametni pogodbi.

Zdaj smo pripravljeni ustvariti prvi test za našo prazno pametno pogodbo. Zaradi jasnosti bomo za zdaj vse teste dodali v isto datoteko lottery-test-suite.fif.

Ustvarimo spremenljivko storage in vanj vpišite prazno cell, bo to shramba pametnih pogodb.

message To je sporočilo, ki ga bomo od zunaj posredovali pametnemu kontaktu. Zaenkrat ga bomo naredili tudi praznega.

variable storage 
<b b> storage ! 

variable message 
<b b> message ! 

Ko smo pripravili konstante in spremenljivke, zaženemo TVM z ukazom runvmctx in posreduje ustvarjene parametre na vhod.

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

Na koncu nam bo uspelo Všečkaj to vmesna koda za Fift.

Zdaj lahko zaženemo dobljeno kodo.

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

Program bi moral delovati brez napak in v izhodu bomo videli dnevnik izvajanja:

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

Super, napisali smo prvo delujočo različico pametne pogodbe.

Zdaj moramo dodati funkcionalnost. Najprej se lotimo sporočil, ki prihajajo iz zunanjega sveta recv_external()

Razvijalec sam izbere obliko sporočila, ki jo pogodba lahko sprejme.

Ampak običajno

  • najprej želimo zaščititi našo pogodbo pred zunanjim svetom in narediti tako, da ji lahko samo lastnik pogodbe pošilja zunanja sporočila.
  • drugič, ko pošljemo veljavno sporočilo TON-u, želimo, da se to zgodi natanko enkrat in ko pošljemo isto sporočilo znova, ga pametna pogodba zavrne.

Torej skoraj vsaka pogodba rešuje ta dva problema, ker naša pogodba sprejema zunanja sporočila, moramo poskrbeti tudi za to.

Naredili bomo v obratnem vrstnem redu. Najprej rešimo problem s ponavljanjem, če je pogodba že prejela takšno sporočilo in ga obdelala, ga drugič ne bo izvršila. In potem bomo problem rešili tako, da bo le določen krog ljudi lahko pošiljal sporočila na pametno pogodbo.

Težavo s podvojenimi sporočili lahko rešite na različne načine. Evo, kako bomo to storili. V pametni pogodbi inicializiramo števec prejetih sporočil z začetno vrednostjo 0. V vsakem sporočilu v pametno pogodbo bomo dodali trenutno vrednost števca. Če se vrednost števca v sporočilu ne ujema z vrednostjo v pametni pogodbi, je ne obdelamo, če se, jo obdelamo in povečamo števec v pametni pogodbi za 1.

Vrnimo se k lottery-test-suite.fif in mu dodajte drugi test. Če pošljemo napačno številko, bi morala koda sprožiti izjemo. Na primer, naj pogodbeni podatki shranijo 166, mi pa bomo poslali 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"

Zaženimo.

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

In videli bomo, da je test izveden z napako.

[ 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

Na tej stopnji lottery-test-suite.fif bi moralo izgledati по ссылке.

Zdaj pa pametni pogodbi dodamo logiko števca 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 sporočilo, ki ga pošiljamo.

Najprej preverimo, ali sporočilo vsebuje podatke, če ne, preprosto zapustimo.

Nato razčlenimo sporočilo. in_msg~load_uint(32) naloži številko 165, 32-bitno unsigned int iz poslanega sporočila.

Nato naložimo 32 bitov iz pomnilnika pametnih pogodb. Preverimo, ali se naložena številka ujema s posredovano; če ne, vržemo izjemo. V našem primeru, ker gremo mimo neujemanja, je treba vrniti izjemo.

Zdaj pa sestavimo.

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

Kopirajte dobljeno kodo v lottery-test-suite.fif, ne pozabite zamenjati zadnje vrstice.

Preverimo, ali je test uspešen:

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

Tukaj Ogledate si lahko ustrezno objavo s trenutnimi rezultati.

Upoštevajte, da je neprijetno nenehno kopirati prevedeno kodo pametne pogodbe v datoteko s testi, zato bomo napisali skript, ki bo namesto nas zapisal kodo v konstanto, in bomo preprosto povezali prevedeno kodo z našimi testi z uporabo "include".

Ustvarite datoteko v mapi projekta build.sh z naslednjo vsebino.

#!/bin/bash

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

Naredimo ga izvršljivega.

chmod +x ./build.sh

Zdaj samo zaženite naš skript, da sestavite pogodbo. Toda poleg tega ga moramo zapisati v konstanto code. Tako bomo ustvarili novo datoteko lotter-compiled-for-test.fif, ki ga bomo vključili v datoteko lottery-test-suite.fif.

Dodajmo skirpt kodo v sh, ki bo preprosto podvojila prevedeno datoteko lotter-compiled-for-test.fif in spremenite zadnjo vrstico v njem.

# 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

Zdaj, da preverimo, zaženimo nastali skript in ustvarjena bo datoteka lottery-compiled-for-test.fif, ki ga bomo vključili v našo lottery-test-suite.fif

В lottery-test-suite.fif izbrišite kodo pogodbe in dodajte vrstico "lottery-compiled-for-test.fif" include.

Izvajamo teste, da preverimo, ali so uspešni.

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

Super, zdaj za avtomatizacijo zagona testov ustvarimo datoteko test.sh, ki se bo najprej izvršil build.shin nato zaženite teste.

touch test.sh
chmod +x test.sh

Pišemo notri

./build.sh 

echo "nCompilation completedn"

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

Naredimo to test.sh in ga zaženite, da se prepričate, ali testi delujejo.

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

Preverimo, ali je pogodba sestavljena in ali so testi izvedeni.

Super, zdaj ob zagonu test.sh Testi bodo sestavljeni in izvedeni takoj. Tukaj je povezava do zavezati.

V redu, preden nadaljujemo, naredimo še eno stvar za udobje.

Ustvarimo mapo build kamor bomo shranili kopirano pogodbo in njen klon, zapisan v konstanto lottery-compiled.fif, lottery-compiled-for-test.fif. Ustvarimo tudi mapo test kje bo shranjena testna datoteka? lottery-test-suite.fif in potencialno druge podporne datoteke. Povezava do ustreznih sprememb.

Nadaljujmo z razvojem pametne pogodbe.

Sledi preizkus, ki preveri, ali je sporočilo prejeto in se števec posodobi v trgovini, ko pošljemo pravilno številko. Ampak to bomo storili kasneje.

Zdaj pa razmislimo o strukturi podatkov in kateri podatki morajo biti shranjeni v pametni pogodbi.

Opisal bom vse, kar hranimo.

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

Nato morate napisati dve funkciji. Pokličimo prvega pack_state(), ki bo zapakiral podatke za kasnejše shranjevanje v shrambo pametnih pogodb. Pokličimo drugo unpack_state() bo prebral in vrnil podatke iz pomnilnika.

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

Ti dve funkciji dodamo na začetek pametne pogodbe. Se bo izšlo Všečkaj to vmesni rezultat.

Za shranjevanje podatkov boste morali poklicati vgrajeno funkcijo set_data() in bo zapisal podatke iz pack_state() v shrambi pametnih pogodb.

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

Zdaj, ko imamo priročne funkcije za pisanje in branje podatkov, lahko nadaljujemo.

Preveriti moramo, ali je sporočilo, ki prihaja od zunaj, podpisano s strani lastnika pogodbe (ali drugega uporabnika, ki ima dostop do zasebnega ključa).

Ko objavimo pametno pogodbo, jo lahko inicializiramo s podatki, ki jih potrebujemo v pomnilniku, ki bodo shranjeni za prihodnjo uporabo. Tam bomo zabeležili javni ključ, da bomo lahko preverili, ali je bilo dohodno sporočilo podpisano z ustreznim zasebnim ključem.

Preden nadaljujemo, ustvarimo zasebni ključ in ga zapišimo test/keys/owner.pk. Če želite to narediti, zaženite Fift v interaktivnem načinu in izvedite štiri ukaze.

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

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

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

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

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

Ustvarimo mapo keys znotraj mape test in tam zapišite zasebni 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

V trenutni mapi vidimo datoteko owner.pk.

Javni ključ odstranimo iz sklada in po potrebi ga lahko pridobimo iz zasebnega.

Zdaj moramo napisati overitev podpisa. Začnimo s testom. Najprej preberemo zasebni ključ iz datoteke s funkcijo file>B in ga zapišite v spremenljivko owner_private_key, nato pa uporabite funkcijo priv>pub pretvorite zasebni ključ v javni ključ in zapiš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 !

Potrebovali bomo oba ključa.

Shrambo pametne pogodbe inicializiramo s poljubnimi podatki v enakem zaporedju kot v funkciji pack_state()in ga zapiši v spremenljivko 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 !

Nato bomo sestavili podpisano sporočilo, vsebovalo bo le podpis in vrednost števca.

Najprej ustvarimo podatke, ki jih želimo posredovati, nato jih podpišemo z zasebnim ključem in na koncu ustvarimo podpisano sporočilo.

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 !  

Posledično se sporočilo, ki ga bomo poslali pametni pogodbi, zabeleži v spremenljivki message_to_send, o funkcijah hashu, ed25519_sign_uint lahko bere v dokumentaciji Fift.

In za izvedbo testa ponovno pokličemo.

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

Tukaj tako Datoteka s testi naj bi na tej stopnji izgledala takole.

Zaženimo test in ne bo uspel, zato bomo spremenili pametno pogodbo, da bo lahko prejemala sporočila v tej obliki in preverjala podpis.

Najprej preštejemo 512 bitov podpisa sporočila in ga zapišemo v spremenljivko, nato preštejemo 32 bitov spremenljivke števca.

Ker imamo funkcijo za branje podatkov iz shrambe pametnih pogodb, jo bomo uporabili.

Sledi preverjanje števca, prenesenega s shrambo, in preverjanje podpisa. Če nekaj ne ustreza, vržemo izjemo z ustrezno kodo.

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

Ustrezna potrditev tukaj.

Opravimo teste in vidimo, da drugi test ne uspe. Iz dveh razlogov ni dovolj bitov v sporočilu in ni dovolj bitov v pomnilniku, zato se koda pri razčlenjevanju zruši. Sporočilu, ki ga pošiljamo, moramo dodati podpis in kopirati shrambo iz zadnjega testa.

V drugem preizkusu bomo dodali podpis sporočila in spremenili shrambo pametne pogodbe. Tukaj tako datoteka s testi trenutno izgleda takole.

Napišimo še četrti test, v katerem bomo poslali sporočilo, podpisano z zasebnim ključem nekoga drugega. Ustvarimo še en zasebni ključ in ga shranimo v datoteko not-owner.pk. S tem zasebnim ključem bomo podpisali sporočilo. Opravimo teste in poskrbimo, da bodo vsi testi uspešni. Zaveži se ta trenutek.

Zdaj lahko končno nadaljujemo z implementacijo logike pametne pogodbe.
В recv_external() sprejeli bomo dve vrsti sporočil.

Ker bo naša pogodba kopičila izgube igralcev, je treba ta denar nakazati ustvarjalcu loterije. Naslov denarnice ustvarjalca loterije se zabeleži v shrambo, ko je pogodba ustvarjena.

Za vsak slučaj potrebujemo možnost spremembe naslova, na katerega pošiljamo grame poražencev. Prav tako bi morali imeti možnost pošiljanja gramov iz loterije na naslov lastnika.

Začnimo s prvim. Najprej napišimo test, ki bo preveril, ali je pametna pogodba po poslanem sporočilu shranila nov naslov v shrambo. Opozarjamo, da v sporočilu poleg števca in novega naslova posredujemo tudi action 7-bitno celo nenegativno število, odvisno od njega bomo izbrali način obdelave sporočila v pametni pogodbi.

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

V preizkusu lahko vidite, kako je shranjevanje pametnih pogodb deserializirano storage v Fiftu. Deserializacija spremenljivk je opisana v dokumentaciji Fift.

Objavi povezavo z dodanim testom.

Izvedimo test in se prepričajmo, da ne uspe. Zdaj pa dodamo logiko za spremembo naslova lastnika loterije.

V pametni pogodbi nadaljujemo z razčlenjevanjem message, preberite action. Naj vas spomnimo, da bomo imeli dva action: spremenite naslov in pošljite gram.

Nato preberemo nov naslov pogodbenega lastnika in ga shranimo v hrambo.
Izvedemo teste in vidimo, da tretji test ne uspe. Sesuje se zaradi tega, ker pogodba zdaj dodatno razčleni 7 bitov iz sporočila, ki manjkajo v testu. Sporočilu dodajte neobstoječega action. Opravimo teste in preverimo, ali vse poteka. Tukaj zavezati se spremembam. Super.

Zdaj pa napišimo logiko za pošiljanje določenega števila gramov na predhodno shranjen naslov.

Najprej napišimo test. Napisali bomo dva testa, enega, ko ni dovolj ravnovesja, drugega, ko bi moralo vse uspešno prestati. Teste si lahko ogledate v tej obvezi.

Zdaj pa dodamo kodo. Najprej napišimo dve pomožni metodi. Prva metoda pridobivanja je ugotoviti trenutno stanje pametne pogodbe.

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

In drugi je za pošiljanje gramov v drugo pametno pogodbo. To metodo sem popolnoma kopiral iz druge pametne pogodbe.

() 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 ti dve metodi v pametno pogodbo in napišimo logiko. Najprej razčlenimo število gramov iz sporočila. Nato preverimo stanje, če ni dovolj, vržemo izjemo. Če je vse v redu, potem pošljemo grame na shranjen naslov in posodobimo števec.

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

Tukaj tako trenutno izgleda kot pametna pogodba. Opravimo teste in poskrbimo, da bodo uspešni.

Mimogrede, vsakič za obdelano sporočilo se od pametne pogodbe odšteje provizija. Da bi sporočila pametne pogodbe izvedla zahtevo, morate po osnovnih preverjanjih poklicati accept_message().

Zdaj pa preidimo na interna sporočila. Pravzaprav bomo sprejeli le grame in vrnili dvojno količino igralcu, če zmaga, in tretjino lastniku, če izgubi.

Najprej napišimo preprost test. Za to potrebujemo testni naslov pametne pogodbe, s katere domnevno pošiljamo grame v pametno pogodbo.

Naslov pametne pogodbe je sestavljen iz dveh številk, 32-bitnega celega števila, odgovornega za delovno verigo, in 256-bitne nenegativne cele številke edinstvene številke računa v tej delovni verigi. Na primer -1 in 12345, to je naslov, ki ga bomo shranili v datoteko.

Funkcijo za shranjevanje naslova sem kopiral 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

Poglejmo, kako funkcija deluje, tako bomo razumeli, kako deluje Fift. Zaženite Fift v interaktivnem načinu.

~/TON/build/crypto/fift -i 

Najprej potisnemo -1, 12345 in ime prihodnje datoteke "sender.addr" na sklad:

-1 12345 "sender.addr" 

Naslednji korak je izvedba funkcije -rot, ki premakne sklad tako, da je na vrhu sklada edinstvena številka pametne pogodbe:

"sender.addr" -1 12345

256 u>B pretvori 256-bitno nenegativno celo število v bajte.

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap zamenja zgornja dva elementa sklada.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

32 i>B pretvori 32-bitno celo število v bajte.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ povezuje dve zaporedji bajtov.

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

Spet swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

In končno se bajti zapišejo v datoteko B>file. Po tem je naš sklad prazen. Ustavimo se Fift. V trenutni mapi je bila ustvarjena datoteka sender.addr. Premaknimo datoteko v ustvarjeno mapo test/addresses/.

Napišimo preprost test, ki bo poslal grame v pametno pogodbo. Tukaj je zaveza.

Zdaj pa poglejmo logiko loterije.

Prva stvar, ki jo naredimo, je, da preverimo sporočilo bounced ali ne če bounced, potem ga ignoriramo. bounced pomeni, da bo pogodba vrnila grame, če pride do napake. Gramov ne bomo vrnili, če nenadoma pride do napake.

Preverimo, če je stanje manjše od pol grama, potem sporočilo preprosto sprejmemo in ga ignoriramo.

Nato razčlenimo naslov pametne pogodbe, iz katere je prišlo sporočilo.

Podatke preberemo iz pomnilnika in nato izbrišemo stare stave iz zgodovine, če jih je več kot dvajset. Za udobje sem napisal tri dodatne funkcije pack_order(), unpack_order(), remove_old_orders().

Nato pogledamo, če stanje ni dovolj za plačilo, potem menimo, da to ni stava, ampak dopolnitev in shranimo dopolnitev v orders.

Potem pa končno bistvo pametne pogodbe.

Najprej, če igralec izgubi, to shranimo v zgodovino stav in če je količina večja od 3 gramov, pošljemo 1/3 lastniku pametne pogodbe.

Če igralec zmaga, potem na njegov naslov pošljemo dvojni znesek in nato podatke o stavi shranimo v zgodovino.

() 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 to. Ustrezna potrditev.

Zdaj je vse, kar ostane, preprosto, ustvarimo get-methode, da lahko pridobimo informacije o stanju pogodbe iz zunanjega sveta (pravzaprav preberemo podatke iz njihovega pametnega pomnilnika pogodb).

Dodajmo get metode. Kako do informacij o pametni pogodbi, bomo pisali v nadaljevanju.

Pozabil sem dodati tudi kodo, ki bo obdelala prvo zahtevo, ki se pojavi ob objavi pametne pogodbe. Ustrezna potrditev. In dalje popravljeno napaka s pošiljanjem 1/3 zneska na račun lastnika.

Naslednji korak je objava pametne pogodbe. Ustvarimo mapo requests.

Za osnovo sem vzel kodo objave simple-wallet-code.fc который lahko najdem v uradnem repozitoriju.

Nekaj, na kar je vredno pozornosti. Generiramo shrambo pametne pogodbe in vhodno sporočilo. Po tem se generira naslov pametne pogodbe, torej je naslov znan že pred objavo v TON. Nato morate na ta naslov poslati več gramov in šele nato poslati datoteko s samo pametno pogodbo, saj omrežje vzame provizijo za shranjevanje pametne pogodbe in operacije v njej (validatorji, ki shranjujejo in izvajajo pametne pogodbe). Kodo si lahko ogledate tukaj.

Nato izvedemo kodo za objavo in dobimo lottery-query.boc datoteka in naslov pametne pogodbe.

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

Ne pozabite shraniti ustvarjenih datotek: lottery-query.boc, lottery.addr, lottery.pk.

Med drugim bomo v dnevnikih izvajanja videli naslov pametne pogodbe.

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

Samo za zabavo, pošljimo zahtevo na TON

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

In videli bomo, da je račun s tem naslovom prazen.

account state is empty

Pošljemo na naslov 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 Gram in po nekaj sekundah izvedemo isti ukaz. Za pošiljanje gramov uporabljam uradna denarnica, lahko pa koga iz klepeta prosite za testne grame, o katerih bom govoril na koncu članka.

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Videti je kot neinicializiran (state:account_uninit) pametno pogodbo z istim naslovom in stanjem 1 nanogramov.

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

Zdaj pa objavimo pametno pogodbo. Zaženimo lite-client in izvedimo.

> 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 

Preverimo, ali je bila pogodba objavljena.

> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Med drugim dobimo.

  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

To vidimo account_active.

Ustrezna potrditev s spremembami tukaj.

Zdaj pa ustvarimo zahteve za interakcijo s pametno pogodbo.

Natančneje, prvega bomo pustili za spremembo naslova kot samostojno delo, drugega pa bomo naredili za pošiljanje gramov na naslov lastnika. Pravzaprav bomo morali narediti isto kot pri testu za pošiljanje gramov.

To je sporočilo, ki ga bomo poslali pametni pogodbi, kjer msg_seqno 165, action 2 in 9.5 grama za pošiljanje.

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

Ne pozabite podpisati sporočila s svojim zasebnim ključem lottery.pk, ki je bil ustvarjen prej pri ustvarjanju pametne pogodbe. Tukaj je ustrezna potrditev.

Prejemanje informacij iz pametne pogodbe z uporabo metod get

Zdaj pa poglejmo, kako zagnati metode pridobivanja pametne pogodbe.

Kosilo lite-client in zaženi metode get, ki smo jih napisali.

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

В result vsebuje vrednost, ki jo vrne funkcija balance() iz naše pametne pogodbe.
Enako bomo storili za več drugih metod.

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

Vprašajmo za tvojo zgodovino stav.

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

Uporabili bomo lite-client in pridobili metode za prikaz informacij o pametni pogodbi na spletnem mestu.

Prikaz podatkov pametnih pogodb na spletni strani

Napisal sem preprosto spletno mesto v Pythonu za prikaz podatkov iz pametne pogodbe na priročen način. Tukaj se ne bom podrobno zadrževal in bom objavil spletno mesto v eni objavi.

Zahteve za TON so podane iz Python s pomočjo lite-client. Zaradi udobja je spletno mesto zapakirano v Docker in objavljeno v Google Cloud. Povezava.

Poskušam

Zdaj pa poskusimo tja poslati grame za dopolnitev denarnica. Poslali bomo 40 gramov. In dajmo nekaj stav za jasnost. Vidimo, da spletno mesto prikazuje zgodovino stav, trenutni odstotek zmag in druge koristne informacije.

Vidimoda smo prvo zmagali, drugo izgubili.

spremna beseda

Članek se je izkazal za veliko daljšega, kot sem pričakoval, morda bi lahko bil krajši ali pa samo za osebo, ki ne ve nič o TON in želi napisati in objaviti ne tako preprosto pametno pogodbo z možnostjo interakcije z to. Morda bi lahko nekatere stvari razložili bolj preprosto.

Morda bi nekatere vidike implementacije lahko naredili bolj učinkovito in elegantno, a bi potem priprava članka vzela še več časa. Možno je tudi, da sem se kje zmotil ali česa nisem razumel, zato se morate, če delate kaj resnega, zanesti na uradno dokumentacijo ali uradno skladišče s kodo TON.

Upoštevati je treba, da ker je TON sam še vedno v aktivni fazi razvoja, lahko pride do sprememb, ki bodo prekinile katerega od korakov v tem članku (kar se je zgodilo, ko sem pisal, je že popravljeno), vendar je splošni pristop malo verjetno se bo spremenilo.

Ne bom govoril o prihodnosti TON. Morda bo platforma postala nekaj velikega in bi morali porabiti čas za njeno preučevanje in zdaj zapolniti nišo z našimi izdelki.

Obstaja tudi Libra iz Facebooka, ki ima potencialno občinstvo uporabnikov večje od TON. O Libri ne vem skoraj nič, po forumu sodeč je tam veliko več aktivnosti kot v skupnosti TON. Čeprav so razvijalci in skupnost TON bolj podzemni, je tudi kul.

reference

  1. Uradna dokumentacija TON: https://test.ton.org
  2. Uradno skladišče TON: https://github.com/ton-blockchain/ton
  3. Uradna denarnica za različne platforme: https://wallet.ton.org
  4. Repozitorij pametnih pogodb iz tega članka: https://github.com/raiym/astonished
  5. Povezava do spletne strani pametne pogodbe: https://ton-lottery.appspot.com
  6. Repozitorij za razširitev za kodo Visual Studio za FunC: https://github.com/raiym/func-visual-studio-plugin
  7. Klepetajte o TON v Telegramu, kar je res pomagalo ugotoviti to na začetni stopnji. Mislim, da ne bo napaka, če rečem, da so tam vsi, ki so kaj napisali za TON. Tam lahko zahtevate tudi testne grame. https://t.me/tondev_ru
  8. Še en klepet o TON, v katerem sem našel koristne informacije: https://t.me/TONgramDev
  9. Prva faza tekmovanja: https://contest.com/blockchain
  10. Druga faza tekmovanja: https://contest.com/blockchain-2

Vir: www.habr.com

Dodaj komentar