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 denne artikel vil jeg fortælle om min deltagelse i den første (af to) konkurrence om blockchain i Telegram, hvor jeg ikke opnåede en præmieplads, og jeg besluttede at dokumentere mine erfaringer i artiklen, så de ikke går tabt, og måske hjælper nogen.

Da jeg ikke ønskede at skrive abstrakt kode, men lave noget fungerende, skrev jeg en smart kontrakt til en instant lotteri og en hjemmeside, der viser data fra smart kontrakten direkte fra TON uden at bruge mellemlager.

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

Ved hjælp af lotteriet vil jeg gå fra installation af miljøet til offentliggørelse af smart kontrakten, interaktion med den og skrive en hjemmeside til at hente og offentliggøre data.

Om deltagelsen i konkurrencen

I oktober sidste år annoncerede Telegram en blockchain-konkurrence med nye sprog Fift og FunC. Man skulle vælge at skrive en hvilken som helst af de fem foreslåede smart kontrakter. Jeg mente, det ville være spændende at beskæftige sig med noget usædvanligt, lære sproget og lave noget, selvom jeg måske ikke skulle skrive mere i fremtiden. Desuden er emnet altid aktuelt.

Det skal siges, at jeg ikke havde erfaring med ontwikkeling af smart kontrakter.

Jeg planlagde at deltage indtil sidste øjeblik, men da det blev muligt, at skrive en anmeldelse, mislykkedes jeg straks i den første. Jeg skrev en wallet med multi-signatur på FunC og den fungerede generelt. Jeg tog udgangspunkt i en smart kontrakt på Solidity.

På det tidspunkt mente jeg, at dette var nok til at opnå i det mindste en præmieplads. I alt blev omkring 40 ud af 60 deltagere præmieret, og jeg var ikke blandt dem. I det hele taget er der ikke noget skræmmende ved det, men én ting gjorde mig urolig. På tidspunktet for resultaterne var der ikke lavet en gennemgang med test af min kontrakt, jeg spurgte deltagerne i chatten, om der var nogen, der ikke havde det, men der var ingen.

Det ser ud til, at dommerne efter to dage offentliggjorde en kommentar i erkendelse af mine beskeder, og jeg forstod ikke, om de tilfældigt havde overset min smart-kontrakt under bedømmelsen, eller om de blot mente, at den var så dårlig, at den ikke behøvede kommentarer. Jeg stillede et spørgsmål på siden, men fik ikke svar. Selvom det ikke er hemmeligt, hvem der dømte, anså jeg det for overflødigt at skrive personlige beskeder.

Der blev brugt en del tid på at forstå det, så jeg besluttede at skrive en artikel. Da informationen ikke er så meget endnu, vil artiklen hjælpe med at spare tid for alle interesserede.

Konceptet for smart-kontrakter i TON

Før vi skriver noget, skal vi finde ud af, hvordan man overhovedet skal nærme sig dette emne. Derfor vil jeg nu fortælle om, hvilke dele systemet består af. Mere præcist hvilke dele man skal kende for at kunne skrive en funktionel kontrakt.

Vi vil fokusere på at skrive en smart-kontrakt og arbejde med TON Virtual Machine (TVM), Fift og FunC, så denne artikel minder mere om at beskrive udviklingen af et almindeligt program. Vi vil ikke stoppe op ved, hvordan platformen fungerer.

Generelt er der god officiel dokumentation om, hvordan TVM og sproget Fift skrives. Der er i øjeblikket ingen dokumentation for det, så for at skrive noget skal man studere eksempler på smart-kontrakter fra det officielle repository og implementeringen af sproget der, plus man kan se på eksempler på smart-kontrakter fra de forgangne to konkurrencer. Links i slutningen af artiklen.

Det primære sprog, der bruges til at skrive smart-kontrakter – FunC. Der er i øjeblikket ikke nogen dokumentation for det, så for at skrive noget må man studere eksempler på smart-kontrakter fra det officielle repository og selve implementeringen af sproget der, derudover kan man se på eksempler fra de to tidligere konkurrencer. Links findes i slutningen af artiklen.

Lad os antage, at vi allerede har skrevet en smart-kontrakt på FunC, derefter kompilere vi koden til Fift-assembler.

Den kompilerede smart-kontrakt skal publiceres. For at gøre det skal vi skrive en funktion på Fift, der tager smart-kontraktens kode og nogle yderligere parametre som input, og outputtet vil være en fil med udvidelsen .boc (hvad der betyder 'bag of cells'), og afhængigt af, hvordan vi skriver det, en privat nøgle og en adresse, der genereres baseret på smart-kontraktens kode. Man kan allerede sende gram til adressen for den smart-kontrakt, som endnu ikke er offentliggjort.

For at offentliggøre smart-kontrakten i TON skal den opnåede .boc Filen skal sendes til blockchainen ved hjælp af en light client (mere om det nedenfor). Men før publiceringen skal du overføre gram til den genererede adresse, ellers vil smartkontrakten ikke blive offentliggjort. Efter offentliggørelsen kan du interagere med smartkontrakten ved at sende den beskeder udefra (for eksempel ved hjælp af light client) eller indefra (for eksempel en smartkontrakt sender en anden smartkontrakt en besked inden for TON).

Når vi har forstået, hvordan koden offentliggøres, bliver det lettere. Vi har en idé om, hvad vi vil skrive, og hvordan vores program vil fungere. Under skrivningen leder vi efter, hvordan det allerede er implementeret i eksisterende smartkontrakter, eller vi tjekker implementationskoden. Fift og FunC i det officielle repository, eller vi ser i den officielle dokumentation.

Meget ofte ledte jeg efter nøgleord i Telegram-chatten, hvor alle deltagerne i konkurrencen og ansatte fra Telegram var samlet, så det skete, at alle mødtes netop der under konkurrencen og begyndte at diskutere Fift og FunC. Linket er i slutningen af artiklen.

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

Forberedelse af miljøet til arbejde med TON

Alt, hvad der beskrives i artiklen, blev gjort på MacOS og er blevet genchecket i en ren Ubuntu 18.04 LTS på Docker.

Det første, vi skal gøre, er at downloade og installere lite-client , som gør det muligt at sende anmodninger til TON.

Instruktionen på den officielle hjemmeside beskriver installationsprocessen ret detaljeret og klart og udelader nogle detaljer. Her følger vi instruktionen, mens vi installerer de manglende afhængigheder. Jeg ville ikke selv kompilere hvert projekt og installerede fra den officielle Ubuntu-repository (på MacOS brugte jeg 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ængighederne er installeret, kan du installere lite-client, Fift, FunC.

Først kloner vi TON-repositoryen sammen med afhængighederne. For nemheds skyld vil vi gøre alt i mappen ~\/TON.

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

I repositoryen findes også implementeringerne. Fift og FunC.

Nu er vi klar til at bygge projektet. Koden fra repositoryen er klonet til mappen ~\/TON\/ton. I ~\/TON vi opretter en mappe build og bygger projektet der.

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

Da vi skal skrive en smartkontrakt, har vi ikke kun brug for lite-client, men også Fift med FunC, så vi kompilerer alt. Det er ikke en hurtig proces, så vi venter.

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

Dernæst downloader vi konfigurationsfilen, som indeholder oplysninger om noden, som lite-client vil blive tilsluttet.

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

Lad os lave de første forespørgsler til TON

Nu starter vi lite-client.

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

Hvis bygningen er lykkedes, vil du efter starten se loggen for forbindelse mellem lytteklienten og noden.

[ 1][t 2][1582054822.963129282][lite-client.h:201][!testnode]   conn klar
[ 2][t 2][1582054823.085654020][lite-client.cpp:277][!testnode] serverversion er 1.1, kapabiliteter 7
[ 3][t 2][1582054823.085725069][lite-client.cpp:286][!testnode] server tid er 1582054823 (delta 0)
...

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

help

Lad os opremse kommandoerne, som vi vil bruge i denne artikel.

liste over tilgængelige kommandoer:
last    Hent sidste blok og tilstandsoplysninger fra serveren
sendfile  Indlæser en serialiseret besked fra  og sender den til serveren
getaccount  []  Indlæser den nyeste tilstand af den angivne konto;  er i [:] format
runmethod  []  ...   Kører GET-metoden  af konto  med angivne parametre

last henter den senest oprettede blok fra serveren.

sendfile  sender en fil med en besked til TON, præcist med denne kommando offentliggøres smartkontrakten og forespørgslerne til den.

getaccount  indlæser den aktuelle tilstand af smartkontrakten med den angivne adresse.

runmethod  []    kører get-metoderne for smartkontrakten. 

Nu er vi klar til at skrive selve kontrakten.

Implementering

Idé

Som tidligere nævnt, er smartkontrakten vi skriver en lotteri.

Desuden er det ikke en lotteri, hvor man skal købe en billet og vente en time, dag eller måned, men en øjeblikkelig, hvor brugeren overfører til kontraktens adresse N grammer, og modtager straks 2 * N grammer eller taber. Sandsynligheden for at vinde vil være omkring 40%. Hvis grammerne til udbetaling ikke er tilstrækkelige, vil vi betragte transaktionen som en indbetaling.

Det er vigtigt, at væddemålene kan ses i realtid og på en overskuelig måde, så brugeren hurtigt kan forstå, om han eller hun har vundet eller tabt. Derfor skal vi lave et websted, som viser væddemålene og resultaterne direkte fra TON.

Skrivning af smartkontrakten

For nemheds skyld har jeg lavet kodefremhævelse til FunC, plugin kan findes og installeres i Visual Studio Code søgning, hvis man vil tilføje noget, har jeg offentliggjort pluginen. Derudover blev der tidligere lavet et plugin til at arbejde med Fift, som også kan findes og installeres i VSC.

Lad os straks oprette et repository, hvor vi kan committe de mellemresultater.

For at gøre livet lettere for os selv, vil vi skrive en smart kontrakt og teste den lokalt, indtil den er klar. Først derefter offentliggør vi den i TON.

Smart kontrakten har to eksterne metoder, som man kan tilgå. Den første, recv_external() denne funktion udføres, når der er en forespørgsel til kontrakten fra en ekstern kilde, altså ikke fra TON, for eksempel når vi selv danner en besked og sender den gennem lite-client. Den anden, recv_internal() det er, når en kontrakt inden i TON henvender sig til vores. I begge tilfælde kan vi sende parametre til funktionen.

Lad os begynde med et simpelt eksempel, som vil fungere, hvis det offentliggøres, men som ikke har nogen funktionel belastning.

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

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

Her skal det forklares, hvad sliceer. Alle data, der opbevares i TON Blockchain, er en samling af TVM cell eller blot cell, i en sådan celle kan man opbevare op til 1023 bits data og op til 4 henvisninger til andre celler.

TVM cell slice eller slice er en del af en eksisterende cell den bruges til at parse den, det bliver klart senere. Det vigtigste for os er, at vi kan sende slice og afhængigt af beskedens art, behandle data i recv_external() eller recv_internal().

impure — et nøgleord, der angiver, at funktionen ændrer dataene i smart kontrakten.

Vi gemmer kontraktens kode i lottery-code.fc og kompilere den.

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

Flagværdierne kan ses ved hjælp af kommandoen

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

Vi har fået en kompileret Fift-assemblerkode 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

Den kan køre lokalt, så lad os forberede miljøet.

Bemærk, at den første linje inkluderer Asm.fif, dette er kode skrevet i Fift til Fift-assembleren.

Da vi ønsker at køre og teste smart kontrakten lokalt, opretter vi en fil lottery-test-suite.fif og kopierer den kompilerede kode derind, idet vi ændrer den sidste linje, der skriver smart kontraktens kode i konstanten code, så vi senere kan sende 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

Det ser ud til at være forståeligt, nu tilføjer vi kode til den samme fil, som vi vil bruge til at køre 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()

I c7 Vi gemmer konteksten, altså de data, som TVM vil blive kørt med (eller netværkets tilstand). Allerede under konkurrencen viste en af udviklerne, hvordan man opretter c7 og jeg kopierede det. I denne artikel skal vi muligvis ændre rand_seed da det afhænger af genereringen af tilfældige tal, og hvis det ikke ændres, vil det returnere det samme tal hver gang.

recv_internal og recv_external konstanterne med værdierne 0 og -1 vil svare til kald af de tilsvarende funktioner i smartkontrakten.

Nu er vi klar til at oprette den første test til vores tomme smartkontrakt. For tydelighedens skyld tilføjer vi i øjeblikket alle tests i denne samme fil lottery-test-suite.fif.

Lad os oprette en variabel storage og skrive i den tom cell, det bliver smartekontraktens lager.

message det er den besked, vi vil sende til smartkontrakten udefra. Den gør vi også i øjeblikket tom.

variabelopbevaring 
<b b> opbevaring ! 

variabel meddelelse 
<b b> meddelelse ! 

Efter at vi har forberedt konstanterne og variablerne, kører vi TVM ved hjælp af kommandoen runvmctx og videregiver de oprettede parametre som input.

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

Resultatet vil være sådan en intermediær kode på Fift.

Nu kan vi køre den resulterende kode.

export FIFTPATH=~\/TON\/ton\/crypto\/fift\/lib \/\/ kør en gang for nemheds skyld 
~\/TON\/build\/crypto\/fift -s lottery-test-suite.fif 

Programmet skal køre uden fejl, og i output ser vi loggen af kørslen:

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

Fremragende, vi har skrevet den første fungerende version af smartkontrakten.

Nu er det tid til at tilføje funktionalitet. Først tager vi os af meddelelserne, der kommer fra den ydre verden ind i recv_external()

Udvikleren vælger selv formatet af den besked, som kontrakten kan modtage.

Men normalt,

  • for det første ønsker vi at beskytte vores kontrakt mod den ydre verden og sørge for, at kun ejer af kontrakten kan sende eksterne beskeder til den.
  • For det andet, når vi sender en gyldig besked til TON, ønsker vi, at dette sker præcist én gang, og ved en gentagen afsendelse af den samme besked skal smartkontrakten afvise den.

Derfor bliver disse to problemer næsten altid løst i hver kontrakt, da vores kontrakt accepterer eksterne beskeder, så vi også skal tage os af dette.

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

Der er forskellige måder at løse problemet med gentagne beskeder på. Vi vil gøre det på denne måde. I smartkontrakten initialiserer vi en tæller for modtagne beskeder med en startværdi på 0. I hver besked til smartkontrakten vil vi tilføje den nuværende værdi af tælleren. Hvis tællerværdien i beskeden ikke stemmer overens med værdien i smartkontrakten, behandler vi ikke beskeden; hvis den stemmer overens, behandler vi den og øger tælleren i smartkontrakten med 1.

Vi vender tilbage til lottery-test-suite.fif og tilføjer en anden test. Vi sender et forkert nummer; koden skal kaste et undtagelse. Lad os antage, at dataene i kontrakten gemmer 166, men vi sender 165.

<b 166 32 u, b> opbevaring !
<b 165 32 u, b> besked !

besked @ 
recv_external 
kode 
opbevaring @ 
c7 
runvmctx

drop 
exit_code ! 
."Exit kode " exit_code @ . cr 
exit_code @ 33 - abort"Test #2 Bestået ikke"

Lad os køre testen.

 ~\/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 Ikke bestået
[ 1][t 0][1582283084.210941076][fift-main.cpp:196]      Fejl under fortolkning af fil `lottery-test-suite.fif`: fejl under fortolkning af inkluderet fil `lottery-test-suite.fif` : lottery-test-suite.fif:67: abort": Test #2 Ikke bestået

På dette tidspunkt lottery-test-suite.fif skal se ud som via linket.

Lad os nu tilføje logikken for tælleren i smartkontrakten i lottery-code.fc.

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

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

I slice in_msg indeholder beskederne, som vi sender.

Det første, vi gør, er at kontrollere, om der er data i beskeden; hvis ikke, så går vi bare ud.

Derefter parser vi beskeden. in_msg~load_uint(32) indlæser tallet 165, 32-bit unsigned int fra den modtagne besked.

Here we load 32 bits from the smart contract storage. We check that the loaded number matches the one passed; if not, we throw an exception. In our case, since we are passing a mismatch, an exception should be thrown.

Now let's compile.

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

We will copy the resulting code to lottery-test-suite.fif, remembering to replace the last line.

We check that the test passes:

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

Her you can view the corresponding commit with the current results.

Notice that constantly copying the compiled smart contract code to the test file is inconvenient, so we'll write a script that will write the code to a constant for us, and we will simply include the compiled code in our tests using "include".

In the project folder, we will create a file build.sh with the following content.

#!/bin/bash

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

Let's make it executable.

chmod +x ./build.sh

Now, just running our script is enough to compile the contract. But besides this, we need to write it to a constant code. So we will create a new file lotter-compiled-for-test.fif, which we will include in the file lottery-test-suite.fif.

Let's add to the sh script the code that will simply duplicate the compiled file into lotter-compiled-for-test.fif and change the last line in it.

# 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

Now to test, we will run the resulting script and a file will be generated for us lottery-compiled-for-test.fif, which we will include in our lottery-test-suite.fif

I lottery-test-suite.fif we remove the contract code and add the line "lottery-compiled-for-test.fif" include.

We run the tests to check that they pass.

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

Great, now to automate the test runs, we will create a file test.sh, which will first execute build.sh, and then run the tests.

touch test.sh
chmod +x test.sh

Inside we write

./build.sh 

echo "nCompilation completedn"

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

Let's make test.sh and run it to ensure the tests work.

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

We check that the contract compiles and the tests run.

Great, now upon running test.sh compilation and test execution will happen simultaneously. Here is the link to commit.

Okay, before we continue, let's do one more thing for convenience.

Let's create a folder build where we will store the compiled contract and its clone recorded in a constant lottery-compiled.fif, lottery-compiled-for-test.fif. We will also create a folder test where the test file will be stored lottery-test-suite.fif and potentially other auxiliary files. Link to the relevant changes.

Let's continue developing the smart contract.

Dernæst skal der være en test, der kontrollerer, at beskeden modtages, og tælleren opdateres i lageret, når vi sender et korrekt tal. Men det gør vi senere.

Lad os nu tænke over, hvilken datamodel og hvilke data, der skal gemmes i smart-kontrakten.

Jeg vil beskrive alt, hvad vi gemmer.

`seqno` er et 32-bit helt positivt tal tæller. 

`pubkey` er et 256-bit helt positivt tal offentlig nøgle, som vi vil bruge til at verificere signaturen af den modtagne besked, som beskrevet nedenfor. 

`order_seqno` er et 32-bit helt positivt tal, der opbevarer tælleren for antallet af bud. 

`number_of_wins` er et 32-bit helt positivt tal, der gemmer antallet af sejre. 

`incoming_amount` datatypen Gram (de første 4 bit angiver længden), gemmer det samlede antal gram, der er sendt til kontrakten. 

`outgoing_amount` er det samlede antal gram, der er sendt til vinderne. 

`owner_wc` er nummeret på arbejdsblokken, 32-bit (i nogle tilfælde nævnt som 8-bit) helt tal. I øjeblikket er der kun to -1 og 0. 

`owner_account_id` er et 256-bit helt positivt tal, adressen på kontrakten i den aktuelle arbejdsblok. 

`orders` er en variabel af type ordbog, der gemmer de seneste tyve bud. 

Dernæst skal vi skrive to funktioner. Den første kalder vi pack_state(), som vil pakke data til senere lagring i smart-kontrakten. Den anden kalder vi unpack_state() og den 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 i begyndelsen af smart-kontrakten. Det vil give os sådan en et mellemresultat.

For at gemme data skal vi kalde den indbyggede funktion set_data() og den vil skrive dataene til pack_state() lageret i smart-kontrakten.

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 videre.

Vi skal kontrollere, at den indgående meddelelse er signeret af kontraktens ejer (eller en anden bruger, der har adgang til den private nøgle).

Når vi publicerer en smart kontrakt, kan vi initialisere den med de nødvendige data i lagringen, som vil blive gemt til fremtidig brug. Vi vil skrive den offentlige nøgle derind, så vi kan kontrollere, at signaturen af den indgående meddelelse blev lavet 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 kører vi Fift i interaktiv tilstand og udfører fire kommandoer.

`newkeypair` genererer en offentlig og privat nøgle og skriver dem til stakken. 

`drop` fjerner det øverste element fra stakken (i dette tilfælde den offentlige nøgle)  

`.s` viser blot, hvad der ligger i stakken i øjeblikket 

`"owner.pk" B>file` skriver den private nøgle til en fil med navnet `owner.pk`. 

`bye` afslutter arbejdet med Fift. 

Let's create a folder nøgler inde i mappen test og vi skriver den private nøgle derind.

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, så kan vi altid hente den fra den private nøgle.

Nu skal vi skrive en signaturkontrol. Lad os starte med en test. F first, læser vi den private nøgle fra filen ved hjælp af funktionen file>B og skriver den til variablen owner_private_key, derefter, ved hjælp af funktionen priv>pub konverterer vi den private nøgle til den offentlige og skriver resultatet til 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 har brug for begge nøgler.

Lad os initialisere lagringen af smart kontrakten med vilkårlige data i præcis den samme rækkefølge som i funktionen pack_state()og skrive den til variablen storage.

variabel ejer_private_key
variabel ejer_public_key 
variabel ordrer
variabel ejer_wc
variabel ejer_konto_id

".\/keys\/owner.pk" fil&gt;B ejer_private_key !
ejer_private_key @ priv&gt;pub ejer_public_key !
dictnew ordrer !
0 ejer_wc !
0 ejer_konto_id !

<b 0 32 u, owner_public_key @ b, gram, owner_wc i, owner_account_id 256 orders dict, b> opbevaring !

Dernæst samler vi den signerede meddelelse, den vil kun indeholde signaturen og tællerens værdi.

Først opretter vi de data, vi ønsker at overføre, derefter underskriver vi dem med den private nøgle, og endelig danner vi den signerede meddelelse.

variabel besked_at_underskrive
variabel besked_at_send
variabel underskrift
<b 0 32 u, b> besked_at_underskrive !
besked_at_underskrive @ hashu ejer_private_nøgle @ ed25519_underskrive_uint underskrift !
<b signature @ b, 0 32 u, b> &lt;s !  

Som resultat er meddelelsen, som vi sender til smart kontrakten, skrevet til variablen message_to_send, om funktionerne hashu, ed25519_sign_uint kan læses i dokumentationen for Fift.

Og for at køre testen kalder vi igen.

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

Sådan gør man filen skal se sådan ud på dette trin.

Vi kører testen, og den vil fejle, så vi ændrer smartkontrakten, så den kan modtage beskeder i dette format og kontrollere signaturen.

Først læser vi 512 bits af signaturen fra beskeden og gemmer dem i en variabel, derefter læser vi 32 bits af tællevariablen.

Da vi har en funktion til at indlæse data fra smartkontraktens lager, vil vi bruge den.

Dernæst kontrollerer vi tælleren, der er sendt sammen med lageret, og verificerer signaturen. Hvis noget ikke stemmer overens, kaster vi en undtagelse med den relevante 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));

Den pågældende commit her.

Vi kører testene og ser, at den anden test fejler. Dette skyldes to grunde: manglende bits i beskeden og manglende bits i lageret, så koden fejler ved parsing. Vi skal tilføje signaturen af beskeden, som vi sender, og kopiere lageret fra den seneste test.

I den anden test tilføjer vi signaturen af beskeden og ændrer lageret i smartkontrakten. Sådan gør man filen ser i øjeblikket sådan ud.

Vi vil skrive den fjerde test, hvor vi sender en besked signeret med en andens private nøgle. Vi opretter endnu en privat nøgle og gemmer den i en fil not-owner.pk. Med denne private nøgle signer vi beskeden. Vi kører testene og sikrer os, at alle tests lykkes. Commit på nuværende tidspunkt.

Nu kan vi endelig gå videre til implementeringen af smartkontraktens logik.
I recv_external() vi vil modtage to typer beskeder.

Da vores kontrakt vil akkumulere spilleres tab, skal disse penge overføres til lotteriets skaber. Adressen til lotteriets skaber gemmes i lageret, når kontrakten oprettes.

For en sikkerheds skyld har vi brug for muligheden for at ændre addressen, som de tabte gram skal sendes til. Vi skal også have mulighed for at sende gram fra lotteriet til ejerens adresse.

Lad os starte med den første. Vi skriver først en test, der vil kontrollere, at smartkontrakten har gemt den nye adresse i lageret efter afsendelse af beskeden. Bemærk, at vi udover tælleren og den nye adresse også sender action Et 7-bit heltal, der ikke er negativt, vil afgøre, hvordan vi håndterer meldingen i smartkontrakten.

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

I testen kan man se, hvordan deserialiseringen af smartkontraktens lager finder sted. storage i Fift. Deserialiseringen af variabler er beskrevet i dokumentationen om Fift.

Link til commit med tilføjelse af test.

Vi kører testen og sørger for, at den fejler. Lad os nu tilføje logik til at ændre ejerens adresse for lotteriet.

I smartkontrakten fortsætter vi med at parse message, vi læser ind i action. Lad os minde om, at vi vil have to action: ændringen af adressen og afsendelse af gram.

Derefter læser vi den nye adresse for kontraktens ejer og gemmer den i lageret.
Vi kører testene og ser, at den tredje test fejler. Den fejler fordi kontrakten nu yderligere parser 7 bit fra meldingen, som mangler i testen. Lad os tilføje den ikke-eksisterende action. Lad os køre testene og se, at alle består. Her commit til ændringer. Fremragende.

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

Først vil vi skrive en test. Vi vil skrive to tests, en når balancen ikke er tilstrækkelig, og en når alt skal gå godt. Testene kan ses i denne commit.

Lad os nu afslutte koden. Først skriver vi to hjælpemetoder. Den første er en get-metode til at finde den nuværende balance for smartkontrakten.

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

Og den anden til at sende gram til en anden smartkontrakt. Denne metode har jeg helt kopieret fra en anden smartkontrakt.

() 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 nuller +  0 som indikation på, at der ikke er en celle med data.
        .end_cell(); 
    send_raw_message(msg, 3); ;; mode, 2 for at ignorere fejl, 1 for sender betaler gebyrer, 64 for at returnere indgående meddelelse værdi
}

Lad os tilføje disse to metoder til smartkontrakten og skrive logikken. Først parser vi antallet af gram fra meldingen. Derefter tjekker vi balancen, hvis den ikke er tilstrækkelig, kaster vi en undtagelse. Hvis alt er i orden, sender vi gram 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));

Sådan gør man Smart-kontrakten ser sådan ud på nuværende tidspunkt. Lad os køre tests og sørge for, at de går igennem.

Forresten, der opkræves et gebyr for hver behandlet besked af smart-kontrakten. For at smart-kontrakten kan udføre anmodningen, skal vi efter de grundlæggende kontroller kalde accept_message().

Nu tager vi os af interne beskeder. Faktisk skal vi kun modtage gram og sende det dobbelte tilbage til spilleren ved gevinst og en tredjedel til ejeren ved tab.

Først skriver vi en simpel test. Til dette får vi brug for en testadresse for smart-kontrakten, som vi bruger til at sende gram til smart-kontrakten.

Adressen til smart-kontrakten består af to tal, et 32-bit heltal, der står for workchain, og et 256-bit ikke-negativt unikt kontonummer i denne workchain. For eksempel, -1 og 12345, denne adresse skal vi gemme i en fil.

Jeg har kopieret 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 gennemgå, hvordan funktionen fungerer, det vil give en forståelse af, hvordan Fift virker. Vi kører Fift i interaktiv tilstand.

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

Først lægger vi -1, 12345 og navnet på den kommende fil "sender.addr" i stakken:

-1 12345 "sender.addr" 

Næste trin er at udføre funktionen -rot, som skifter stakken, så den øverste del af stakken er det unikke nummer på smart-kontrakten:

"sender.addr" -1 12345

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

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap skifter de to øverste elementer i stakken.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

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

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ forbinder to byte-sekvenser.

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

Igen swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

Og endelig udføres skrivningen af bytes til filen B>file. Efter dette er vores stak tom. Vi stopper Fift. I den nuværende mappe er filen sender.addr. Vi flytter filen til den oprettede mappe test\/addresses\/.

Lad os skrive en simpel test, der sender gram til smart-kontrakten. Her er committet.

Nu går vi videre til lotteri-logikken.

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

Vi tjekker balancen; hvis den er mindre end en halv gram, accepterer vi blot beskeden og ignorerer den.

Dernæst parser vi adressen på smartkontrakten, som beskeden kom fra.

Vi læser data fra lagringen og fjerner derefter gamle indsatser fra historikken, hvis der er mere end tyve. For nemheds skyld har jeg skrevet tre ekstra funktioner pack_order(), unpack_order(), remove_old_orders().

Derefter ser vi, hvis balancen ikke er tilstrækkelig til udbetaling, at dette ikke er en indsats, men en indbetaling, og gemmer indbetalingen i orders.

Vi kommer endelig til essensen af smartkontrakten.

Først, hvis spilleren taber, gemmer vi ham i historien over indsatser, og hvis beløbet er over 3 gram, sender vi 1/3 til ejeren af smartkontrakten.

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) { ;; ignorer bounced
        return ();
    }
    if (order_amount < 500000000) { ;; modtag blot gram uden at ændre tilstand 
        return ();
    }
    slice src_addr_slice = cs~load_msg_addr();
    (int src_wc, int src_addr) = parse_std_addr(src_addr_slice);
    (int stored_seqno, int pubkey, int order_seqno, int number_of_wins, int incoming_amount, int outgoing_amount, int owner_wc, int owner_account_id, cell orders) = unpack_state();
    orders = remove_old_orders(orders, order_seqno);
    if (balance() = 4) {
        builder order = pack_order(order_seqno, 3, now(), order_amount, src_wc, src_addr);
        orders~udict_set_builder(32, order_seqno, order);
        set_data(pack_state(stored_seqno, pubkey, order_seqno + 1, number_of_wins, incoming_amount + order_amount, outgoing_amount, owner_wc, owner_account_id, orders));
        if (order_amount > 3000000000) {
            send_grams(owner_wc, owner_account_id, order_amount / 3);
        }
        return ();
    }
    send_grams(src_wc, src_addr, 2 * order_amount);
    builder order = pack_order(order_seqno, 2, now(), order_amount, src_wc, src_addr);
    orders~udict_set_builder(32, order_seqno, order);
    set_data(pack_state(stored_seqno, pubkey, order_seqno + 1, number_of_wins + 1, incoming_amount, outgoing_amount + 2 * order_amount, owner_wc, owner_account_id, orders));
}

Og det var det. Den relevante commit.

Nu er det tid til at oprette get-metoder, så vi fra den ydre verden kan få information om kontraktens tilstand (faktisk betragte dataene fra smartkontraktens lager).

Lad os tilføje get-metoder. Hvordan man får information om smartkontrakten vil vi uddybe nedenfor.

Jeg glemte også at tilføje koden, der vil håndtere den allerførste anmodning, der sker ved offentliggørelse af smartkontrakten. Den relevante commit. Og desuden rettet fejlen med at sende 1/3 af beløbet til ejerens konto.

Derefter er det tid til at offentliggøre smartkontrakten. Vi opretter en mappe requests.

Jeg har baseret det på kodepublikationen simple-wallet-code.fc som kan findes i det officielle repository.

Det, man skal være opmærksom på, er, at vi formerer smartkontraktens lager og beskeden som input. Derefter genereres adressen til smartkontrakten, hvilket vil sige, at adressen er kendt, inden den offentliggøres i TON. Derefter skal der sendes nogle gram til denne adresse, og først derefter skal filen med selve smartkontrakten sendes, da netværket opkræver et gebyr for opbevaringen af smartkontrakten og operationer i den (validatorer, der opbevarer og udfører smartkontrakter). Koden kan ses her.

Derefter udfører vi publiceringskoden og får lottery-query.boc filen og adressen til smartkontrakten.

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

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

Blandt andet vil vi i udførelsesloggene se adressen til smartkontrakten.

new wallet address = 0:044910149dbeaf8eadbb2b28722e7d6a2dc6e264ec2f1d9bebd6fb209079bc2a 
(Gemmer adressen til fil lottery.addr)
Non-bounceable address (for init): 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd
Bounceable address (for senere adgang): kQAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KpFY

Af nysgerrighed vil vi lave en anmodning i 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

Sender til adressen 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 Gram og efter et par sekunder udfører vi samme kommando. For at sende gram bruger jeg den officielle wallet, og testgrammer kan man anmode om fra nogen i chatten, som jeg nævner i slutningen af artiklen.

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Ser, at der i netværket er dukket en ikke-initialiseret (state:account_uninit) smartkontrakt op med denne adresse og en balance på 1 000 000 000 nanogram.

kontoets tilstand er (konto
  adresse:(addr_std
    anycast:ingen workchain_id:0 adresse:x044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A)
  opbevarings_stat:(storage_info
    brugt:(storage_used
      celler:(var_uint len:1 værdi:1)
      bits:(var_uint len:1 værdi:103)
      offentlige_celler:(var_uint len:0 værdi:0)) seneste_betalt:1583257959
    skyldig_betaling:ingen)
  opbevaring:(konto_opbevaring sidst_trans_lt:3825478000002
    saldo:(valutaer
      gram:(nanogram
        beløb:(var_uint len:4 værdi:2000000000))
      andet:(ekstra_valutaer
        dict:hme_empty))
    tilstand:konto_ukendt))
x{C00044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A20259C2F2F4CB3800000DEAC10776091DCD650004_}
sidste transaktion lt = 3825478000001 hash = B043616AE016682699477FFF01E6E903878CDFD6846042BA1BFC64775E7AC6C4
kontoets saldo er 2000000000ng

Lad os nu offentliggøre smartkontrakten. Vi starter lite-client og udfører.

> sendfile lottery-query.boc
[ 1][t 2][1583008371.631410122][lite-client.cpp:966][!testnode] sender forespørgsel fra fil lottery-query.boc
[ 3][t 1][1583008371.828550100][lite-client.cpp:976][!query]    ekstern meddelelse status er 1 

Lad os tjekke, om kontrakten er offentliggjort.

> sidste
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Blandt andet vil vi modtage.

  opbevaring:(konto_opbevaring sidst_trans_lt:3825499000002
    saldo:(valutaer
      gram:(nanogram
        beløb:(var_uint len:4 værdi:1987150999))
      andet:(ekstra_valutaer
        dict:hme_empty))
    tilstand:(konto_aktiv

Vi ser, at konto_aktiv.

Den relevante commit med ændringer her.

Lad os nu oprette forespørgsler til interaktion med smartkontrakt.

Nærmere bestemt vil vi efterlade den første til at ændre adressen som selvstændigt arbejde, og den anden til at sende gram til ejerens adresse. Faktisk skal vi gøre det samme som i testen om at sende gram.

Sådan en besked vil vi sende til smartkontrakten, hvor msg_seqno 165, action 2 og 9.5 gram til at sende.

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

Glem ikke at underskrive beskeden med den private nøgle lottery.pk, som blev genereret tidligere ved oprettelsen af smartkontrakten. Her er den relevante commit.

Vi henter information fra smartkontrakten ved hjælp af get-metoder

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

Starting lite-client og vi kører de get-metoder, vi har skrevet.

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

I resultat indeholder værdien, som funktionen returnerer balance() fra vores smartkontrakt.
Det samme vil vi udføre for flere metoder.

> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_seqno
...
argumenter:  [ 77871 ] 
resultat:  [ 1 ] 

Lad os anmode om historien over indsatser.

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

Vi vil bruge lite-client og GET-metoder til at vise oplysninger om smart-kontrakten på hjemmesiden.

Viser data for smart-kontrakten på hjemmesiden

Jeg har skrevet en simpel hjemmeside i Python for at vise data fra smart-kontrakten på en brugervenlig måde. Her vil jeg ikke gå i dybden med den og vil offentliggøre hjemmesiden med en commit.

Forespørgsler til TON udføres fra Python ved hjælp af lite-client. For nemheds skyld pakkes hjemmesiden i Docker og offentliggøres på Google Cloud. Link til hjemmesiden.

Lad os prøve

Nu prøver vi at sende grams til opfyldning fra tegnebogen. Lad os sende 40 grams. Og lave et par indsatser for tydelighedens skyld. Vi ser, at hjemmesiden viser indsatsens historie, den aktuelle gevinstprocent og andre nyttige oplysninger.

Vi ser, at vi vandt den første, og tabte den anden.

Efterord

Artiklen er blevet meget længere, end jeg havde antaget, måske kunne den have været kortere, eller måske er det netop for en person, der ved intet om TON og ønsker at skrive og offentliggøre en ikke så simpel smart-kontrakt med mulighed for at interagere med den. Måske kunne nogle ting have været forklaret enklere.

Måske kunne nogle aspekter af implementeringen have været gjort mere effektivt og elegant, men så ville der være gået endnu mere tid til forberedelsen af artiklen. Det er også muligt, at jeg har lavet fejl eller misforstået noget, så hvis du laver noget seriøst, skal du stole på den officielle dokumentation eller det officielle repository med TON-koden.

Det skal bemærkes, at da TON selv stadig er i aktiv udvikling, kan der opstå ændringer, der bryder et hvilket som helst af trinnene i denne artikel (hvilket også skete, mens jeg skrev det, men jeg har allerede rettet det), men den overordnede tilgang vil næppe ændre sig.

Jeg vil ikke spekulere på fremtiden for TON. Måske vil platformen blive noget større, og vi bør bruge tid på at studere den og tage en niche med vores produkter allerede nu.

Der er også Libra fra Facebook, som har en potentiel brugerbase, der er større end TONs. Jeg ved næsten ingenting om Libra, men ifølge forumet er aktiviteten der meget højere end i TON-fællesskabet. Selvom udviklerne og fællesskabet omkring TON mere minder om en undergrund, hvilket også er sejt.

Links

  1. Officiel dokumentation for TON: https://test.ton.org
  2. Officielt repository for TON: https://github.com/ton-blockchain/ton
  3. Officiel wallet til forskellige platforme: https://wallet.ton.org
  4. Repository for smart-kontrakten fra denne artikel: https://github.com/raiym/astonished
  5. Link til hjemmesiden for smart-kontrakten: https://ton-lottery.appspot.com
  6. Repository for udvidelsen til Visual Studio Code til FunC: https://github.com/raiym/func-visual-studio-plugin
  7. Chat om TON på Telegram, der virkelig har hjulpet mig med at forstå alt fra begyndelsen. Jeg tror ikke, det vil være en fejltagelse at sige, at alle, der har skrevet noget for TON, er der. Man kan også bede om testgræske der. https://t.me/tondev_ru
  8. Endnu en chat om TON, hvor jeg har fundet 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: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster