O tom, jak napsat a publikovat chytrý kontrakt v Telegram Open Network (TON)

Jak napsat a publikovat smart kontrakt v TON

O čem je tento článek?

V článku popíšu, jak jsem se zúčastnil prvního (z dvou) soutěže Telegramu o blockchain, nezískal jsem žádné ocenění a rozhodl se svůj zážitek zdokumentovat, aby nezapadl do zapomnění a možná pomohl někomu.

Protože jsem nechtěl psát abstraktní kód, ale vytvořit něco funkčního, napsal jsem pro článek smart kontrakt na okamžitou loterii a web, který zobrazuje data smart kontraktu přímo z TON bez použití meziskladů.

Článek bude užitečný pro ty, kteří chtějí vytvořit svůj první smart kontrakt v TON, ale nevědí, jak začít.

Na příkladu loterie projdu od nastavení prostředí až po publikaci smart kontraktu, interakci s ním a vytvořím web pro zisk a publikaci dat.

O účasti v soutěži

V říjnu minulého roku Telegram vyhlásil soutěž o blockchain s novými jazyky Fift a FunC. Bylo třeba napsat jakýkoliv z pěti navrhovaných smart kontraktů. Uvažoval jsem, že by nebylo špatné se pustit do něčeho neobvyklého, naučit se jazyk a vytvořit něco, i když v budoucnu nemusím psát nic jiného. Navíc, téma je stále v kurzu.

Je třeba říci, že jsem neměl žádné zkušenosti s vývojem smart kontraktů.

Plánoval jsem se účastnit až do samého konce, pokud to půjde, a poté napsat přehledový článek, ale hned v prvním kole jsem selhal. Já napsal peněženku s multi-podpisem na FunC a ta v zásadě fungovala. Jako základ jsem vzal smart kontrakt napsaný v Solidity.

V tu chvíli jsem si myslel, že to určitě stačí, abych získal alespoň nějaké ocenění. Výsledkem bylo, že asi 40 z 60 účastníků se stalo oceněnými a mezi nimi jsem nebyl. V tom žádné drama nebylo, ale byla tam jedna věc, která mě znepokojila. V době vyhlášení výsledků žádné hodnocení s testem mého kontraktu nebylo provedeno, ptal jsem se účastníků v chatu, jestli je někdo další, kdo ho nemá, nebyli mezi nimi.

Zřejmě si všimli mých zpráv, a po dvou dnech rozhodčí zveřejnili komentář, a já jsem tak úplně nepochopil, zda můj smart kontrakt během hodnocení prostě přehlédli, nebo jej považovali za natolik špatný, že si nezaslouží komentář. Položil jsem otázku na stránce, ale odpovědi jsem se nedočkal. Ačkoliv kdo posuzoval — to není tajemství, považoval jsem za zbytečné psát osobní zprávy.

Na porozumění bylo vynaloženo nemálo času, proto bylo rozhodnuto napsat článek. Jelikož informací zatím není příliš, článek pomůže ušetřit čas všem zainteresovaným.

Koncept fungování chytrých kontraktů v TON

Než začneme něco psát, musíme se ujistit, z jakého úhlu k této věci přistoupit. Proto nyní vysvětlím, z jakých částí se systém skládá. Přesněji řečeno, které části je třeba znát, aby bylo možné napsat alespoň nějaký funkční kontrakt.

Soustředíme se na psaní chytrého kontraktu a práci s TON Virtual Machine (TVM), Fift a FunC, proto článek více připomíná popis vývoje běžného programu. Na tom, jak platforma samotná funguje, se zde zastavovat nebudeme.

O tom, jak funguje TVM a jazyk Fift , existuje dobrá oficiální dokumentace. Během účasti v soutěži a nyní při psaní aktuálního kontraktu jsem se na ni často obracel.

Hlavní jazyk, ve kterém jsou psány chytré kontrakty — FunC. V současnosti neexistuje žádná dokumentace, takže pro napsání něčeho je nutné studovat příklady chytrých kontraktů z oficiálního repozitáře a také samotnou implementaci jazyka tamtéž, navíc je dobré se podívat na příklady chytrých kontraktů z uplynulých dvou soutěží. Odkazy najdete na konci článku.

Představme si, že už jsme napsali chytrý kontrakt na FunC, poté zkompilujeme kód do Fift-assembleru.

Zkompilovaný chytrý kontrakt zbývá publikovat. K tomu musíme napsat funkci v Fift, která na vstupu přijme kód chytrého kontraktu a ještě některé parametry, a na výstupu se získá soubor s příponou .boc (což znamená "bag of cells"), a v závislosti na způsobu, jakým ji napíšeme, privátní klíč a adresu, která se generuje na základě kódu chytrého kontrakt. Na adresu chytrého kontraktu, který ještě nebyl publikován, je už možné posílat gramy.

Abychom publikovali chytrý kontrakt v TON, je nutné odeslat získaný .boc soubor do blockchainu pomocí light klienta (o čemž bude níže). Ale než to publikujeme, je potřeba převést gramy na vygenerovanou adresu, jinak chytrý kontrakt nebude publikován. Po publikaci s chytrým kontraktem bude možné interagovat, posílat mu zprávy zvenčí (například pomocí light klienta) nebo zevnitř (například jeden chytrý kontrakt posílá druhému zprávu uvnitř TON).

Jakmile jsme pochopili, jak se kód publikuje, další postup je jednodušší. Přesně víme, co chceme napsat a jak bude naše aplikace fungovat. Při psaní hledáme, jak bylo toto již implementováno v existujících chytrých smlouvách, nebo se podíváme na kód implementace. Fift a FunC v oficiálním repozitáři, nebo se podíváme do oficiální dokumentace.

Často jsem hledal klíčová slova v Telegram chatu, kde se setkali všichni účastníci soutěže a zaměstnanci Telegramu, tak se stalo, že během soutěže se tam všichni sešli a začali diskutovat o Fift a FunC. Odkaz na konci článku.

Je čas přejít od teorie k praxi.

Příprava prostředí pro práci s TON

Vše, co bude v článku popsáno, jsem provedl na MacOS a ověřil na čistém Ubuntu 18.04 LTS pomocí Dockeru.

První věc, kterou musíte udělat, je stáhnout a nainstalovat lite-client , pomocí kterého lze posílat dotazy do TON.

Návod na oficiálních stránkách poměrně podrobně a srozumitelně popisuje proces instalace a vynechává některé detaily. Zde se řídíme názorem a zároveň instalujeme chybějící závislosti. Nechtěl jsem sám kompilovat každý projekt a instaloval jsem z oficiálního repozitáře Ubuntu (na MacOS jsem použil 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 

Jakmile jsou všechny závislosti nainstalovány, můžeme nainstalovat lite-client, Fift, FunC.

Nejprve klonujeme repozitář TON spolu se závislostmi. Pro pohodlí to všechno provedeme ve složce ~\/TON.

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

V repozitáři se také nacházejí implementace Fift a FunC.

Teď jsme připraveni sestavit projekt. Kód repozitáře byl zklonován do složky ~\/TON\/ton. V ~\/TON vytvořte složku build a v ní sestavíme projekt.

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

Jelikož máme v úmyslu psát chytrou smlouvu, potřebujeme nejen lite-client, ale také Fift s FunC, proto kompilujeme všechno. Není to rychlý proces, takže čekáme.

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

Dále stáhneme konfigurační soubor, ve kterém jsou údaje o nodu, ke kterému lite-client se připojíme.

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

Děláme první dotazy do TON

Nyní spustíme lite-client.

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

Pokud kompilace proběhla úspěšně, po spuštění uvidíte log připojení klienta k nodu.

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

Můžete vykonat příkaz help a podívat se, jaké příkazy jsou k dispozici.

help

Vyjmenujeme příkazy, které budeme používat v tomto článku.

seznam dostupných příkazů:
last    Získá poslední blok a informace o stavu ze serveru
sendfile  Načte serializovanou zprávu z  a odešle ji na server
getaccount  []  Načte nejnovější stav specifikovaného účtu;  je ve formátu [:]
runmethod  []  ...   Spustí GET metodu  účtu  se specifikovanými parametry

last získává poslední vytvořený blok ze serveru.

sendfile  odesílá do TON soubor se zprávou, právě pomocí tohoto příkazu se publikuje smart kontrakt a jeho požadavky.

getaccount  načítá aktuální stav smart kontraktu na uvedené adrese.

runmethod  []    spouští get-metody smart kontraktu. 

Nyní jsme připraveni napsat samotný kontrakt.

Implementace

Nápad

Jak jsem již psal výše, smart kontrakt, který píšeme, je loterie.

Navíc to není loterie, kde si musíte koupit lístek a čekat hodinu, den nebo měsíc, ale okamžitá, ve které uživatel převádí na adresu kontraktu N gramy, a okamžitě dostává zpět 2 * N gramů nebo prohrává. Pravděpodobnost výhry uděláme kolem 40 %. Pokud gramů na výplatu nebude dost, budeme považovat transakci za doplnění.

Je důležité, aby sázky bylo možné vidět v reálném čase a pohodlným způsobem, aby uživatel ihned pochopil, jestli vyhrál nebo prohrál. Proto je třeba vytvořit webovou stránku, která ukáže sázky a výsledky přímo z TON.

Napsání smart kontraktu

Pro pohodlí jsem vytvořil zvýraznění kódu pro FunC, plugin můžete najít a nainstalovat v hledání Visual Studio Code. Pokud byste chtěli něco přidat, plugin je k dispozici veřejně. Dříve byl rovněž vytvořen plugin pro práci s Fift, který si také můžete nainstalovat v VSC.

I hned vytvoříme repozitář, do kterého budeme commitovat mezivýsledky.

Abychom si usnadnili život, budeme psát smart kontrakt a testovat jej lokálně, dokud nebude připraven. Až poté ho zveřejníme v TON.

Smart kontrakt má dvě externí metody, na které se lze obrátit. První, recv_external() tato funkce se provádí, když k kontraktu přichází žádost z vnějšího světa, tedy ne z TON, například když sami formulujeme zprávu a odesíláme ji přes lite-client. Druhý, recv_internal() to je, když uvnitř samotného TON nějaký kontrakt volá náš. V obou případech lze předat parametry do funkce.

Začněme jednoduchým příkladem, který bude fungovat, pokud ho zveřejníme, ale není v něm žádná funkční náplň.

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

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

Zde je třeba vysvětlit, co je slice. Všechna uložená data v TON Blockchain jsou kolekcí TVM cell nebo jen cell, v takové buňce lze uložit až 1023 bitů dat a až 4 odkazy na jiné buňky.

TVM cell slice nebo slice je část existující cell používá se pro její parsování, později to bude jasné. Hlavní pro nás je, že do chytrého kontraktu můžeme předat slice a v závislosti na typu zprávy zpracovat data v recv_external() nebo recv_internal().

impure — klíčové slovo, které naznačuje, že funkce mění data chytrého kontraktu.

Uložíme kód kontraktu do lottery-code.fc a zkompilujeme.

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

Hodnoty flagů lze zobrazit pomocí příkazu

~\/TON\/build\/crypto\/func -help

Získali jsme zkompilovaný Fift-assembler kód v 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

Může být spuštěn lokálně, pro to připravíme prostředí.

Poznamenáme, že v prvním řádku se připojuje Asm.fif, to je kód napsaný v Fift pro Fift-assembler.

Protože chceme spouštět a testovat chytrý kontrakt lokálně, vytvoříme soubor lottery-test-suite.fif a zkopírujeme tam zkompilovaný kód, přičemž nahradíme poslední řádek, který zapisuje kód chytrého kontraktu do konstanty code, abychom ho později předali virtuální mu POD:

"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

Zatím to vypadá jasně, nyní přidáme do stejného souboru kód, který budeme používat pro spuštění TVM.

0 tuple 0x076ef1ea , \/\/ magic
0 , 0 , \/\/ akce msg_sents
1570998536 , \/\/ unix_time
1 , 1 , 3 , \/\/ block_lt, trans_lt, rand_seed
0 tuple 100000000000000 , dictnew , , \/\/ zbývající zůstatek
0 , dictnew , \/\/ contract_address, global_config
1 tuple \/\/ zabalit do dalšího tuple
constant c7

0 constant recv_internal \/\/ pro spuštění recv_internal() 
-1 constant recv_external \/\/ pro vyvolání recv_external()

V c7 zapíšeme kontext, tedy data, s nimiž se bude spouštět TVM (nebo stav sítě). Už během soutěže jeden z vývojářů ukázal, jak se vytváří c7 a já jsem si to zkopíroval. V tomto článku možná budeme potřebovat měnit rand_seed protože od něj závisí generace náhodného čísla a nemění se, takže se vždy vrátí stejné číslo.

recv_internal a recv_external konstanty se hodnotou 0 a -1 budou odpovídat za zavolání příslušných funkcí ve smart kontraktu.

Nyní jsme připraveni vytvořit první test pro náš prázdný smart kontrakt. Pro názornost zatím všechny testy přidáme do tohoto souboru lottery-test-suite.fif.

Vytvoříme proměnnou úložiště a zapíšeme do ní prázdnou cell, to bude úložiště smart kontraktu.

zpráva to je zpráva, kterou předáme smart kontraktu zvenku. Také to zatím uděláme prázdné.

úložný prostor 
<b b> úložiště ! 

variabilní zpráva 
<b b> zpráva ! 

Po přípravě konstant a proměnných spustíme TVM pomocí příkazu runvmctx a předáme vytvořené parametry jako vstup.

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

Nakonec dostaneme takovýto mezičlánkový kód na Fift.

Nyní můžeme spustit získaný kód.

export FIFTPATH=~\/TON\/ton\/crypto\/fift\/lib \/\/ provedeme jednou pro pohodlí 
~\/TON\/build\/crypto\/fift -s lottery-test-suite.fif 

Program by měl proběhnout bez chyb a ve výstupu uvidíme log vykonávání:

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

Skvěle, napsali jsme první funkční verzi smart kontraktu.

Nyní je potřeba přidat funkčnost. Nejprve se zaměříme na zprávy, které přicházejí z vnějšího světa do recv_external()

Vývojář si sám vybírá formát zprávy, který kontrakt může přijmout.

Ale obvykle,

  • za prvé, chceme chránit náš kontrakt před vnějším světem a zajistit, aby pouze vlastník kontraktu mohl posílat externí zprávy na něj.
  • za druhé, když posíláme platnou zprávu do TON, chceme, aby se to stalo přesně jednou, a při opakovaném poslání téže zprávy smart kontrakt ji odmítl.

Proto v téměř každém kontraktu řešíme tyto dva problémy, protože náš kontrakt přijímá externí zprávy, musíme se o to také postarat.

Uděláme to v opačném pořadí. Nejprve vyřešíme problém s opakováním, pokud kontrakt již obdržel takovou zprávu a zpracoval ji, nebude ji provádět podruhé. A pak vyřešíme problém, aby pouze určitý okruh osob mohl posílat zprávy smart kontraktu.

Existují různé způsoby, jak vyřešit problém s opakujícími se zprávami. Uděláme to takto. V chytrém kontraktu inicializujeme počítadlo přijatých zpráv s počáteční hodnotou 0. Do každé zprávy přidáme aktuální hodnotu počítadla. Pokud hodnota počítadla ve zprávě nesouhlasí s hodnotou v chytrém kontraktu, nebudeme ji zpracovávat; pokud souhlasí, zpracujeme ji a zvýšíme počítadlo v chytrém kontraktu o 1.

Vracíme se do lottery-test-suite.fif a dopíšeme do něj druhý test. Odešleme nesprávné číslo, kód by měl vyhodit výjimku. Například ať je v datech kontraktu uloženo 166, a my odešleme 165.

<b 166 32 u, b> úložiště !
<b 165 32 u, b> zpráva !

zpráva @ 
recv_external 
kód 
úložiště @ 
c7 
runvmctx

drop 
exit_code ! 
."Kód výstupu " exit_code @ . cr 
exit_code @ 33 - abort"Test #2 nebyl úspěšný"

Spustíme.

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

A uvidíme, že test probíhá s chybou.

[ 1][t 0][1582283084.210902214][words.cpp:3046] lottery-test-suite.fif:67: abort": Test #2 nebyl splněn
[ 1][t 0][1582283084.210941076][fift-main.cpp:196]      Chyba při interpretaci souboru `lottery-test-suite.fif`: chyba při interpretaci zahrnutého souboru `lottery-test-suite.fif` : lottery-test-suite.fif:67: abort": Test #2 nebyl splněn

V této fázi lottery-test-suite.fif by měl vypadat jako na odkazu.

Nyní přidáme logiku počítadla do chytrého kontraktu v lottery-code.fc.

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

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

V slice in_msg obsahuje zprávu, kterou posíláme.

První, co uděláme, je zkontrolovat, zda ve zprávě jsou data; pokud ne, jednoduše odejdeme.

Dále zprávu parsujeme. in_msg~load_uint(32) načítá číslo 165, 32bitové unsigned int z předané zprávy.

Poté načítáme 32 bitů ze skladu chytrého kontraktu. Kontrolujeme, že načtené číslo souhlasí s předaným; pokud ne, vyhodíme výjimku. V našem případě, protože předáváme nesouhlasící, by měla být vyhozená výjimka.

Nyní zkompilujeme.

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

Výsledný kód zkopírujeme do lottery-test-suite.fif, nezapomínáme nahradit poslední řádek.

Zkontrolujeme, že test prochází:

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

Tady můžete vidět odpovídající commit s aktuálními výsledky.

Poznamenáme, že neustále kopírovat zkompilovaný kód chytrého kontraktu do souboru s testy není pohodlné, proto napíšeme skript, který bude zapisovat kód do konstanty za nás, a my jednoduše připojíme zkompilovaný kód do našich testů pomocí "include".

V adresáři projektu vytvoříme soubor build.sh s následujícím obsahem.

#!/bin/bash

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

Učiníme ho spustitelným.

chmod +x ./build.sh

Nyní stačí spustit náš skript, aby se zkompilovala smlouva. Kromě toho musíme jej zapsat do konstanty code. Proto vytvoříme nový soubor lotter-compiled-for-test.fif, který zahrneme v souboru lottery-test-suite.fif.

Přidáme do sh skriptu kód, který jednoduše zduplikuje zkompilovaný soubor do lotter-compiled-for-test.fif a změní v něm poslední řádek.

# 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

Nyní, abychom to zkontrolovali, spustíme vzniklý skript a vygeneruje se nám soubor lottery-compiled-for-test.fif, který zahrneme do našeho lottery-test-suite.fif

V lottery-test-suite.fif odstraníme kód smlouvy a přidáme řádek "lottery-compiled-for-test.fif" include.

Spustíme testy, abychom zkontrolovali, že procházejí.

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

Skvěle, nyní, abychom automatizovali spuštění testů, vytvoříme soubor test.sh, který nejprve vykoná build.sh, a poté spustí testy.

touch test.sh
chmod +x test.sh

Dovnitř napíšeme

.\/build.sh 

echo "nKompilace dokončena n"

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

Uděláme test.sh a spustíme, abychom se ujistili, že testy fungují.

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

Kontrolujeme, že se smlouva kompiluje a testy se vykonávají.

Skvěle, nyní při spuštění test.sh bude okamžitě probíhat kompilace a spuštění testů. Zde je odkaz na commit.

Dobře, než budeme pokračovat, udělejme pro pohodlí ještě jednu věc.

Vytvoříme složku build kde budeme uchovávat zkompilovanou smlouvu a její klon zapsaný do konstanty lottery-compiled.fif, lottery-compiled-for-test.fif. Také vytvoříme složku test kde budou uloženy soubor s testy lottery-test-suite.fif a potenciálně další pomocné soubory. Odkaz na příslušné změny.

Pokračujme ve vývoji chytré smlouvy.

Dále by měl být test, který kontroluje, že zpráva je přijímána a čítač se aktualizuje ve skladu, když posíláme správné číslo. Ale to uděláme později.

Teď přemýšlíme o tom, jaká je struktura dat a jaká data je třeba uchovávat v chytré smlouvě.

Popíšu vše, co uchováváme.

`seqno` 32-bit celé kladné číslo, počítadlo. 

`pubkey` 256-bit celé kladné číslo, veřejný klíč, pomocí kterého budeme kontrolovat podpis zprávy zaslané zvenčí, o čemž dále. 

`order_seqno` 32-bit celé kladné číslo, které uchovává počítadlo počtu sázek. 

`number_of_wins` 32-bit celé kladné číslo, které uchovává počet výher. 

`incoming_amount` typ dat Gram (první 4 bity odpovídají délce), uchovává celkové množství gramů, které byly zaslány na kontrakt. 

`outgoing_amount` celkové množství gramů, které bylo zasláno výhercům. 

`owner_wc` číslo workchainu, 32-bit (na některých místech je uvedeno, že 8-bit) celé číslo. V současnosti jsou pouze dvě -1 a 0. 

`owner_account_id` 256-bit celé kladné číslo, adresa kontraktu v aktuálním workchainu. 

`orders` proměnná typu slovník, uchovává posledních dvacet sázek. 

Dále je potřeba napsat dvě funkce. První pojmenujme pack_state(), která bude balit data pro následné uložení do úložiště smart kontraktu. Druhou, nazveme unpack_state() , která bude číst a vracet data z úložiště.

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

Přidáme tyto dvě funkce na začátek smart kontraktu. Výsledkem bude takovýto mezikrok.

Abychom uložili data, bude potřeba zavolat vestavěnou funkci set_data() a ta zapíše data z pack_state() do úložiště smart kontraktu.

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

Nyní, když máme pohodlné funkce pro zápis a čtení dat, můžeme jít dál.

Musíme zkontrolovat, že příchozí zpráva je podepsána vlastníkem kontraktu (nebo jiným uživatelem, který má přístup k soukromému klíči).

Když publikujeme smart kontrakt, můžeme jej inicializovat s potřebnými daty ve skladu, které se uchovají pro budoucí použití. Zapíšeme tam veřejný klíč, abychom mohli ověřit, že podpis příchozí zprávy byl vytvořen odpovídajícím privátním klíčem.

Než budeme pokračovat, vytvořme privátní klíč a zapíšeme jej do test/keys/owner.pk. Za tímto účelem spustíme Fift v interaktivním režimu a vykonáme čtyři příkazy.

`newkeypair` generuje veřejný a privátní klíč a zapisuje je do zásobníku. 

`drop` odstraní zásobníku vrchní prvek (v tomto případě veřejný klíč)  

`.s` pouze zobrazí, co je v zásobníku v tomto okamžiku 

`"owner.pk" B>file` zapíše privátní klíč do souboru nazvaného `owner.pk`. 

`bye` ukončuje práci s Fift. 

Vytvoříme složku keys ve složce test a tam zapíšeme privátní klíč.

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

Vidíme v aktuální složce soubor owner.pk.

Odstraňujeme veřejný klíč ze zásobníku, kdykoli ho budeme potřebovat, můžeme jej získat z privátního.

Nyní potřebujeme napsat kontrolu podpisu. Začneme testem. Nejprve načteme privátní klíč ze souboru pomocí funkce file>B a zapíšeme jej do proměnné owner_private_key, dále pomocí funkce priv>pub převedeme privátní klíč na veřejný a uložíme výsledek do 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 !

Oba klíče budeme potřebovat.

Inicializujeme úložiště smart kontraktu náhodnými daty ve stejné posloupnosti, jako v funkci pack_state()a zapíšeme do proměnné úložiště.

proměnná owner_private_key
proměnná owner_public_key 
proměnná orders
proměnná owner_wc
proměnná owner_account_id

".\/keys\/owner.pk" soubor&gt;B owner_private_key !
owner_private_key @ priv&gt;pub owner_public_key !
dictnew orders !
0 owner_wc !
0 owner_account_id !

<b 0 32 u, owner_public_key @ b, gram, owner_wc i, owner_account_id 256 orders dict, b> úložiště !

Dále vytvoříme podepsanou zprávu, která bude obsahovat pouze podpis a hodnotu čítače.

Nejprve vytvoříme data, která chceme přenést, potom je podepíšeme svým privátním klíčem a nakonec vytvoříme podepsanou zprávu.

variabilní zpráva_k_podepsání
variabilní zpráva_k_odeslání
variabilní podpis
<b 0 32 u, b> zpráva_k_podepsání !
zpráva_k_podepsání @ majitel_private_key @ ed25519_sign_uint podpis !
<b signature @ b, 0 32 u, b> &lt;s !  

Výsledná zpráva, kterou odešleme do smart kontraktu, je uložena v proměnné message_to_send, pokud jde o funkce hashu, ed25519_sign_uint si můžete přečíst v dokumentaci k Fift.

A pro spuštění testu znovu zavoláme.

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

Takto měla by vypadat jako soubor s testy v této fázi.

Spustíme test a selže, proto upravíme smart kontrakt, aby mohl přijímat zprávy takového formátu a ověřovat podpis.

Nejprve načteme 512 bitů podpisu z zprávy a uložíme je do proměnné, poté načteme 32 bitů z proměnné čítače.

Jelikož máme funkci pro načítání dat ze smart kontraktu, budeme ji používat.

Dále proběhne kontrola čítače předaného spolu se stavem a kontrola podpisu. Pokud se něco neshoduje, vyhodíme výjimku se odpovídající chybovým kódem.

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

Odpovídající commit tady.

Spustíme testy a uvidíme, že druhý test selhává. Z důvodu nedostatku bitů ve zprávě a nedostatku bitů ve skladu selhává kód při parsování. Musíme přidat podpis zprávy, kterou odesíláme, a zkopírovat sklad z posledního testu.

Ve druhém testu přidáme podpis zprávy a změníme sklad smart kontraktu. Takto Takto momentálně vypadá soubor s testy.

Napíšeme čtvrtý test, ve kterém budeme odesílat zprávu podepsanou cizím soukromým klíčem. Vytvoříme další soukromý klíč a uložíme ho do souboru not-owner.pk. Tímto soukromým klíčem podepíšeme zprávu. Spustíme testy a ujistíme se, že všechny testy procházejí. Commit do současné doby.

Nyní konečně můžeme přejít k implementaci logiky smart kontraktu.
V recv_external() Budeme přijímat dva typy zpráv.

Jelikož náš kontrakt bude akumulovat prohry hráčů, tyto peníze musí být převedeny na tvůrce loterie. Adresa peněženky tvůrce loterie je uložena ve skladu při vytváření kontraktu.

Pro jistotu potřebujeme možnost měnit adresu, na kterou posílat gramy prohrávajících. Také bychom měli mít možnost posílat gramy z loterie na adresu vlastníka.

Začněme s prvním. Nejprve napíšeme test, který prověří, že po odeslání zprávy smart kontrakt uložil novou adresu do skladu. Všimneme si, že do zprávy kromě čítače a nové adresy přidáváme také akce 7bitové celé nezáporné číslo, podle kterého budeme vybírat, jak zpracovat zprávu ve smart kontraktu.

<b 0 32 u, 1 @ 7 new_owner_wc i, new_owner_account_id 256 b> zpráva_k_podepsání !

V testu lze vidět, jak probíhá deserializace skladu smart kontraktu. úložiště V Fift. Deserializace proměnných je popsána v dokumentaci k Fift.

Odkaz na commit s přidáním testu.

Spouštíme test a ujistíme se, že selhává. Nyní přidáme logiku pro změnu adresy vlastníka loterie.

Ve smart kontraktu pokračujeme v parsování zpráva, čteme do akce. Připomeňme, že budeme mít dvě akce: změna adresy a odeslání gramů.

Potom načteme novou adresu vlastníka kontraktu a uložíme ji do úložiště.
Spouštíme testy a vidíme, že třetí test selhává. Selhává kvůli tomu, že kontrakt nyní navíc parsuje 7 bitů z zprávy, které v testu chybí. Přidáme do zprávy neexistující akce. Spustíme testy a vidíme, že všechny projdou. Tady commit na změny. Skvěle.

Nyní napíšeme logiku pro odeslání uvedeného počtu gramů na dříve uloženou adresu.

Nejdříve napíšeme test. Napíšeme dva testy, jeden kdy dostatečný zůstatek chybí, druhý kdy by vše mělo proběhnout úspěšně. Testy si můžete prohlédnout v tomto commitu.

Nyní doplníme kód. Nejprve napíšeme dvě pomocné metody. První get metodu pro zjištění aktuálního zůstatku smart kontraktu.

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

A druhou pro odeslání gramů na jiný smart kontrakt. Tuto metodu jsem zcela zkopíroval z jiného smart kontraktu.

() 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 <= formát indikátoru int_msg_info$0 
    ;;  .store_uint(1, 1) ;; 1 <= ihr zakázáno
    ;;  .store_uint(1, 1) ;; 1 <= bounce = true
    ;;  .store_uint(0, 1) ;; 0 <= bounced = false
    ;;  .store_uint(4, 5)  ;; 00100 <= adresní flagy, anycast = false, 8-bit pracovní řetězec
        .store_uint (196, 9)
        .store_int(wc, 8)
        .store_uint(addr, 256)
        .store_grams(grams)
        .store_uint(0, 107) ;; 106 nul +  0 jako indikátor, že neexistuje buňka s daty.
        .end_cell(); 
    send_raw_message(msg, 3); ;; mod, 2 pro ignorování chyb, 1 pro platbu poplatků ze strany odesílatele, 64 pro vracení hodnoty příchozí zprávy
}

Přidáme tyto dvě metody do smart kontraktu a napíšeme logiku. Nejprve parsujeme množství gramů ze zprávy. Dále kontrolujeme zůstatek, pokud nestačí, vyhodíme výjimku. Pokud je vše v pořádku, odešleme gramů na uloženou adresu a aktualizujeme počítadlo.

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

Takto vypadá smart kontrakt v tuto chvíli. Spustíme testy a ujistíme se, že probíhají.

Mimochodem, za zpracovanou zprávu může být u smart kontraktu každou chvíli stržena provize. Aby smart kontrakt vykonal požadavek na zprávě, je třeba po základních kontrolách vyvolat accept_message().

Nyní se zaměřme na vnitřní zprávy. V podstatě budeme pouze přijímat gramy a posílat zpět hráči dvojnásobnou částku při výhře a třetinu vlastníkovi při prohře.

Nejprve napíšeme jednoduchý test. K tomu budeme potřebovat testovací adresu smart kontraktu, ze které budeme jakoby posílat gramy na smart kontrakt.

Adresa smart kontraktu se skládá ze dvou čísel, 32bitové celé číslo odpovídá za workchain a 256bitové celé nezáporné číslo je unikátní číslo účtu v tomto workchainu. Například, -1 a 12345, tuto adresu uložíme do souboru.

Zkopíroval jsem funkci pro uložení adresy z 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

Pojďme se podívat, jak funguje funkce, to nám poskytne pochopení, jak funguje Fift. Spustíme Fift v interaktivním režimu.

~\/TON\/build\/crypto\/fift -i 

Nejprve vložíme do zásobníku -1, 12345 a název budoucího souboru "sender.addr":

-1 12345 "sender.addr" 

Dalším krokem se vykoná funkce -rot, která posune zásobník tak, že na vrcholu zásobníku bude unikátní číslo smart kontraktu:

"sender.addr" -1 12345

256 u>B převede 256bitové nezáporné celé číslo na bajty.

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap prohodí dva horní prvky zásobníku.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

32 i>B převede 32bitové celé číslo na bajty.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ spojí dvě sekvence bajtů.

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

Znovu swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

A nakonec dojde k zápisu bajtů do souboru B>file. Po tomto je náš zásobník prázdný. Zastavujeme Fift. V aktuálním adresáři byl vytvořen soubor sender.addr. Přesuneme soubor do vytvořené složky test\/addresses\/.

Napíšeme jednoduchý test, který bude posílat gramy na smart kontrakt. Tady je commit.

Nyní se zaměříme na logiku loterie.

První, co uděláme, je zkontrolovat zprávu bounced nebo ne, pokud bounced, tak ignorujeme. bounced to znamená, že kontrakt vrátí gramy, pokud dojde k nějaké chybě. My gramy zpět nevrátíme, pokud by náhodou došlo k chybě.

Kontrolujeme zůstatek, pokud je menší než půl gramu, tak prostě přijmeme zprávu a ignorujeme.

Dále parsujeme adresu smart kontraktu, ze kterého přišla zpráva.

Čteme data ze skladu a poté odstraňujeme staré sázky z historie, pokud jich je více než dvacet. Pro snadnost jsem napsal tři další funkce. pack_order(), unpack_order(), remove_old_orders().

Dále se podíváme, pokud není dostatek prostředků na výplatu, tak to považujeme za doplnění, a ukládáme doplnění do orders.

Dále konečně podstata smart kontraktu.

Nejprve, pokud hráč prohraje, ukládáme ho do historie sázek a pokud je suma větší než 3 gramy, pošleme 1/3 majiteli smart kontraktu.

Pokud hráč vyhraje, posíláme dvojnásobnou částku na adresu hráče a dále ukládáme informace o sázce do historie.

() 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) { ;; ignorovat odražené
        return ();
    }
    if (order_amount < 500000000) { ;; pouze přijmout gramy bez změny stavu 
        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() = 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));
}

A to je vše. Odpovídající commit.

Teď zbývá jednoduché, uděláme get metody, aby se z vnějšího světa dala získat informace o stavu kontraktu (v podstatě číst data ze skladu smart kontraktu).

Přidáme get metody. O tom, jak získávat informace o smart kontraktu, napíšeme níže.

Také jsem zapomněl přidat kód, který zpracovává první požadavek, který se odehrává při publikaci chytrého kontraktu. Odpovídající commit. A také Velké zpoždění při nízkém QPS bylo způsobeno optimalizací OS. S ohledem na zpětnou vazbu, profilování nezjistilo zpoždění, protože bylo prováděno v jádrovém režimu, nikoli v chybu s odesíláním 1/3 částky na účet vlastníka.

Teď už zbývá publikovat chytrý kontrakt. Vytvořme složku requests.

Základem jsem vzal kód publikace simple-wallet-code.fc který je možné najít v oficiálním repozitáři.

Co si zaslouží pozornost. Vytváříme úložiště chytrého kontraktu a vstupní zprávu. Poté se generuje adresa chytrého kontraktu, tedy adresa je známa ještě před publikací v TON. Poté je třeba na tuto adresu poslat několik gramů a teprve poté odeslat soubor se samotným chytrým kontraktem, protože za uchovávání chytrého kontraktu a operace v něm síť požaduje poplatek (validátoři, kteří uchovávají a provádějí chytré kontrakty). Kód lze vidět zde.

Nyní spouštíme kód publikace a dostáváme lottery-query.boc soubor a adresu chytrého kontraktu.

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

Nezapomínejte uložit vygenerované soubory: lottery-query.boc, lottery.addr, lottery.pk.

Mezi jiným v logu provádění uvidíme adresu chytrého kontraktu.

new wallet address = 0:044910149dbeaf8eadbb2b28722e7d6a2dc6e264ec2f1d9bebd6fb209079bc2a 
(Ukládání adresy do souboru lottery.addr)
Non-bounceable address (for init): 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd
Bounceable address (for later access): kQAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KpFY

Pro zajímavost provedeme dotaz do TON

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

A uvidíme, že účet s touto adresou je prázdný.

account state is empty

Posíláme na adresu 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 Gramy a po několika sekundách provádíme stejný příkaz. Pro odeslání gramů používám oficiální peněženku, a testovací gramy si můžete vyžádat od někoho z chatu, o kterém budu mluvit na konci článku.

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Dívá se, že v síti vznikl neinitialized (state:account_uninit) chytrý kontrakt s touto adresou a zůstatkem 1 000 000 000 nanogramů.

stav účtu je (účet
  addr:(addr_std
    anycast:nothing workchain_id:0 adresa: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_}
poslední transakce lt = 3825478000001 hash = B043616AE016682699477FFF01E6E903878CDFD6846042BA1BFC64775E7AC6C4
zůstatek účtu je 2000000000ng

Nyní zveřejníme chytrý kontrakt. Spustíme lite-client a provedeme.

> sendfile lottery-query.boc
[ 1][t 2][1583008371.631410122][lite-client.cpp:966][!testnode] odesílání dotazu z souboru lottery-query.boc
[ 3][t 1][1583008371.828550100][lite-client.cpp:976][!query]    stav externí zprávy je 1 

Zkontrolujeme, že kontrakt byl zveřejněn.

> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Mezi jinými obdržíme.

  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

Vidíme, že account_active.

Odpovídající commit s změnami tady.

Nyní vytvoříme požadavky pro interakci s chytrým kontraktem.

Konkrétně první pro změnu adresy necháme jako samostatnou práci a druhý pro odeslání gramů na adresu vlastníka provedeme. V podstatě budeme potřebovat udělat to samé jako v testu na odesílání gramů.

Takovou zprávu budeme posílat na chytrý kontrakt, kde msg_seqno 165, akce 2 a 9.5 gramů k odeslání.

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

Nezapomeňte podepsat zprávu soukromým klíčem lottery.pk, který byl vygenerován dříve při vytváření chytrého kontraktu. Zde je odpovídající commit.

Získáváme informace z chytrého kontraktu pomocí get metod

Nyní se podíváme, jak spouštět get metody chytrého kontraktu.

Spouštíme lite-client a spouštíme get metody, které jsme napsali.

$ .\/lite-client\/lite-client -C ton-lite-client-test1.config.json
> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd balance
argumenty:  [ 104128 ] 
výsledek:  [ 64633878952 ] 
...

V result obsahuje hodnotu, kterou vrací funkce balance() z našeho chytrého kontraktu.
Totéž provedeme ještě pro další metody.

> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_seqno
...
argumenty:  [ 77871 ] 
výsledek:  [ 1 ] 

Požádáme o historii sázek.

> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_orders
...
argumenty:  [ 67442 ] 
výsledek:  [ ([0 1 1583258284 10000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [1 3 1583258347 4000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [2 1 1583259901 50000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308]) ] 

Budeme používat lite-client a GET metody k zobrazení informací o smart kontraktu na webu.

Zobrazujeme data smart kontraktu na webu

Napsal jsem jednoduchou webovou stránku v Pythonu, abych zobrazil data ze smart kontraktu přehledně. Na něj se teď nebudu podrobně zastavovat a zveřejním stránku jedním commitem.

Žádosti k TON se provádějí z CouchDB prostřednictvím lite-client. Pro pohodlí je web zabalen do Dockeru a zveřejněn na Google Cloud. Odkaz na web.

Zkoušíme

Teď zkusíme poslat gramy pro dobití z peněženky. Pošleme 40 gramů a uděláme pár sázek pro názornost. Vidíme, že web zobrazuje historii sázek, aktuální procento výhry a další užitečné informace.

Vidíme, že první jsme vyhráli, druhou jsme prohráli.

Poznámka na závěr

Článek se ukázal být mnohem delší, než jsem předpokládal, možná by bylo možné se zkrátit, ale možná je to právě pro někoho, kdo nic neví o TON a chce napsat a zveřejnit ne zcela jednoduchý smart kontrakt s možností s ním interagovat. Možná některé věci by šly vysvětlit jednodušeji.

Možná některé aspekty realizace by šly provést efektivněji a elegantněji, ale v tom případě by příprava článku trvala ještě déle. Také možná, že jsem někde udělal chybu nebo něco nepochopil, proto pokud děláte něco vážného, je třeba se opírat o oficiální dokumentaci nebo oficiální repozitář s kódem TON.

Je třeba poznamenat, že jelikož je samotný TON stále ve fázi aktivního vývoje, mohou nastat změny, které rozbijí některé kroky v tomto článku (což se už stalo, zatímco jsem psal, už jsem to opravil), ale celkový přístup se pravděpodobně nezmění.

O budoucnosti TON se vyjadřovat nebudu. Možná se platforma stane něčím větším a stojí za to věnovat čas jejímu studiu a prosadit se na trhu s našimi produkty už nyní.

Je zde také Libra od Facebooku, která má potenciální publikum uživatelů větší než TON. O Libře toho moc nevím, podle fóra tam je mnohem více aktivity než ve společenství TON. Ačkoli vývojáři a komunita TON se více podobají undergroundu, což je také skvělé.

Odkazy

  1. Oficiální dokumentace k TON: https://test.ton.org
  2. Oficiální repozitář TON: https://github.com/ton-blockchain/ton
  3. Oficiální peněženka pro různé platformy: https://wallet.ton.org
  4. Repozitář smart kontraktu z tohoto článku: https://github.com/raiym/astonished
  5. Odkaz na web smart kontraktu: https://ton-lottery.appspot.com
  6. Repozitář na rozšíření pro Visual Studio Code pro FunC: https://github.com/raiym/func-visual-studio-plugin
  7. Chat o TONu na Telegramu, který mi velmi pomohl se na začátku zorientovat. Myslím, že nebude chybou říct, že tam jsou všichni, kdo něco napsali pro TON. Můžete také požádat o testovací gramy. https://t.me/tondev_ru
  8. Další chat o TONu, ve kterém jsem našel užitečné informace: https://t.me/TONgramDev
  9. První etapa soutěže: https://contest.com/blockchain
  10. Druhá etapa soutěže: https://contest.com/blockchain-2

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster