Om hvordan man skriver og udgiver en smart kontrakt i Telegram Open Network (TON)

Om hvordan man skriver og udgiver en smart kontrakt i TON

Hvad handler denne artikel om?

I artiklen vil jeg tale om, hvordan jeg deltog i den første (af to) Telegram blockchain-konkurrence, ikke tog en præmie og besluttede at optage min oplevelse i en artikel, så den ikke synker i glemmebogen og måske hjælpe nogen.

Da jeg ikke ønskede at skrive abstrakt kode, men at gøre noget, der fungerede, skrev jeg til artiklen en smart kontrakt for et øjeblikkeligt lotteri og en hjemmeside, der viser smart kontraktdata direkte fra TON uden at bruge mellemlagring.

Artiklen vil være nyttig for dem, der ønsker at lave deres første smarte kontrakt i TON, men ikke ved, hvor de skal starte.

Med lotteriet som eksempel vil jeg gå fra at installere miljøet til at udgive en smart kontrakt, interagere med den og skrive en hjemmeside til modtagelse og publicering af data.

Om deltagelse i konkurrencen

I oktober sidste år annoncerede Telegram en blockchain-konkurrence med nye sprog Fift и FunC. Det var nødvendigt at vælge mellem at skrive en af ​​de fem foreslåede smarte kontrakter. Jeg tænkte, at det ville være rart at lave noget anderledes, lære et sprog og lave noget, selvom jeg ikke skal skrive andet i fremtiden. Desuden er emnet konstant på læberne.

Det er værd at sige, at jeg ikke havde nogen erfaring med at udvikle smarte kontrakter.

Jeg planlagde at deltage til det sidste, indtil jeg kunne, og så skrive en anmeldelsesartikel, men jeg fejlede med det samme ved den første. jeg skrev en tegnebog med multisignatur på FunC og det virkede generelt. Jeg tog det som grundlag smart kontrakt om soliditet.

På det tidspunkt tænkte jeg, at dette helt sikkert var nok til i det mindste at vinde en præmieplads. Som følge heraf blev omkring 40 ud af 60 deltagere præmievindere, og jeg var ikke blandt dem. Generelt er der ikke noget galt med dette, men én ting generede mig. På tidspunktet for offentliggørelsen af ​​resultaterne var gennemgangen af ​​testen for min kontrakt ikke foretaget, jeg spurgte deltagerne i chatten, om der var andre, der ikke havde det, der var ingen.

Tilsyneladende var jeg opmærksom på mine beskeder, to dage senere offentliggjorde dommerne en kommentar, og jeg forstår stadig ikke, om de ved et uheld gik glip af min smarte kontrakt under bedømmelsen eller blot troede, at det var så slemt, at det ikke behøvede en kommentar. Jeg stillede et spørgsmål på siden, men fik ikke svar. Selvom det ikke er nogen hemmelighed, hvem der dømte, fandt jeg det unødvendigt at skrive personlige beskeder.

Der blev brugt meget tid på forståelse, så det blev besluttet at skrive en artikel. Da der ikke er meget information endnu, vil denne artikel hjælpe med at spare tid for alle interesserede.

Konceptet med smarte kontrakter i TON

Før du skriver noget, skal du finde ud af, hvilken side du skal nærme dig denne ting fra. Derfor vil jeg nu fortælle dig, hvilke dele systemet består af. Mere præcist, hvilke dele du skal vide for at skrive i det mindste en form for arbejdskontrakt.

Vi vil fokusere på at skrive en smart kontrakt og arbejde med TON Virtual Machine (TVM), Fift и FunC, så artiklen er mere som en beskrivelse af udviklingen af ​​et almindeligt program. Vi vil ikke dvæle ved, hvordan selve platformen fungerer her.

Generelt om hvordan det fungerer TVM og sprog Fift der er god officiel dokumentation. Mens jeg deltog i konkurrencen og nu mens jeg skrev den nuværende kontrakt, henvendte jeg mig ofte til hende.

Hovedsproget, som smarte kontrakter er skrevet på, er FunC. Der er ingen dokumentation på det i øjeblikket, så for at skrive noget skal du studere eksempler på smarte kontrakter fra det officielle arkiv og implementeringen af ​​selve sproget der, plus du kan se på eksempler på smarte kontrakter fra de sidste to konkurrencer. Links i slutningen af ​​artiklen.

Lad os sige, at vi allerede har skrevet en smart kontrakt for FunC, derefter kompilerer vi koden i Fift assembler.

Den kompilerede smarte kontrakt mangler at blive offentliggjort. For at gøre dette skal du skrive en funktion i Fift, som vil tage den smarte kontraktkode og nogle andre parametre som input, og outputtet vil være en fil med udvidelsen .boc (som betyder "pose med celler"), og, afhængigt af hvordan vi skriver det, en privat nøgle og adresse, som genereres baseret på den smarte kontraktkode. Du kan allerede sende gram til adressen på en smart kontrakt, der endnu ikke er offentliggjort.

For at offentliggøre en smart kontrakt i TON modtaget .boc filen skal sendes til blockchain ved hjælp af en let klient (mere om det nedenfor). Men før udgivelsen skal du overføre gram til den genererede adresse, ellers vil den smarte kontrakt ikke blive offentliggjort. Efter offentliggørelsen kan du interagere med den smarte kontrakt ved at sende den beskeder udefra (for eksempel ved hjælp af en lysklient) eller indefra (f.eks. sender en smart kontrakt en anden en besked inde i TON).

Når vi først forstår, hvordan koden udgives, bliver det nemmere. Vi ved nogenlunde, hvad vi vil skrive, og hvordan vores program vil fungere. Og mens vi skriver, kigger vi efter, hvordan dette allerede er implementeret i eksisterende smarte kontrakter, eller vi kigger på implementeringskoden Fift и FunC i det officielle arkiv, eller se i den officielle dokumentation.

Meget ofte søgte jeg på nøgleord i Telegram-chatten, hvor alle konkurrencedeltagere og Telegram-medarbejdere var samlet, og det skete, at under konkurrencen samledes alle der og begyndte at diskutere Fift og FunC. Link i slutningen af ​​artiklen.

Det er tid til at gå fra teori til praksis.

Forberedelse af miljøet til at arbejde med TON

Jeg gjorde alt, hvad der vil blive beskrevet i artiklen om MacOS og dobbelttjekkede det i ren Ubuntu 18.04 LTS på Docker.

Den første ting du skal gøre er at downloade og installere lite-client hvormed du kan sende anmodninger til TON.

Instruktionerne på den officielle hjemmeside beskriver installationsprocessen ret detaljeret og tydeligt og udelader nogle detaljer. Her følger vi instruktionerne og installerer de manglende afhængigheder undervejs. Jeg kompilerede ikke hvert projekt selv og installerede fra det officielle Ubuntu-depot (på MacOS jeg brugte 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 

Når alle afhængigheder er installeret, kan du installere lite-client, Fift, FunC.

Først kloner vi TON-lageret sammen med dets afhængigheder. For nemheds skyld vil vi gøre alt i en mappe ~/TON.

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

Depotet gemmer også implementeringer Fift и FunC.

Nu er vi klar til at samle projektet. Depotkoden klones ind i en mappe ~/TON/ton. I ~/TON oprette en mappe build og samle projektet i det.

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

Da vi skal skrive en smart kontrakt, behøver vi ikke kun lite-clientMen Fift с FunC, så lad os kompilere alt. Det er ikke en hurtig proces, så vi venter.

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

Download derefter konfigurationsfilen, som indeholder data om den node, hvortil lite-client vil forbinde.

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

Fremsætter de første anmodninger til TON

Lad os nu starte lite-client.

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

Hvis opbygningen lykkedes, vil du efter lanceringen se en log over lysklientens forbindelse til noden.

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

Du kan køre kommandoen help og se hvilke kommandoer der er tilgængelige.

help

Lad os liste de kommandoer, som vi vil bruge i denne artikel.

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

Nu er vi klar til at skrive selve kontrakten.

implementering

Idea

Som jeg skrev ovenfor, er den smarte kontrakt, som vi skriver, et lotteri.

Desuden er dette ikke et lotteri, hvor du skal købe en billet og vente en time, dag eller måned, men et øjeblikkeligt et, hvor brugeren overfører til kontraktadressen N gram, og får det med det samme tilbage 2 * N gram eller taber. Vi vil gøre sandsynligheden for at vinde omkring 40 %. Hvis der ikke er gram nok til betaling, så vil vi betragte transaktionen som en top-up.

Desuden er det vigtigt, at væddemålene kan ses i realtid og i en bekvem form, så brugeren med det samme kan forstå, om han vandt eller tabte. Derfor skal du lave en hjemmeside, der vil vise indsatser og resultater direkte fra TON.

At skrive en smart kontrakt

For nemheds skyld har jeg fremhævet koden til FunC; plugin'et kan findes og installeres i Visual Studio Code-søgningen; hvis du pludselig vil tilføje noget, har jeg gjort plugin'et offentligt tilgængeligt. Også nogen tidligere lavet et plugin til at arbejde med Fift, du kan også installere det og finde det i VSC.

Lad os straks oprette et lager, hvor vi vil forpligte de mellemliggende resultater.

For at gøre vores liv lettere, skriver vi en smart kontrakt og tester den lokalt, indtil den er klar. Først derefter offentliggør vi den i TON.

Den smarte kontrakt har to eksterne metoder, der kan tilgås. Først, recv_external() denne funktion udføres, når en forespørgsel til kontrakten kommer fra omverdenen, det vil sige ikke fra f.eks. TON, når vi selv genererer en besked og sender den gennem lite-klienten. Anden, recv_internal() det er når, inden for TON selv, enhver kontrakt refererer til vores. I begge tilfælde kan du overføre parametre til funktionen.

Lad os starte med et simpelt eksempel, der fungerer, hvis det udgives, men der er ingen funktionel belastning i det.

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

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

Her skal vi forklare, hvad det er slice. Alle data gemt i TON Blockchain er en samling TVM cell eller bare cell, i en sådan celle kan du gemme op til 1023 bit data og op til 4 links til andre celler.

TVM cell slice eller slice dette er en del af den eksisterende cell bruges til at parse det, vil det blive klart senere. Det vigtigste for os er, at vi kan overføre slice og afhængigt af typen af ​​meddelelse, behandle dataene i recv_external() eller recv_internal().

impure — et nøgleord, der angiver, at funktionen ændrer smart kontraktdata.

Lad os gemme kontraktkoden ind lottery-code.fc og kompiler.

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

Betydningen af ​​flagene kan ses ved hjælp af kommandoen

~/TON/build/crypto/func -help

Vi har kompileret Fift assembler-kode i 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

Det kan lanceres lokalt, til dette vil vi forberede miljøet.

Bemærk, at den første linje forbinder Asm.fif, dette er kode skrevet i Fift for Fift assembler.

Da vi ønsker at køre og teste den smarte kontrakt lokalt, vil vi oprette en fil lottery-test-suite.fif og kopier den kompilerede kode dertil, og erstatter den sidste linje i den, som skriver den smarte kontraktkode til en konstant codefor derefter at overføre det til den virtuelle maskine:

"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

Indtil videre virker det klart, lad os nu tilføje koden til den samme fil, som vi vil bruge til at starte TVM.

0 tuple 0x076ef1ea , // magic
0 , 0 , // actions msg_sents
1570998536 , // unix_time
1 , 1 , 3 , // block_lt, trans_lt, rand_seed
0 tuple 100000000000000 , dictnew , , // remaining balance
0 , dictnew , // contract_address, global_config
1 tuple // wrap to another tuple
constant c7

0 constant recv_internal // to run recv_internal() 
-1 constant recv_external // to invoke recv_external()

В c7 vi registrerer konteksten, det vil sige de data, som TVM'en (eller netværkstilstanden) vil blive lanceret med. Selv under konkurrencen viste en af ​​udviklerne, hvordan man skaber c7 og jeg kopierede. I denne artikel skal vi muligvis ændre rand_seed da genereringen af ​​et tilfældigt tal afhænger af det, og hvis det ikke ændres, vil det samme tal blive returneret hver gang.

recv_internal и recv_external konstanter med værdierne 0 og -1 vil være ansvarlige for at kalde de tilsvarende funktioner i den smarte kontrakt.

Nu er vi klar til at lave den første test for vores tomme smarte kontrakt. For klarhedens skyld vil vi indtil videre tilføje alle test til den samme fil lottery-test-suite.fif.

Lad os oprette en variabel storage og skriv en tom en ind i den cell, vil dette være den smarte kontraktopbevaring.

message Dette er budskabet, som vi vil overføre til den smarte kontakt udefra. Vi vil også gøre det tomt indtil videre.

variable storage 
<b b> storage ! 

variable message 
<b b> message ! 

Efter at vi har forberedt konstanterne og variablerne, starter vi TVM ved hjælp af kommandoen runvmctx og videregive de oprettede parametre til input.

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

I sidste ende vil vi lykkes sådan her mellemkode for Fift.

Nu kan vi køre den resulterende kode.

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

Programmet skal køre uden fejl, og i outputtet vil vi se udførelsesloggen:

execute SETCP 0
execute DICTPUSHCONST 19 (xC_,1)
execute DICTIGETJMPZ
execute DROP
execute implicit RET
[ 3][t 0][1582281699.325381279][vm.cpp:479]     steps: 5 gas: used=304, max=9223372036854775807, limit=9223372036854775807, credit=0

Super, vi har skrevet den første fungerende version af den smarte kontrakt.

Nu skal vi tilføje funktionalitet. Lad os først beskæftige os med beskeder, der kommer fra omverdenen til recv_external()

Bygherren vælger selv det meddelelsesformat, som kontrakten kan acceptere.

Men normalt

  • for det første ønsker vi at beskytte vores kontrakt mod omverdenen og gøre det sådan, at det kun er ejeren af ​​kontrakten, der kan sende eksterne beskeder til den.
  • for det andet, når vi sender en gyldig besked til TON, ønsker vi, at dette sker præcis én gang, og når vi sender den samme besked igen, afviser den smarte kontrakt det.

Så næsten hver kontrakt løser disse to problemer, da vores kontrakt accepterer eksterne beskeder, skal vi også tage os af det.

Vi gør det i omvendt rækkefølge. Lad os først løse problemet med gentagelse; hvis kontrakten allerede har modtaget en sådan besked og behandlet den, vil den ikke udføre den en anden gang. Og så løser vi problemet, så kun en bestemt kreds af mennesker kan sende beskeder til den smarte kontrakt.

Der er forskellige måder at løse problemet med duplikerede meddelelser. Sådan gør vi det. I den smarte kontrakt initialiserer vi tælleren for modtagne beskeder med startværdien 0. I hver besked til den smarte kontrakt tilføjer vi den aktuelle tællerværdi. Hvis tællerværdien i meddelelsen ikke svarer til værdien i den smarte kontrakt, så behandler vi den ikke; hvis den gør det, så behandler vi den og øger tælleren i den smarte kontrakt med 1.

Lad os vende tilbage til lottery-test-suite.fif og tilføje en anden test til det. Hvis vi sender et forkert nummer, bør koden give en undtagelse. Lad for eksempel kontraktdata gemme 166, så sender vi 165.

<b 166 32 u, b> storage !
<b 165 32 u, b> message !

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx

drop 
exit_code ! 
."Exit code " exit_code @ . cr 
exit_code @ 33 - abort"Test #2 Not passed"

Lad os starte.

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

Og vi vil se, at testen udføres med en fejl.

[ 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

På dette stadium lottery-test-suite.fif skal se ud по ссылке.

Lad os nu tilføje modlogikken til den smarte kontrakt i 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 ligger det budskab, vi sender.

Det første vi gør er at tjekke om beskeden indeholder data, hvis ikke, så afslutter vi simpelthen.

Dernæst analyserer vi beskeden. in_msg~load_uint(32) indlæser tallet 165, 32-bit unsigned int fra den sendte besked.

Dernæst indlæser vi 32 bits fra det smarte kontraktlager. Vi tjekker, at det indlæste nummer matcher det beståede; hvis ikke, kaster vi en undtagelse. I vores tilfælde, da vi passerer en ikke-kamp, ​​bør der kastes en undtagelse.

Lad os nu kompilere.

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

Kopier den resulterende kode til lottery-test-suite.fif, ikke at glemme at erstatte den sidste linje.

Vi kontrollerer, at testen består:

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

Lige her Du kan se den tilsvarende commit med de aktuelle resultater.

Bemærk, at det er ubelejligt konstant at kopiere den kompilerede kode af en smart kontrakt ind i en fil med test, så vi skriver et script, der vil skrive koden til en konstant for os, og vi forbinder blot den kompilerede kode til vores tests vha. "include".

Opret en fil i projektmappen build.sh med følgende indhold.

#!/bin/bash

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

Lad os gøre det eksekverbart.

chmod +x ./build.sh

Nu skal du bare køre vores script for at kompilere kontrakten. Men udover dette er vi nødt til at skrive det ind i en konstant code. Så vi vil oprette en ny fil lotter-compiled-for-test.fif, som vi vil inkludere i filen lottery-test-suite.fif.

Lad os tilføje skirpt-kode til sh, som blot vil duplikere den kompilerede fil ind lotter-compiled-for-test.fif og ændre den sidste linje i den.

# 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

Nu, for at kontrollere, lad os køre det resulterende script, og en fil vil blive genereret lottery-compiled-for-test.fif, som vi vil tage med i vores lottery-test-suite.fif

В lottery-test-suite.fif slet kontraktkoden og tilføj linjen "lottery-compiled-for-test.fif" include.

Vi kører test for at kontrollere, at de består.

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

Godt, lad os nu oprette en fil for at automatisere lanceringen af ​​tests test.sh, som først udføres build.sh, og kør derefter testene.

touch test.sh
chmod +x test.sh

Vi skriver indenfor

./build.sh 

echo "nCompilation completedn"

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

Lad os gøre det test.sh og kør det for at sikre, at testene virker.

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

Vi kontrollerer, at kontrakten kompilerer, og testene er udført.

Super, nu ved opstart test.sh Testene vil blive kompileret og kørt med det samme. Her er linket til begå.

Okay, før vi fortsætter, lad os gøre en ting mere for nemheds skyld.

Lad os oprette en mappe build hvor vi vil gemme den kopierede kontrakt og dens klon skrevet i en konstant lottery-compiled.fif, lottery-compiled-for-test.fif. Lad os også oprette en mappe test hvor vil testfilen blive gemt? lottery-test-suite.fif og potentielt andre understøttende filer. Link til relevante ændringer.

Lad os fortsætte med at udvikle den smarte kontrakt.

Dernæst skulle der være en test der tjekker at beskeden er modtaget og tælleren er opdateret i butikken når vi sender det rigtige nummer. Men det gør vi senere.

Lad os nu tænke over, hvilken datastruktur og hvilke data der skal gemmes i den smarte kontrakt.

Jeg vil beskrive alt, hvad vi gemmer.

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

Dernæst skal du skrive to funktioner. Lad os ringe til den første pack_state(), som vil pakke dataene til efterfølgende lagring i det smarte kontraktlager. Lad os kalde den anden unpack_state() vil læse og returnere data fra lageret.

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

Vi tilføjer disse to funktioner til begyndelsen af ​​den smarte kontrakt. Det vil nok gå sådan her mellemresultat.

For at gemme data skal du kalde den indbyggede funktion set_data() og den vil skrive data fra pack_state() i det smarte kontraktlager.

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

Nu hvor vi har praktiske funktioner til at skrive og læse data, kan vi komme videre.

Vi skal kontrollere, at den besked, der kommer udefra, er underskrevet af ejeren af ​​kontrakten (eller en anden bruger, der har adgang til den private nøgle).

Når vi udgiver en smart kontrakt, kan vi initialisere den med de data, vi har brug for på lager, som vil blive gemt til fremtidig brug. Vi vil optage den offentlige nøgle der, så vi kan bekræfte, at den indgående besked blev signeret med den tilsvarende private nøgle.

Inden vi fortsætter, lad os oprette en privat nøgle og skrive den til test/keys/owner.pk. For at gøre dette, lad os starte Fift i interaktiv tilstand og udføre fire kommandoer.

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

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

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

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

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

Lad os oprette en mappe keys inde i mappen test og skriv den private nøgle der.

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

Vi ser en fil i den aktuelle mappe owner.pk.

Vi fjerner den offentlige nøgle fra stakken, og når det er nødvendigt kan vi hente den fra den private.

Nu skal vi skrive en signaturbekræftelse. Lad os starte med testen. Først læser vi den private nøgle fra filen ved hjælp af funktionen file>B og skriv det til en variabel owner_private_key, og derefter bruge funktionen priv>pub konverter den private nøgle til en offentlig nøgle og skriv resultatet ind 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 !

Vi skal bruge begge nøgler.

Vi initialiserer det smarte kontraktlager med vilkårlige data i samme rækkefølge som i funktionen pack_state()og skriv det ind i en variabel 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 !

Dernæst vil vi komponere en underskrevet besked, den vil kun indeholde signaturen og tællerværdien.

Først opretter vi de data, vi ønsker at overføre, derefter underskriver vi dem med en privat nøgle og til sidst genererer vi en underskrevet besked.

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 !  

Som et resultat bliver beskeden, som vi sender til den smarte kontrakt, registreret i en variabel message_to_send, om funktioner hashu, ed25519_sign_uint du kan læse i Fift-dokumentationen.

Og for at køre testen ringer vi igen.

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

Her så Filen med test skal se sådan ud på dette tidspunkt.

Lad os køre testen, og den mislykkes, så vi ændrer den smarte kontrakt, så den kan modtage beskeder i dette format og bekræfte signaturen.

Først tæller vi 512 bits af signaturen fra beskeden og skriver den til en variabel, derefter tæller vi 32 bits af tællervariablen.

Da vi har en funktion til at læse data fra det smarte kontraktlager, vil vi bruge det.

Det næste er at tjekke tælleren, der er overført med lageret, og kontrollere signaturen. Hvis noget ikke matcher, så smider vi en undtagelse med den passende kode.

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

Relevant forpligtelse her.

Lad os køre testene og se, at den anden test mislykkes. Af to årsager er der ikke nok bits i beskeden, og der er ikke nok bits i lageret, så koden går ned ved parsing. Vi skal tilføje en signatur til den besked, vi sender, og kopiere lageret fra den sidste test.

I den anden test vil vi tilføje en beskedsignatur og ændre den smarte kontraktlagring. Her så filen med test ser ud i øjeblikket.

Lad os skrive en fjerde test, hvor vi sender en besked underskrevet med en andens private nøgle. Lad os oprette en anden privat nøgle og gemme den i en fil not-owner.pk. Vi underskriver beskeden med denne private nøgle. Lad os køre testene og sikre os, at alle prøver består. Begå i dette øjeblik.

Nu kan vi endelig gå videre til implementeringen af ​​den smarte kontraktlogik.
В recv_external() vi accepterer to typer beskeder.

Da vores kontrakt vil akkumulere spillernes tab, skal disse penge overføres til skaberen af ​​lotteriet. Tegnebogsadressen på lotteriopretteren registreres i lageret, når kontrakten oprettes.

For en sikkerheds skyld har vi brug for muligheden for at ændre adressen, som vi sender gram af taberne til. Vi burde også kunne sende gram fra lotteriet til ejerens adresse.

Lad os starte med den første. Lad os først skrive en test, der vil kontrollere, at efter at have sendt beskeden, gemte den smarte kontrakt den nye adresse i lageret. Bemærk venligst, at vi i beskeden udover skranken og den nye adresse også sender action Et 7-bit heltal ikke-negativt tal, afhængigt af det, vil vi vælge, hvordan vi behandler beskeden i den smarte kontrakt.

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

I testen kan du se, hvordan smartcontract storage er deserialiseret storage i Femte. Deserialisering af variable er beskrevet i Fift-dokumentationen.

Forpligtelse link med tilsat dej.

Lad os køre testen og sikre os, at den mislykkes. Lad os nu tilføje logik for at ændre adressen på lotteriets ejer.

I den smarte kontrakt fortsætter vi med at parse message, læs ind action. Lad os minde dig om, at vi får to action: skift adresse og send gram.

Så læser vi den nye adresse på kontraktejeren og gemmer den på lager.
Vi kører testene og ser, at den tredje test mislykkes. Det går ned på grund af, at kontrakten nu yderligere parser 7 bits fra beskeden, som mangler i testen. Tilføj en ikke-eksisterende til beskeden action. Lad os køre testene og se, at alt består. Her forpligte sig til ændringer. Store.

Lad os nu skrive logikken for at sende det angivne antal gram til den tidligere gemte adresse.

Lad os først skrive en test. Vi skriver to tests, den ene når der ikke er balance nok, den anden når alt skal bestå. Tests kan ses i denne forpligtelse.

Lad os nu tilføje koden. Lad os først skrive to hjælpemetoder. Den første get-metode er at finde ud af den aktuelle saldo af en smart kontrakt.

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

Og den anden er til at sende gram til en anden smart kontrakt. Jeg kopierede fuldstændig denne metode fra en anden smart kontrakt.

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

Lad os tilføje disse to metoder til den smarte kontrakt og skrive logikken. Først analyserer vi antallet af gram fra beskeden. Dernæst tjekker vi saldoen, hvis det ikke er nok, kaster vi en undtagelse. Hvis alt er i orden, så sender vi grammene til den gemte adresse og opdaterer tælleren.

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

Her så ligner den smarte kontrakt i øjeblikket. Lad os køre testene og sikre os, at de består.

Der trækkes i øvrigt en kommission fra den smarte kontrakt hver gang for en behandlet besked. For at de smarte kontraktmeddelelser kan udføre anmodningen, skal du efter grundlæggende kontrol ringe accept_message().

Lad os nu gå videre til interne beskeder. Faktisk accepterer vi kun gram og sender det dobbelte beløb tilbage til spilleren, hvis han vinder, og en tredjedel til ejeren, hvis han taber.

Lad os først skrive en simpel test. For at gøre dette har vi brug for en testadresse på den smarte kontrakt, hvorfra vi angiveligt sender gram til den smarte kontrakt.

Den smarte kontraktadresse består af to tal, et 32-bit heltal, der er ansvarligt for arbejdskæden, og et 256-bit ikke-negativt heltals unikt kontonummer i denne arbejdskæde. For eksempel -1 og 12345, dette er adressen vi gemmer i en fil.

Jeg kopierede funktionen til at gemme adressen fra 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

Lad os se på hvordan funktionen virker, dette vil give en forståelse af hvordan Fift virker. Start Fift i interaktiv tilstand.

~/TON/build/crypto/fift -i 

Først skubber vi -1, 12345 og navnet på den fremtidige fil "sender.addr" på stakken:

-1 12345 "sender.addr" 

Det næste trin er at udføre funktionen -rot, som flytter stakken på en sådan måde, at der øverst i stakken er et unikt smart kontraktnummer:

"sender.addr" -1 12345

256 u>B konverterer et 256-bit ikke-negativt heltal til bytes.

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap udskifter de to øverste elementer i stakken.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

32 i>B konverterer et 32-bit heltal til bytes.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ forbinder to sekvenser af bytes.

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

igen swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

Og til sidst skrives bytes til filen B>file. Herefter er vores stak tom. Vi stopper Fift. Der er oprettet en fil i den aktuelle mappe sender.addr. Lad os flytte filen til den oprettede mappe test/addresses/.

Lad os skrive en simpel test, der sender gram til en smart kontrakt. Her er forpligtelsen.

Lad os nu se på lotteriets logik.

Det første vi gør er at tjekke beskeden bounced eller ej hvis bounced, så ignorerer vi det. bounced betyder, at kontrakten vil returnere gram, hvis der opstår en fejl. Vi returnerer ikke gram, hvis der pludselig opstår en fejl.

Vi tjekker, hvis saldoen er mindre end et halvt gram, så accepterer vi blot beskeden og ignorerer den.

Derefter analyserer vi adressen på den smarte kontrakt, hvorfra beskeden kom.

Vi læser dataene fra lageret og sletter derefter gamle væddemål fra historien, hvis der er mere end tyve af dem. For nemheds skyld skrev jeg tre yderligere funktioner pack_order(), unpack_order(), remove_old_orders().

Dernæst ser vi om saldoen ikke rækker til betalingen, så vurderer vi, at dette ikke er et væddemål, men en genopfyldning og gemmer genopfyldningen i orders.

Så endelig essensen af ​​den smarte kontrakt.

Først, hvis spilleren taber, gemmer vi det i væddemålshistorikken, og hvis beløbet er mere end 3 gram, sender vi 1/3 til ejeren af ​​den smarte kontrakt.

Hvis spilleren vinder, sender vi det dobbelte beløb til spillerens adresse og gemmer derefter oplysningerne om indsatsen i historien.

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

Det er det. Tilsvarende forpligtelse.

Nu er alt, der er tilbage, simpelt, lad os skabe get-metoder, så vi kan få information om kontraktens tilstand fra omverdenen (faktisk læs dataene fra deres smarte kontraktlager).

Lad os tilføje get-metoder. Vi vil nedenfor skrive om, hvordan du modtager information om en smart kontrakt.

Jeg glemte også at tilføje koden, der vil behandle den allerførste anmodning, der opstår, når du udgiver en smart kontrakt. Tilsvarende forpligtelse. Og videre rettet fejl med at sende 1/3 af beløbet til ejerens konto.

Næste skridt er at offentliggøre den smarte kontrakt. Lad os oprette en mappe requests.

Jeg tog udgivelseskoden som grundlag simple-wallet-code.fc hvilken kan findes i det officielle depot.

Noget der er værd at være opmærksom på. Vi genererer en smart kontraktlagring og en inputbesked. Herefter genereres adressen på den smarte kontrakt, det vil sige, at adressen er kendt allerede før offentliggørelse i TON. Så skal du sende flere gram til denne adresse, og først derefter skal du sende en fil med selve den smarte kontrakt, da netværket tager en provision for lagring af den smarte kontrakt og operationer i den (validatorer, der gemmer og udfører smarte kontrakter ). Koden kan ses her.

Dernæst eksekverer vi udgivelseskoden og får lottery-query.boc smart kontraktfil og adresse.

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

Glem ikke at gemme de genererede filer: lottery-query.boc, lottery.addr, lottery.pk.

Vi vil blandt andet se adressen på den smarte kontrakt i udførelsesloggene.

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

Bare for sjov, lad os sende en anmodning til TON

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

Og vi vil se, at kontoen med denne adresse er tom.

account state is empty

Vi sender til adressen 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 gram og efter et par sekunder udfører vi den samme kommando. At sende gram bruger jeg officiel pung, og du kan bede en fra chatten om testgram, som jeg vil tale om sidst i artiklen.

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Det ligner en uinitialiseret (state:account_uninit) en smart kontrakt med samme adresse og en saldo på 1 nanogram.

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

Lad os nu offentliggøre den smarte kontrakt. Lad os starte lite-klient og køre.

> 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 

Lad os tjekke, at kontrakten er offentliggjort.

> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Vi får bl.a.

  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

Det ser vi account_active.

Tilsvarende commit med ændringer her.

Lad os nu oprette anmodninger om at interagere med den smarte kontrakt.

Mere præcist vil vi forlade den første til at ændre adressen som et selvstændigt værk, og vi vil gøre den anden til at sende gram til ejerens adresse. Faktisk bliver vi nødt til at gøre det samme som i testen for at sende gram.

Dette er den besked, vi sender til den smarte kontrakt, hvor msg_seqno 165, action 2 og 9.5 gram til afsendelse.

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

Glem ikke at underskrive beskeden med din private nøgle lottery.pk, som blev genereret tidligere ved oprettelse af den smarte kontrakt. Her er den tilsvarende forpligtelse.

Modtagelse af information fra en smart kontrakt ved hjælp af get-metoder

Lad os nu se på, hvordan man kører smart contract get-metoder.

Lad os starte lite-client og kør de get-metoder, som vi skrev.

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

В result indeholder den værdi, som funktionen returnerer balance() fra vores smarte kontrakt.
Vi vil gøre det samme for flere flere metoder.

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

Lad os bede om din indsatshistorik.

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

Vi vil bruge lite-klient og få metoder til at vise information om den smarte kontrakt på siden.

Visning af smart kontraktdata på hjemmesiden

Jeg skrev en simpel hjemmeside i Python for at vise dataene fra den smarte kontrakt på en bekvem måde. Her vil jeg ikke dvæle ved det i detaljer og vil offentliggøre siden i én forpligtelse.

Forespørgsler til TON sker fra Python via lite-client. For nemheds skyld er webstedet pakket i Docker og udgivet på Google Cloud. Link.

Lad os prøve

Lad os nu prøve at sende gram dertil til genopfyldning fra pung. Vi sender 40 gram. Og lad os lave et par væddemål for klarhedens skyld. Vi ser, at siden viser væddemålshistorikken, den aktuelle vinderprocent og anden nyttig information.

Vi serat vi vandt den første, tabte den anden.

efterskrift

Artiklen viste sig at være meget længere, end jeg havde forventet, måske kunne den have været kortere, eller måske bare for en person, der ikke ved noget om TON og gerne vil skrive og udgive en ikke-så-simpel smart kontrakt med mulighed for at interagere med det. Nogle ting kunne måske have været forklaret mere enkelt.

Måske kunne nogle aspekter af implementeringen være gjort mere effektivt og elegant, men så ville det have taget endnu mere tid at forberede artiklen. Det er også muligt, at jeg lavede en fejl et eller andet sted eller ikke forstod noget, så hvis du gør noget seriøst, skal du stole på den officielle dokumentation eller det officielle lager med TON-koden.

Det skal bemærkes, at da TON selv stadig er i det aktive udviklingsstadium, kan der forekomme ændringer, der vil bryde ethvert af trinene i denne artikel (hvilket skete, mens jeg skrev, det er allerede blevet rettet), men den generelle tilgang er næppe ændre sig.

Jeg vil ikke tale om fremtiden for TON. Måske bliver platformen til noget stort, og vi burde bruge tid på at studere den og fylde en niche med vores produkter nu.

Der er også Libra fra Facebook, som har et potentielt publikum af brugere større end TON. Jeg ved næsten intet om Libra, ud fra forummet at dømme er der meget mere aktivitet der end i TON-fællesskabet. Selvom udviklerne og samfundet i TON er mere som underjordiske, hvilket også er fedt.

RЎSЃS <P "RєRё

  1. Officiel TON-dokumentation: https://test.ton.org
  2. Officielt TON-lager: https://github.com/ton-blockchain/ton
  3. Officiel tegnebog til forskellige platforme: https://wallet.ton.org
  4. Smart kontraktopbevaring fra denne artikel: https://github.com/raiym/astonished
  5. Link til hjemmesiden for smart kontrakt: https://ton-lottery.appspot.com
  6. Repository for udvidelsen til Visual Studio Code for FunC: https://github.com/raiym/func-visual-studio-plugin
  7. Chat om TON i Telegram, som virkelig hjalp med at finde ud af det i den indledende fase. Jeg tror, ​​det vil ikke være en fejl, hvis jeg siger, at alle, der har skrevet noget for TON, er der. Du kan også bede om testgram der. https://t.me/tondev_ru
  8. Endnu en chat om TON, hvor jeg fandt nyttige oplysninger: https://t.me/TONgramDev
  9. Første fase af konkurrencen: https://contest.com/blockchain
  10. Anden fase af konkurrencen: https://contest.com/blockchain-2

Kilde: www.habr.com

Tilføj en kommentar