Az intelligens szerződés megírásáról és közzétételéről a Telegram Open Networkben (TON)

Arról, hogyan írjunk és tegyünk közzé egy intelligens szerződést TON-ban

Miről szól ez a cikk?

A cikkben arról fogok beszélni, hogyan vettem részt az első (kettőből) Telegram blokklánc versenyen, nem nyertem el díjat, és úgy döntöttem, hogy a tapasztalataimat egy cikkben rögzítem, hogy ne merüljön feledésbe, és talán segítsen. valaki.

Mivel nem absztrakt kódot akartam írni, hanem valami működőképes dolgot, a cikkhez írtam egy okos szerződést egy azonnali lottóhoz, és egy olyan weboldalt, amely közvetlenül a TON-tól mutatja az intelligens szerződések adatait közbenső tárolás nélkül.

A cikk hasznos lesz azoknak, akik szeretnék megkötni első intelligens szerződésüket TON-ban, de nem tudják, hol kezdjék.

Példaként a lottót használva a környezet telepítésétől eljutok az okosszerződés közzétételéig, a vele való interakcióig, valamint az adatok fogadására és közzétételére szolgáló weboldal írására.

A versenyen való részvételről

Tavaly októberben a Telegram blokklánc versenyt hirdetett új nyelvekkel Fift и FunC. Választani kellett az öt javasolt okosszerződés írásából. Arra gondoltam, hogy jó lenne valami mást csinálni, nyelvet tanulni és készíteni valamit, még akkor is, ha a jövőben nem kell mást írnom. Ráadásul a téma folyamatosan a száján van.

Érdemes elmondani, hogy nem volt tapasztalatom intelligens szerződések fejlesztésében.

Terveztem, hogy a legvégéig részt veszek, amíg tudok, majd írok egy ismertető cikket, de az elsőnél rögtön megbuktam. én tárcát írt több aláírás bekapcsolásával FunC és általában működött. Ezt vettem alapul intelligens szerződés a Solidityről.

Akkoriban azt hittem, hogy ez biztosan elég ahhoz, hogy legalább egy díjat elfoglaljak. Ennek eredményeként a 40 résztvevőből körülbelül 60 nyertes lett, én pedig nem voltam köztük. Általában véve nincs ezzel semmi baj, de egy dolog zavart. Eredményhirdetéskor a szerződésem tesztjének áttekintése még nem történt meg, megkérdeztem a chaten résztvevőket, hogy van-e még akinek nem, nem volt.

Látszólag az üzeneteimre figyelve két nappal később a bírók kommentet tettek közzé, és még mindig nem értem, hogy véletlenül kihagyták-e az okos szerződésemet a zsűrizés során, vagy egyszerűen azt gondolták, hogy az olyan rossz, hogy nem kell kommentár. Feltettem egy kérdést az oldalon, de nem kaptam választ. Bár nem titok, hogy ki ítélkezett, feleslegesnek tartottam személyes üzeneteket írni.

Sok időt fordítottak a megértésre, ezért úgy döntöttek, hogy írok egy cikket. Mivel még nincs sok információ, ez a cikk minden érdeklődő számára időt takarít meg.

Az intelligens szerződések fogalma a TON-ban

Mielőtt bármit is írnál, ki kell találnod, melyik oldalról közelítsd meg ezt a dolgot. Ezért most elmondom, milyen részekből áll a rendszer. Pontosabban, hogy milyen részeket kell tudni ahhoz, hogy legalább valamilyen munkaszerződést megírhasson.

Az intelligens szerződés megírására és a vele való együttműködésre összpontosítunk TON Virtual Machine (TVM), Fift и FunC, tehát a cikk inkább egy szokásos program fejlesztésének leírása. Itt nem foglalkozunk azzal, hogy maga a platform hogyan működik.

Általánosságban a működéséről TVM és a nyelv Fift jó hivatalos dokumentáció van. A versenyen való részvétel során és most az aktuális szerződés megírása közben gyakran fordultam hozzá.

Az intelligens szerződések fő nyelve a következő FunC. Jelenleg nincs róla dokumentáció, így ahhoz, hogy valamit írhasson, tanulmányoznia kell a hivatalos adattárból származó intelligens szerződések példáit és magának a nyelvnek az ott való megvalósítását, valamint megnézheti az okos szerződések példáit az elmúlt kettőből. versenyeken. Linkek a cikk végén.

Tegyük fel, hogy már írtunk egy okos szerződést FunC, ezután Fift assemblerbe fordítjuk a kódot.

Az összeállított okosszerződést még közzé kell tenni. Ehhez be kell írni egy függvényt Fift, amely az intelligens szerződés kódját és néhány egyéb paramétert veszi be bemenetként, a kimenet pedig egy kiterjesztésű fájl lesz .boc (ami „sejtzsákot” jelent), és attól függően, hogy hogyan írjuk, egy privát kulcsot és címet, amely az intelligens szerződés kódja alapján jön létre. Egy még nem publikált okosszerződés címére már lehet grammokat küldeni.

Intelligens szerződés közzétételéhez TON-ban kapott .boc a fájlt el kell küldeni a blokkláncnak egy könnyű kliens segítségével (erről bővebben lentebb). De közzététel előtt át kell vinni a grammokat a generált címre, különben az intelligens szerződés nem kerül közzétételre. A közzététel után az intelligens szerződéssel kapcsolatba léphet úgy, hogy üzeneteket küld neki kívülről (például egy könnyű kliens segítségével) vagy belülről (például az egyik intelligens szerződés üzenetet küld a másiknak a TON-on belül).

Ha megértjük a kód közzétételének módját, könnyebbé válik. Nagyjából tudjuk, hogy mit akarunk írni, és hogyan fog működni a programunk. Írás közben pedig utánanézünk, hogy ez hogyan valósul meg már a meglévő okosszerződésekben, vagy belenézünk a megvalósítási kódba Fift и FunC a hivatalos adattárban, vagy nézd meg a hivatalos dokumentációt.

Nagyon gyakran kerestem kulcsszavakat a Telegram chaten, ahol a verseny összes résztvevője és a Telegram munkatársai összegyűltek, és úgy esett, hogy a verseny alatt mindenki ott gyűlt össze, és elkezdett beszélgetni a Fiftről és a FunC-ről. Link a cikk végén.

Ideje áttérni az elméletről a gyakorlatra.

A környezet előkészítése a TON-nal való munkavégzéshez

Mindent megtettem, amit a MacOS-ról szóló cikkben leírunk, és kétszer is ellenőriztem a tiszta Ubuntu 18.04 LTS-ben a Dockeren.

Az első dolog, amit meg kell tennie, a letöltés és telepítés lite-client amellyel kéréseket küldhet a TON-nak.

A hivatalos weboldalon található utasítások meglehetősen részletesen és egyértelműen leírják a telepítési folyamatot, és néhány részletet kihagynak. Itt követjük az utasításokat, és közben telepítjük a hiányzó függőségeket. Nem magam fordítottam le minden projektet, hanem a hivatalos Ubuntu tárolóból telepítettem (MacOS-en 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 

Miután minden függőséget telepített, telepítheti lite-client, Fift, FunC.

Először is klónozzuk a TON tárolót a függőségeivel együtt. A kényelem kedvéért mindent egy mappában fogunk csinálni ~/TON.

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

A repository implementációkat is tárol Fift и FunC.

Most készen állunk a projekt összeállítására. A tárkód egy mappába klónozva van ~/TON/ton. -Ban ~/TON hozzon létre egy mappát build és gyűjtsük össze benne a projektet.

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

Mivel okos szerződést fogunk írni, nem csak lite-clientDe Fift с FunC, szóval állítsunk össze mindent. Ez nem egy gyors folyamat, ezért várunk.

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

Ezután töltse le a konfigurációs fájlt, amely az adott csomópont adatait tartalmazza lite-client csatlakozni fog.

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

Az első kérések benyújtása TON-nak

Most pedig indítsuk el lite-client.

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

Ha a felépítés sikeres volt, akkor az indítás után megjelenik egy napló a könnyű kliens csomóponthoz való csatlakozásáról.

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

Futtathatja a parancsot help és nézze meg, milyen parancsok állnak rendelkezésre.

help

Soroljuk fel a cikkben használt parancsokat.

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

Most készen állunk a szerződés megírására.

Реализация

Ötlet

Ahogy fentebb is írtam, az okos szerződés, amit írunk, egy lottó.

Ráadásul ez nem egy lottó, amelyen jegyet kell venni, és várni kell egy órát, napot vagy hónapot, hanem egy azonnali lottó, amelyben a felhasználó átutal a szerződéses címre. N gramm, és azonnal visszakapja 2 * N gramm vagy veszít. A nyerési valószínűséget körülbelül 40%-ra tesszük. Ha nincs elég gramm a fizetéshez, akkor a tranzakciót feltöltésnek tekintjük.

Ezenkívül fontos, hogy a fogadások valós időben és kényelmes formában láthatóak legyenek, így a felhasználó azonnal megértheti, nyert-e vagy veszített. Ezért létre kell hoznia egy webhelyet, amely közvetlenül a TON-tól fogja megjeleníteni a fogadásokat és az eredményeket.

Okos szerződés írása

A kényelem kedvéért kiemeltem a FunC kódját; a bővítmény megtalálható és telepíthető a Visual Studio Code keresőjében; ha hirtelen szeretne valamit hozzáadni, nyilvánosan elérhetővé tettem a bővítményt. Valaki korábban készített egy plugint a Fift-tel való együttműködéshez, azt is telepítheti és megtalálhatja a VSC-ben.

Azonnal hozzunk létre egy adattárat, ahol rögzítjük a köztes eredményeket.

Az életünk megkönnyítése érdekében okos szerződést írunk és helyben teszteljük, amíg készen nem lesz. Csak ezután tesszük közzé a TON-ban.

Az intelligens szerződés két külső módszerrel érhető el. Első, recv_external() ez a funkció akkor hajtódik végre, ha a szerződésre irányuló kérés a külvilágból érkezik, vagyis nem a TON-tól, például amikor mi magunk generálunk egy üzenetet, és azt a lite-kliensen keresztül küldjük el. Második, recv_internal() ilyenkor magán a TON-on belül bármely szerződés a miénkre vonatkozik. Mindkét esetben átadhatunk paramétereket a függvénynek.

Kezdjük egy egyszerű példával, amely működik, ha közzétesszük, de nincs benne funkcionális terhelés.

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

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

Itt meg kell magyaráznunk, hogy mi az slice. A TON Blockchainben tárolt összes adat gyűjtemény TVM cell vagy egyszerűen cell, egy ilyen cellában legfeljebb 1023 bit adatot és legfeljebb 4 hivatkozást tárolhat más cellákra.

TVM cell slice vagy slice ez a meglévő része cell elemzésére szolgál, később kiderül. Nekünk az a fő, hogy át tudjuk adni slice és az üzenet típusától függően feldolgozza az adatokat recv_external() vagy recv_internal().

impure — egy kulcsszó, amely azt jelzi, hogy a függvény módosítja az intelligens szerződés adatait.

Mentsük el a szerződés kódját lottery-code.fc és összeállítjuk.

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

A zászlók jelentése a paranccsal tekinthető meg

~/TON/build/crypto/func -help

Összeállítottuk a Fift assembler kódot 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

Helyben indítható, erre készítjük fel a környezetet.

Vegye figyelembe, hogy az első sor csatlakozik Asm.fif, ez a Fiftben írt kód a Fift assemblerhez.

Mivel az intelligens szerződést helyben szeretnénk futtatni és tesztelni, létrehozunk egy fájlt lottery-test-suite.fif és másolja oda a lefordított kódot, cserélje le benne az utolsó sort, amely az intelligens szerződés kódját egy konstansba írja codehogy ezután vigye át a virtuális gépre:

"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

Egyelőre egyértelműnek tűnik, most ugyanahhoz a fájlhoz adjuk hozzá azt a kódot, amellyel a TVM-et elindítjuk.

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 rögzítjük a kontextust, vagyis azokat az adatokat, amelyekkel a TVM (vagy hálózati állapot) elindul. Még a verseny alatt az egyik fejlesztő megmutatta, hogyan kell alkotni c7 és másoltam. Ebben a cikkben lehet, hogy változtatnunk kell rand_seed mivel egy véletlenszám generálása attól függ, és ha nem változtatjuk meg, akkor minden alkalommal ugyanaz a szám kerül visszaadásra.

recv_internal и recv_external A 0 és -1 értékű konstansok felelősek a megfelelő függvények meghívásáért az intelligens szerződésben.

Most készen állunk az első teszt létrehozására üres intelligens szerződésünkhöz. Az egyértelműség kedvéért egyelőre az összes tesztet ugyanabba a fájlba adjuk lottery-test-suite.fif.

Hozzunk létre egy változót storage és írj bele egy üreset cell, ez lesz az intelligens szerződéses tárhely.

message Ez az az üzenet, amelyet kívülről továbbítunk az intelligens kapcsolattartónak. Egyelőre üressé is tesszük.

variable storage 
<b b> storage ! 

variable message 
<b b> message ! 

Miután elkészítettük az állandókat és a változókat, elindítjuk a TVM-et a paranccsal runvmctx és adja át a létrehozott paramétereket a bemenetnek.

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

A végén sikerülni fog itt van egy köztes kód ehhez Fift.

Most már futtathatjuk a kapott kódot.

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

A programnak hiba nélkül kell futnia, és a kimenetben látni fogjuk a végrehajtási naplót:

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

Remek, megírtuk az intelligens szerződés első működő verzióját.

Most funkcionalitást kell hozzáadnunk. Először foglalkozzunk a külvilágból érkező üzenetekkel recv_external()

A fejlesztő maga választja ki azt az üzenetformátumot, amelyet a szerződés elfogadhat.

De általában

  • egyrészt szeretnénk megvédeni a szerződésünket a külvilágtól, és úgy tenni, hogy csak a szerződés tulajdonosa küldhessen neki külső üzeneteket.
  • másodszor, amikor érvényes üzenetet küldünk a TON-nak, azt akarjuk, hogy ez pontosan egyszer történjen meg, és amikor újra elküldjük ugyanazt az üzenetet, az intelligens szerződés elutasítja azt.

Így szinte minden szerződés megoldja ezt a két problémát, hiszen a szerződésünk fogadja a külső üzeneteket, erre is ügyelnünk kell.

Fordított sorrendben tesszük. Először is oldjuk meg a problémát az ismétléssel, ha a szerződés már kapott ilyen üzenetet és feldolgozta, akkor másodszor nem hajtja végre. És akkor megoldjuk a problémát, hogy csak egy bizonyos kör tudjon üzenetet küldeni az okosszerződésnek.

Az ismétlődő üzenetekkel kapcsolatos probléma többféleképpen is megoldható. Íme, hogyan fogjuk csinálni. Az intelligens szerződésben a fogadott üzenetek számlálóját 0 kezdeti értékkel inicializáljuk. Az intelligens szerződés minden egyes üzenetében hozzáadjuk az aktuális számlálóértéket. Ha az üzenetben szereplő számláló értéke nem egyezik az intelligens szerződésben szereplő értékkel, akkor nem dolgozzuk fel, ha igen, akkor feldolgozzuk, és az intelligens szerződésben szereplő számlálót 1-gyel növeljük.

Térjünk vissza a lottery-test-suite.fif és adjunk hozzá egy második tesztet. Ha hibás számot küldünk, a kódnak kivételt kell dobnia. Például hagyja, hogy a szerződés adatai tárolják a 166-ot, és mi küldjük a 165-öt.

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

Indítsuk el.

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

És látni fogjuk, hogy a tesztet hibával hajtják végre.

[ 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

Ebben a szakaszban lottery-test-suite.fif úgy kell kinéznie по ссылке.

Most adjuk hozzá a számláló logikát az intelligens szerződéshez 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 rejlik az üzenet, amit küldünk.

Először ellenőrizzük, hogy az üzenet tartalmaz-e adatokat, ha nem, akkor egyszerűen kilépünk.

Ezután elemezzük az üzenetet. in_msg~load_uint(32) betölti a 165-ös számot, 32 bites unsigned int a továbbított üzenetből.

Ezután 32 bitet töltünk be az intelligens szerződéses tárolóból. Ellenőrizzük, hogy a betöltött szám megegyezik-e az átadott számmal, ha nem, kivételt dobunk. A mi esetünkben, mivel nem meccset passzolunk, kivételt kell tenni.

Most pedig állítsuk össze.

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

Másolja a kapott kódot ide lottery-test-suite.fif, nem felejtve el az utolsó sort kicserélni.

Ellenőrizzük a teszt sikerességét:

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

Itt van Láthatja a megfelelő véglegesítést az aktuális eredményekkel.

Megjegyzendő, hogy kényelmetlen egy intelligens szerződés lefordított kódját állandóan egy fájlba másolni tesztekkel, ezért írunk egy szkriptet, amely a kódot egy konstansba írja nekünk, és a lefordított kódot egyszerűen csatlakoztatjuk a tesztjeinkhez. "include".

Hozzon létre egy fájlt a projekt mappájában build.sh a következő tartalommal.

#!/bin/bash

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

Tegyük végrehajthatóvá.

chmod +x ./build.sh

Most csak futtassa a szkriptünket a szerződés összeállításához. De ezen kívül konstansba kell írnunk code. Tehát létrehozunk egy új fájlt lotter-compiled-for-test.fif, amelyet belefoglalunk a fájlba lottery-test-suite.fif.

Adjunk hozzá skirpt kódot az sh-hez, ami egyszerűen megkettőzi a lefordított fájlt lotter-compiled-for-test.fif és változtassa meg benne az utolsó sort.

# 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

Most az ellenőrzéshez futtassuk az eredményül kapott szkriptet, és létrejön egy fájl lottery-compiled-for-test.fif, amelyet beépítünk a mi lottery-test-suite.fif

В lottery-test-suite.fif törölje a szerződés kódját és adja hozzá a sort "lottery-compiled-for-test.fif" include.

Teszteket futtatunk annak ellenőrzésére, hogy megfelelnek-e.

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

Remek, most, hogy automatizáljuk a tesztek indítását, hozzunk létre egy fájlt test.sh, amely először végrehajtódik build.sh, majd futtassa a teszteket.

touch test.sh
chmod +x test.sh

Belül írunk

./build.sh 

echo "nCompilation completedn"

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

Meg fog tenni test.sh és futtassa, hogy megbizonyosodjon a tesztek működéséről.

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

Ellenőrizzük a szerződés összeállítását és a tesztek végrehajtását.

Remek, most indul test.sh A teszteket azonnal összeállítják és lefutják. Itt a link a elkövetni.

Rendben, mielőtt folytatnánk, tegyünk még egy dolgot a kényelem kedvéért.

Hozzunk létre egy mappát build ahol a másolt szerződést és annak konstansba írt klónját tároljuk lottery-compiled.fif, lottery-compiled-for-test.fif. Hozzunk létre egy mappát is test hol lesz tárolva a tesztfájl? lottery-test-suite.fif és potenciálisan más támogató fájlok. Link a vonatkozó változásokhoz.

Folytassuk az intelligens szerződés fejlesztését.

Ezután egy tesztnek kell lennie, amely ellenőrzi, hogy az üzenet megérkezett-e, és a számláló frissül-e az áruházban, amikor a megfelelő számot küldjük. De ezt később megtesszük.

Most gondoljuk át, milyen adatszerkezetet és milyen adatokat kell tárolni az okosszerződésben.

Leírok mindent, amit tárolunk.

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

Ezután két függvényt kell írni. Hívjuk az elsőt pack_state(), amely az intelligens szerződéses tárolóba csomagolja az adatokat későbbi mentéshez. Hívjuk a másodikat unpack_state() beolvassa és visszaadja az adatokat a tárhelyről.

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

Ezt a két funkciót hozzáadjuk az intelligens szerződés elejéhez. Majd sikerülni fog itt van egy köztes eredmény.

Az adatok mentéséhez meg kell hívnia a beépített funkciót set_data() és innen fog adatokat írni pack_state() az intelligens szerződéses tárolóban.

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

Most, hogy kényelmes funkciókkal rendelkezünk az adatok írására és olvasására, továbbléphetünk.

Ellenőriznünk kell, hogy a kívülről érkező üzenetet a szerződés tulajdonosa (vagy más, a privát kulcshoz hozzáféréssel rendelkező felhasználó) írja-e alá.

Amikor közzéteszünk egy okosszerződést, inicializálhatjuk a tárolóban szükséges adatokkal, amelyeket későbbi felhasználás céljából elmentünk. Ott rögzítjük a nyilvános kulcsot, hogy ellenőrizhessük, hogy a bejövő üzenetet a megfelelő privát kulccsal írták alá.

Mielőtt folytatnánk, hozzunk létre egy privát kulcsot, és írjuk be test/keys/owner.pk. Ehhez indítsuk el a Fiftet interaktív módban, és hajtsunk végre négy parancsot.

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

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

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

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

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

Hozzunk létre egy mappát keys a mappán belül test és oda írja be a privát kulcsot.

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

Egy fájlt látunk az aktuális mappában owner.pk.

Eltávolítjuk a nyilvános kulcsot a veremből, és szükség esetén lekérhetjük a privát kulcsból.

Most egy aláírás-ellenőrzést kell írnunk. Kezdjük a teszttel. Először a privát kulcsot olvassuk ki a fájlból a függvény segítségével file>B és írd be egy változóba owner_private_key, majd a funkció használatával priv>pub konvertálja a privát kulcsot nyilvános kulccsá, és írja be az eredményt 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 !

Mindkét kulcsra szükségünk lesz.

Az intelligens szerződéses tárolót tetszőleges adatokkal inicializáljuk a függvényben megadott sorrendben pack_state()és írd be egy változóba 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 !

Ezután írunk aláírt üzenetet, amely csak az aláírást és a számláló értéket tartalmazza.

Először elkészítjük a továbbítani kívánt adatokat, majd aláírjuk egy privát kulccsal, végül pedig létrehozunk egy aláírt üzenetet.

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 !  

Ennek eredményeként az üzenet, amelyet az intelligens szerződésnek küldünk, egy változóban rögzítésre kerül message_to_send, a funkciókról hashu, ed25519_sign_uint te tudsz olvasni az Fift dokumentációjában.

És a teszt futtatásához újra hívjuk.

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

Itt van A teszteket tartalmazó fájlnak ebben a szakaszban így kell kinéznie.

Futtassuk le a tesztet, és meghiúsul, ezért módosítjuk az intelligens szerződést, hogy az ilyen formátumú üzeneteket fogadhasson, és ellenőrizze az aláírást.

Először megszámoljuk az üzenetből származó aláírás 512 bitjét és beírjuk egy változóba, majd megszámoljuk a számlálóváltozó 32 bitjét.

Mivel van egy funkciónk az intelligens szerződéses tárolóból adatok kiolvasására, ezt fogjuk használni.

A következő lépés a tárolóval átvitt számláló ellenőrzése és az aláírás ellenőrzése. Ha valami nem egyezik, akkor kivételt dobunk a megfelelő kóddal.

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

Releváns kötelezettségvállalás itt.

Futtassuk le a teszteket, és nézzük meg, hogy a második teszt sikertelen. Két ok miatt nincs elég bit az üzenetben, és nincs elég bit a tárolóban, ezért a kód összeomlik elemzéskor. Hozzá kell adnunk egy aláírást a küldendő üzenethez, és ki kell másolnunk a tárhelyet az utolsó tesztből.

A második tesztben üzenetaláírást adunk hozzá, és megváltoztatjuk az intelligens szerződéses tárolást. Itt van a teszteket tartalmazó fájl jelenleg így néz ki.

Írjunk egy negyedik tesztet, amelyben valaki más privát kulcsával aláírt üzenetet küldünk. Hozzon létre egy másik privát kulcsot, és mentse el egy fájlba not-owner.pk. Ezzel a privát kulccsal írjuk alá az üzenetet. Futtassuk le a teszteket, és győződjön meg arról, hogy minden teszt sikeres. Elkövetni jelenleg.

Most végre továbbléphetünk az intelligens szerződési logika megvalósítására.
В recv_external() kétféle üzenetet fogadunk el.

Mivel szerződésünkben a játékosok veszteségei halmozódnak fel, ezt a pénzt a lottó készítőjének kell átutalni. A szerződés létrejöttekor a tárhelyen rögzítésre kerül a lottó készítőjének pénztárcacíme.

Minden esetre szükségünk van arra, hogy módosítsuk a címet, amelyre a vesztesek grammjait küldjük. A lottóból grammokat is tudjunk küldeni a tulajdonos címére.

Kezdjük az elsővel. Először írjunk egy tesztet, ami ellenőrzi, hogy az üzenet elküldése után az intelligens szerződés elmentette-e az új címet a tárhelyen. Felhívjuk figyelmét, hogy az üzenetben a számláló és az új cím mellett továbbítjuk action 7 bites egész szám, nem negatív szám, ettől függően választjuk ki, hogyan dolgozzuk fel az üzenetet az intelligens szerződésben.

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

A tesztben láthatja, hogyan történik a smartcontract tárolás deszerializálása storage a Fiftben. A változók deszerializálását az Fift dokumentáció írja le.

Hivatkozás véglegesítése hozzáadott tésztával.

Futtassuk le a tesztet, és győződjünk meg arról, hogy sikertelen. Most adjunk hozzá logikát a lottótulajdonos címének megváltoztatásához.

Az intelligens szerződésben folytatjuk az elemzést message, olvass bele action. Emlékeztessünk, hogy kettőnk lesz action: változtassa meg a címet és küldje el a grammokat.

Ezután elolvassuk a szerződéstulajdonos új címét, és elmentjük a tárhelyen.
Futtatjuk a teszteket, és látjuk, hogy a harmadik teszt sikertelen. Összeomlik amiatt, hogy a szerződés ezentúl 7 bitet is elemel az üzenetből, ami hiányzik a tesztből. Adjon hozzá egy nem létezőt az üzenethez action. Futtassuk le a teszteket, és nézzük meg, hogy minden megy. Itt kötelezze el magát a változások mellett. Nagy.

Most írjuk meg a logikát, hogy a megadott számú grammot elküldjük a korábban elmentett címre.

Először is írjunk egy tesztet. Két tesztet írunk, az egyiket, amikor nincs elég egyensúly, a másodikat, amikor mindennek sikeresnek kell lennie. A tesztek megtekinthetők ebben az elköteleződésben.

Most adjuk hozzá a kódot. Először írjunk két segítő módszert. Az első beszerzési módszer az intelligens szerződés aktuális egyenlegének megállapítása.

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

A második pedig egy másik okosszerződéshez való grammok küldésére szolgál. Ezt a módszert teljesen átmásoltam egy másik intelligens szerződésből.

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

Adjuk hozzá ezt a két metódust az intelligens szerződéshez, és írjuk fel a logikát. Először is elemezzük a grammok számát az üzenetből. Ezután ellenőrizzük az egyenleget, ha nem elég, kivételt dobunk. Ha minden rendben van, akkor elküldjük a grammokat a mentett címre és frissítjük a számlálót.

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

Itt van úgy néz ki, mint az intelligens szerződés jelenleg. Futtassuk le a teszteket, és győződjünk meg arról, hogy sikeresek.

Az intelligens szerződésből egyébként minden alkalommal jutalékot vonnak le egy feldolgozott üzenetért. Ahhoz, hogy az intelligens szerződéses üzenetek teljesítsék a kérést, az alapvető ellenőrzések után fel kell hívni accept_message().

Most térjünk át a belső üzenetekre. Valójában csak grammokat fogadunk el, és a dupláját küldjük vissza a játékosnak, ha nyer, és a harmadát a tulajdonosnak, ha veszít.

Először is írjunk egy egyszerű tesztet. Ehhez szükségünk van az intelligens szerződés tesztcímére, ahonnan állítólag grammokat küldünk az intelligens szerződésnek.

Az intelligens szerződés címe két számból áll, egy 32 bites egész számból, amely felelős a munkaláncért, és egy 256 bites, nem negatív egész számból álló egyedi számlaszámból ebben a munkaláncban. Például -1 és 12345, ez az a cím, amelyet fájlba mentünk.

A címmentés funkcióját innen másoltam 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

Nézzük meg, hogyan működik a függvény, ez megérti a Fift működését. Indítsa el az Fift alkalmazást interaktív módban.

~/TON/build/crypto/fift -i 

Először a -1, 12345 és a jövőbeli "sender.addr" fájl nevét helyezzük a verembe:

-1 12345 "sender.addr" 

A következő lépés a funkció végrehajtása -rot, amely oly módon tolja el a veremet, hogy a verem tetején egy egyedi intelligens szerződésszám szerepel:

"sender.addr" -1 12345

256 u>B egy 256 bites, nem negatív egész számot konvertál bájtokká.

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap felcseréli a verem felső két elemét.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

32 i>B a 32 bites egész számot bájtokká alakítja.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ két bájtsorozatot köt össze.

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

ismét swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

És végül a bájtok beírásra kerülnek a fájlba B>file. Ezt követően a veremünk üres. Megállunk Fift. Létrejött egy fájl az aktuális mappában sender.addr. Helyezzük át a fájlt a létrehozott mappába test/addresses/.

Írjunk egy egyszerű tesztet, amely grammokat küld egy intelligens szerződésre. Itt a kötelezettségvállalás.

Most nézzük a lottó logikáját.

Az első dolgunk, hogy ellenőrizzük az üzenetet bounced vagy nem ha bounced, akkor figyelmen kívül hagyjuk. bounced azt jelenti, hogy a szerződés grammokat ad vissza, ha valamilyen hiba történik. Nem adunk vissza grammokat, ha hirtelen hiba történik.

Ellenőrizzük, ha az egyenleg fél grammnál kisebb, akkor egyszerűen elfogadjuk az üzenetet és figyelmen kívül hagyjuk.

Ezután elemezzük annak az intelligens szerződésnek a címét, amelyről az üzenet érkezett.

Kiolvassuk az adatokat a tárhelyről, majd töröljük a régi fogadásokat az előzményekből, ha húsznál több van belőlük. A kényelem kedvéért három további funkciót írtam pack_order(), unpack_order(), remove_old_orders().

Ezután megnézzük, ha az egyenleg nem elegendő a fizetéshez, akkor úgy tekintjük, hogy ez nem fogadás, hanem utánpótlás, és elmentjük az utánpótlást orders.

Aztán végre az okosszerződés lényege.

Először is, ha a játékos veszít, elmentjük a fogadási előzményekben, és ha az összeg meghaladja a 3 grammot, akkor az 1/3-át elküldjük az okosszerződés tulajdonosának.

Ha a játékos nyer, akkor az összeg dupláját küldjük a játékos címére, majd elmentjük a fogadással kapcsolatos információkat a történelemben.

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

Ennyi. Megfelelő kötelezettségvállalás.

Most már csak az egyszerű, hozzunk létre get-metódusokat, hogy információkat szerezzünk a szerződés állapotáról a külvilágból (sőt, olvassuk le az adatokat az okos szerződéses tárolójukból).

Adjuk hozzá a get metódusokat. Az alábbiakban arról írunk, hogyan kaphatunk információkat az okosszerződésről.

Azt a kódot is elfelejtettem hozzáadni, amely feldolgozza a legelső kérést, amely egy intelligens szerződés közzétételekor fordul elő. Megfelelő kötelezettségvállalás. És tovább javítva hiba az összeg 1/3-ának a tulajdonos számlájára történő elküldésével.

A következő lépés az intelligens szerződés közzététele. Hozzunk létre egy mappát requests.

A publikációs kódot vettem alapul simple-wallet-code.fc который megtalálja a hivatalos adattárban.

Valami, amire érdemes odafigyelni. Intelligens szerződéstárolót és bemeneti üzenetet generálunk. Ezt követően generálódik az intelligens szerződés címe, vagyis a cím már a TON-ban való közzététel előtt ismert. Ezután több grammot kell küldenie erre a címre, és csak ezt követően kell elküldenie egy fájlt magával az intelligens szerződéssel, mivel a hálózat jutalékot vesz fel az intelligens szerződés és a benne végzett műveletek tárolásáért (ellenőrzők, akik az intelligens szerződést tárolják és végrehajtják szerződések). A kód itt megtekinthető.

Ezután végrehajtjuk a közzétételi kódot, és megkapjuk lottery-query.boc intelligens szerződés fájl és cím.

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

Ne felejtse el menteni a generált fájlokat: lottery-query.boc, lottery.addr, lottery.pk.

A végrehajtási naplókban többek között látni fogjuk az intelligens szerződés címét.

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

Csak szórakozásból tegyünk egy kérést TON-nak

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

És látni fogjuk, hogy az ezzel a címmel rendelkező fiók üres.

account state is empty

címre küldjük 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 grammot, és néhány másodperc múlva végrehajtjuk ugyanazt a parancsot. Gram küldésére használom hivatalos pénztárca, és kérhetsz valakitől a chaten tesztgrammot, amiről a cikk végén lesz szó.

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Úgy néz ki, mint egy inicializálatlan (state:account_uninit) intelligens szerződés ugyanazzal a címmel és 1 000 000 000 nanogramm egyenleggel.

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

Most pedig tegyük közzé az okosszerződést. Indítsuk el a lite-klienst és hajtsuk végre.

> 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 

Ellenőrizzük, hogy megjelent-e a szerződés.

> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Többek között kapunk.

  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

Ezt látjuk account_active.

Megfelelő kötelezettségvállalás változtatásokkal itt.

Most hozzunk létre kéréseket az intelligens szerződéssel való interakcióhoz.

Pontosabban az elsőt a címváltoztatásra hagyjuk önálló munkaként, a másodikat pedig a tulajdonosi címre történő grammküldésre. Valójában ugyanazt kell tennünk, mint a grammküldés tesztjében.

Ezt az üzenetet küldjük az okosszerződésnek, ahol msg_seqno 165, action 2 és 9.5 grammos küldésre.

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

Ne felejtse el aláírni az üzenetet privát kulcsával lottery.pk, amely korábban az intelligens szerződés létrehozásakor keletkezett. Itt van a megfelelő commit.

Intelligens szerződésből származó információk fogadása get metódusokkal

Most nézzük meg, hogyan kell futtatni az intelligens szerződésszerzési módszereket.

Dob lite-client és futtassa az általunk írt get metódusokat.

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

В result tartalmazza a függvény által visszaadott értéket balance() okos szerződésünkből.
Ugyanezt fogjuk megtenni több további módszernél is.

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

Kérjük a fogadási előzményeket.

> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_orders
...
arguments:  [ 67442 ] 
result:  [ ([0 1 1583258284 10000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [1 3 1583258347 4000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [2 1 1583259901 50000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308]) ] 

Lite-klienst használunk, és módszereket kapunk az intelligens szerződéssel kapcsolatos információk megjelenítésére a webhelyen.

Intelligens szerződéses adatok megjelenítése a weboldalon

Írtam egy egyszerű webhelyet Pythonban, hogy kényelmesen jelenítse meg az intelligens szerződés adatait. Itt nem fogok részletesen foglalkozni vele, és közzéteszem az oldalt egy commitban.

A TON-hoz intézett kérések innen származnak Python keresztül lite-client. A kényelem kedvéért a webhelyet a Docker csomagban csomagolják, és a Google Cloudon teszik közzé. Link.

Megpróbálja

Most próbáljunk meg grammokat küldeni oda utánpótlásra pénztárca. 40 grammot küldünk. És tegyünk néhány fogadást az egyértelműség kedvéért. Látjuk, hogy az oldalon a fogadások előzményei, az aktuális nyerési százalék és egyéb hasznos információk láthatók.

Látjukhogy az elsőt megnyertük, a másodikat elveszítettük.

utószó

A cikk sokkal hosszabbnak bizonyult, mint amire számítottam, talán rövidebb is lehetett volna, vagy talán csak egy olyan személy számára, aki semmit sem tud a TON-ról, és szeretne egy nem túl egyszerű intelligens szerződést írni és közzétenni, és képes lenne kapcsolatba lépni azt. Talán néhány dolgot egyszerűbben is meg lehetett volna magyarázni.

Talán a megvalósítás egyes aspektusait hatékonyabban és elegánsabban is meg lehetett volna csinálni, de akkor még több időbe telt volna a cikk elkészítése. Az is lehet, hogy valahol hibáztam, vagy valamit nem értettem, ezért ha valami komoly dolgot csinál, akkor a hivatalos dokumentációra vagy a TON kóddal ellátott hivatalos adattárra kell hagyatkoznia.

Megjegyzendő, hogy mivel maga a TON még a fejlesztés aktív szakaszában van, előfordulhatnak olyan változások, amelyek megszakítják a cikkben szereplő bármely lépést (ami az írás során történt, már javítva lett), de az általános megközelítés nem valószínű, hogy megváltozik.

Nem beszélek a TON jövőjéről. Talán a platform valami nagy lesz, és érdemes időt szánnunk a tanulmányozására, és most egy rést kell betöltenünk termékeinkkel.

A Facebookról is van Libra, amelynek potenciális felhasználói közönsége nagyobb, mint TON. A Mérlegről szinte semmit nem tudok, a fórumból ítélve ott sokkal nagyobb az aktivitás, mint a TON közösségben. Bár a TON fejlesztői és közössége inkább underground, ami szintén menő.

referenciák

  1. Hivatalos TON dokumentáció: https://test.ton.org
  2. Hivatalos TON adattár: https://github.com/ton-blockchain/ton
  3. Hivatalos pénztárca különböző platformokhoz: https://wallet.ton.org
  4. Intelligens szerződéstár ebből a cikkből: https://github.com/raiym/astonished
  5. Link az intelligens szerződés weboldalához: https://ton-lottery.appspot.com
  6. A Visual Studio Code for FunC kiterjesztésének tárháza: https://github.com/raiym/func-visual-studio-plugin
  7. Csevegés a TON-ról a Telegramban, ami valóban segített a kezdeti szakaszban kitalálni. Szerintem nem lesz hiba, ha azt mondom, hogy mindenki ott van, aki írt valamit a TON-nak. Ott is kérhetsz tesztgrammot. https://t.me/tondev_ru
  8. Egy másik beszélgetés a TON-ról, amelyben hasznos információkat találtam: https://t.me/TONgramDev
  9. A verseny első szakasza: https://contest.com/blockchain
  10. A verseny második szakasza: https://contest.com/blockchain-2

Forrás: will.com

Hozzászólás