Om hvordan du skriver og publiserer en smart kontrakt i Telegram Open Network (TON)

Om hvordan du skriver og publiserer en smart kontrakt i TON

Hva handler denne artikkelen om?

I artikkelen vil jeg snakke om hvordan jeg deltok i den første (av to) Telegram blockchain-konkurransen, ikke tok en premie og bestemte meg for å spille inn opplevelsen min i en artikkel slik at den ikke synker i glemmeboken og kanskje hjelpe noen.

Siden jeg ikke ønsket å skrive abstrakt kode, men å gjøre noe som fungerer, skrev jeg for artikkelen en smart kontrakt for et øyeblikkelig lotteri og et nettsted som viser smart kontraktsdata direkte fra TON uten å bruke mellomlagring.

Artikkelen vil være nyttig for de som ønsker å lage sin første smarte kontrakt i TON, men ikke vet hvor de skal begynne.

Ved å bruke lotteriet som eksempel vil jeg gå fra å installere miljøet til å publisere en smart kontrakt, samhandle med den og skrive en nettside for mottak og publisering av data.

Om deltakelse i konkurransen

I oktober i fjor annonserte Telegram en blokkjedekonkurranse med nye språk Fift и FunC. Det var nødvendig å velge mellom å skrive en av de fem foreslåtte smarte kontraktene. Jeg tenkte det kunne være fint å gjøre noe annerledes, lære et språk og lage noe, selv om jeg ikke trenger å skrive noe annet i fremtiden. I tillegg er temaet konstant på leppene.

Det er verdt å si at jeg ikke hadde noen erfaring med å utvikle smarte kontrakter.

Jeg planla å delta helt til det siste til jeg kunne og så skrive en anmeldelsesartikkel, men jeg mislyktes med en gang ved den første. Jeg skrev en lommebok med multisignatur på FunC og det fungerte stort sett. Jeg tok det som grunnlag smart kontrakt på soliditet.

På den tiden tenkte jeg at dette definitivt var nok til å ta i det minste en premieplass. Som et resultat ble rundt 40 av 60 deltakere prisvinnere og jeg var ikke blant dem. Generelt er det ikke noe galt med dette, men en ting plaget meg. På tidspunktet for kunngjøringen av resultatene var gjennomgangen av testen for kontrakten min ikke gjort, jeg spurte deltakerne i chatten om det var noen andre som ikke hadde det, det var ingen.

Tilsynelatende tok hensyn til meldingene mine, to dager senere publiserte dommerne en kommentar, og jeg forstår fortsatt ikke om de ved et uhell gikk glipp av den smarte kontrakten min under bedømmelsen eller bare trodde at den var så ille at den ikke trengte en kommentar. Jeg stilte et spørsmål på siden, men fikk ikke svar. Selv om det ikke er noen hemmelighet hvem som dømte, anså jeg det som unødvendig å skrive personlige meldinger.

Det ble brukt mye tid på forståelse, så det ble besluttet å skrive en artikkel. Siden det ikke er mye informasjon ennå, vil denne artikkelen bidra til å spare tid for alle interesserte.

Konseptet med smarte kontrakter i TON

Før du skriver noe, må du finne ut hvilken side du skal nærme deg denne tingen fra. Derfor skal jeg nå fortelle deg hvilke deler systemet består av. Mer presist, hvilke deler du trenger å vite for å skrive i det minste en slags arbeidskontrakt.

Vi vil fokusere på å skrive en smart kontrakt og jobbe med TON Virtual Machine (TVM), Fift и FunC, så artikkelen er mer som en beskrivelse av utviklingen av et vanlig program. Vi vil ikke dvele ved hvordan selve plattformen fungerer her.

Generelt om hvordan det fungerer TVM og språk Fift det er god offisiell dokumentasjon. Mens jeg deltok i konkurransen og nå mens jeg skrev den nåværende kontrakten, henvendte jeg meg ofte til henne.

Hovedspråket som smarte kontrakter er skrevet på er FunC. Det er ingen dokumentasjon på det for øyeblikket, så for å skrive noe må du studere eksempler på smarte kontrakter fra det offisielle depotet og implementeringen av selve språket der, pluss at du kan se på eksempler på smarte kontrakter fra de to siste konkurranser. Lenker på slutten av artikkelen.

La oss si at vi allerede har skrevet en smart kontrakt for FunC, etter det kompilerer vi koden til Fift assembler.

Den kompilerte smartkontrakten gjenstår å bli publisert. For å gjøre dette må du skrive en funksjon i Fift, som tar den smarte kontraktskoden og noen andre parametere som input, og utdataene vil være en fil med utvidelsen .boc (som betyr "pose med celler"), og, avhengig av hvordan vi skriver det, en privat nøkkel og adresse, som genereres basert på den smarte kontraktskoden. Du kan allerede sende gram til adressen til en smart kontrakt som ennå ikke er publisert.

For å publisere en smart kontrakt i TON mottatt .boc filen må sendes til blokkjeden ved hjelp av en lett klient (mer om det nedenfor). Men før du publiserer, må du overføre gram til den genererte adressen, ellers vil den smarte kontrakten ikke bli publisert. Etter publisering kan du samhandle med smartkontrakten ved å sende den meldinger fra utsiden (for eksempel ved hjelp av en lysklient) eller fra innsiden (for eksempel sender en smartkontrakt en melding til en annen inne i TON).

Når vi forstår hvordan koden publiseres, blir det enklere. Vi vet omtrent hva vi vil skrive og hvordan programmet vårt vil fungere. Og mens vi skriver ser vi etter hvordan dette allerede er implementert i eksisterende smarte kontrakter, eller vi ser på implementeringskoden Fift и FunC i det offisielle depotet, eller se i den offisielle dokumentasjonen.

Svært ofte søkte jeg etter nøkkelord i Telegram-chatten der alle konkurransedeltakerne og Telegram-ansatte samlet seg, og det hendte at alle under konkurransen samlet seg der og begynte å diskutere Fift og FunC. Link på slutten av artikkelen.

Det er på tide å gå fra teori til praksis.

Forberede miljøet for arbeid med TON

Jeg gjorde alt som vil bli beskrevet i artikkelen om MacOS og dobbeltsjekket det i ren Ubuntu 18.04 LTS på Docker.

Det første du må gjøre er å laste ned og installere lite-client som du kan sende forespørsler til TON med.

Instruksjonene på den offisielle nettsiden beskriver installasjonsprosessen ganske detaljert og tydelig og utelater noen detaljer. Her følger vi instruksjonene, og installerer de manglende avhengighetene underveis. Jeg kompilerte ikke hvert prosjekt selv og installerte fra det offisielle Ubuntu-depotet (på MacOS jeg brukte 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 avhengigheter er installert, kan du installere lite-client, Fift, FunC.

Først kloner vi TON-depotet sammen med dets avhengigheter. For enkelhets skyld vil vi gjø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 lagrer også implementeringer Fift и FunC.

Nå er vi klare for å sette sammen prosjektet. Depotkoden klones inn i en mappe ~/TON/ton. I ~/TON opprette en mappe build og samle prosjektet i den.

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

Siden vi skal skrive en smart kontrakt, trenger vi ikke bare lite-clientMen Fift с FunC, så la oss kompilere alt. Det er ikke en rask prosess, så vi venter.

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

Deretter laster du ned konfigurasjonsfilen som inneholder data om noden som lite-client vil koble til.

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

Gir de første forespørslene til TON

La oss nå starte lite-client.

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

Hvis byggingen var vellykket, vil du etter lansering se en logg over tilkoblingen av lysklienten 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 kjøre kommandoen help og se hvilke kommandoer som er tilgjengelige.

help

La oss liste opp kommandoene vi skal bruke i denne artikkelen.

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

Nå er vi klare til å skrive selve kontrakten.

implementering

Idé

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

Dessuten er dette ikke et lotteri der du trenger å kjøpe en billett og vente en time, dag eller måned, men et øyeblikkelig lotteri der brukeren overfører til kontraktsadressen N gram, og får den umiddelbart tilbake 2 * N gram eller taper. Vi vil gjøre sannsynligheten for å vinne omtrent 40 %. Hvis det ikke er nok gram til betaling, vil vi vurdere transaksjonen som en påfylling.

Dessuten er det viktig at spill kan sees i sanntid og i en praktisk form, slik at brukeren umiddelbart kan forstå om han vant eller tapte. Derfor må du lage en nettside som viser spill og resultater direkte fra TON.

Skrive en smart kontrakt

For enkelhets skyld har jeg fremhevet koden for FunC; plugin-en kan finnes og installeres i Visual Studio Code-søket; hvis du plutselig vil legge til noe, har jeg gjort plugin-en offentlig tilgjengelig. Også, noen tidligere laget en plugin for å jobbe med Fift, du kan også installere den og finne den i VSC.

La oss umiddelbart lage et depot der vi forplikter mellomresultatene.

For å gjøre livet vårt enklere skal vi skrive en smart kontrakt og teste den lokalt til den er klar. Først etter det vil vi publisere den i TON.

Smartkontrakten har to eksterne metoder som kan nås. Først, recv_external() denne funksjonen utføres når en forespørsel til kontrakten kommer fra omverdenen, det vil si ikke fra TON, for eksempel når vi selv genererer en melding og sender den gjennom lite-klienten. Sekund, recv_internal() dette er når, innenfor TON selv, enhver kontrakt refererer til vår. I begge tilfeller kan du sende parametere til funksjonen.

La oss starte med et enkelt eksempel som vil fungere hvis det publiseres, men det er ingen funksjonell belastning i det.

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

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

Her må vi forklare hva det er slice. All data som er lagret i TON Blockchain er en samling TVM cell eller rett og slett cell, i en slik celle kan du lagre opptil 1023 biter med data og opptil 4 lenker til andre celler.

TVM cell slice eller slice dette er en del av den eksisterende cell brukes til å analysere det, vil det bli klart senere. Hovedsaken for oss er at vi kan overføre slice og avhengig av typen melding, behandle dataene i recv_external() eller recv_internal().

impure — et nøkkelord som indikerer at funksjonen endrer smart kontraktsdata.

La oss lagre kontraktskoden i lottery-code.fc og kompilere.

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

Betydningen av flaggene kan sees ved hjelp av kommandoen

~/TON/build/crypto/func -help

Vi har kompilert 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 lanseres lokalt, for dette vil vi forberede miljøet.

Merk at den første linjen kobles til Asm.fif, dette er kode skrevet i Fift for Fift-montøren.

Siden vi ønsker å kjøre og teste smartkontrakten lokalt, vil vi lage en fil lottery-test-suite.fif og kopier den kompilerte koden dit, og erstatte den siste linjen i den, som skriver den smarte kontraktskoden til en konstant codefor deretter å overføre den til den virtuelle maskinen:

"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

Så langt virker det klart, la oss nå legge til den samme filen koden som vi vil bruke til å 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 si dataene som TVM (eller nettverkstilstand) vil bli lansert med. Selv under konkurransen viste en av utviklerne hvordan man lager c7 og jeg kopierte. I denne artikkelen må vi kanskje endre rand_seed siden genereringen av et tilfeldig tall avhenger av det, og hvis det ikke endres, vil det samme tallet returneres hver gang.

recv_internal и recv_external konstanter med verdier 0 og -1 vil være ansvarlig for å kalle de tilsvarende funksjonene i den smarte kontrakten.

Nå er vi klare til å lage den første testen for vår tomme smarte kontrakt. For klarhetens skyld vil vi foreløpig legge alle testene til den samme filen lottery-test-suite.fif.

La oss lage en variabel storage og skriv en tom en inn i den cell, vil dette være den smarte kontraktlagringen.

message Dette er budskapet som vi vil overføre til den smarte kontakten fra utsiden. Vi skal også gjøre det tomt foreløpig.

variable storage 
<b b> storage ! 

variable message 
<b b> message ! 

Etter at vi har forberedt konstantene og variablene, starter vi TVM ved å bruke kommandoen runvmctx og gi de opprettede parameterne til inngangen.

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

Til slutt vil vi lykkes her er en mellomkode for Fift.

Nå kan vi kjøre den resulterende koden.

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

Programmet skal kjøre uten feil, og i utdataene vil vi se utfø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

Flott, vi har skrevet den første fungerende versjonen av smartkontrakten.

Nå må vi legge til funksjonalitet. La oss først ta for oss meldinger som kommer fra omverdenen til recv_external()

Utbygger velger selv hvilket meldingsformat kontrakten kan akseptere.

Men vanligvis

  • for det første ønsker vi å beskytte kontrakten vår fra omverdenen og gjøre det slik at bare eieren av kontrakten kan sende eksterne meldinger til den.
  • for det andre, når vi sender en gyldig melding til TON, vil vi at dette skal skje nøyaktig én gang, og når vi sender den samme meldingen igjen, avviser smartkontrakten det.

Så nesten hver kontrakt løser disse to problemene, siden kontrakten vår aksepterer eksterne meldinger, må vi også ta vare på det.

Vi gjør det i omvendt rekkefølge. Først, la oss løse problemet med repetisjon; hvis kontrakten allerede har mottatt en slik melding og behandlet den, vil den ikke utføre den en gang til. Og så skal vi løse problemet slik at bare en viss krets av mennesker kan sende meldinger til smartkontrakten.

Det er forskjellige måter å løse problemet med dupliserte meldinger. Slik gjør vi det. I smartkontrakten initialiserer vi telleren for mottatte meldinger med startverdien 0. I hver melding til smartkontrakten vil vi legge til gjeldende tellerverdi. Hvis tellerverdien i meldingen ikke samsvarer med verdien i smartkontrakten, behandler vi den ikke; hvis den gjør det, behandler vi den og øker telleren i smartkontrakten med 1.

La oss gå tilbake til lottery-test-suite.fif og legg til en ny test til den. Hvis vi sender et feil nummer, bør koden gi et unntak. La for eksempel kontraktdataene lagre 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"

La oss lansere.

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

Og vi vil se at testen blir utført med en feil.

[ 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 stadiet lottery-test-suite.fif skal se ut по ссылке.

La oss nå legge til motlogikken til den smarte kontrakten 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 budskapet vi sender.

Det første vi gjør er å sjekke om meldingen inneholder data, hvis ikke, så avslutter vi ganske enkelt.

Deretter analyserer vi meldingen. in_msg~load_uint(32) laster tallet 165, 32-bit unsigned int fra den overførte meldingen.

Deretter laster vi 32 biter fra den smarte kontraktlagringen. Vi sjekker at det innlastede nummeret samsvarer med det beståtte; hvis ikke, kaster vi et unntak. I vårt tilfelle, siden vi passerer en ikke-kamp, ​​bør et unntak gjøres.

La oss nå kompilere.

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

Kopier den resulterende koden til lottery-test-suite.fif, ikke glem å erstatte den siste linjen.

Vi sjekker at testen består:

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

Akkurat her Du kan se den tilsvarende forpliktelsen med de nåværende resultatene.

Merk at det er upraktisk å hele tiden kopiere den kompilerte koden til en smart kontrakt til en fil med tester, så la oss skrive et skript som vil skrive koden inn i en konstant for oss, og vi kobler ganske enkelt den kompilerte koden til testene våre ved å bruke "include".

Lag en fil i prosjektmappen build.sh med følgende innhold.

#!/bin/bash

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

La oss gjøre det kjørbart.

chmod +x ./build.sh

Nå er det bare å kjøre skriptet vårt for å kompilere kontrakten. Men i tillegg til dette, må vi skrive det inn i en konstant code. Så vi lager en ny fil lotter-compiled-for-test.fif, som vi tar med i filen lottery-test-suite.fif.

La oss legge til skirpt-kode til sh, som ganske enkelt vil duplisere den kompilerte filen inn lotter-compiled-for-test.fif og endre den siste linjen 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

Nå, for å sjekke, la oss kjøre det resulterende skriptet og en fil vil bli generert lottery-compiled-for-test.fif, som vi vil inkludere i vår lottery-test-suite.fif

В lottery-test-suite.fif slett kontraktskoden og legg til linjen "lottery-compiled-for-test.fif" include.

Vi kjører tester for å sjekke at de består.

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

Flott, nå for å automatisere lanseringen av tester, la oss lage en fil test.sh, som først kjøres build.sh, og kjør deretter testene.

touch test.sh
chmod +x test.sh

Vi skriver inne

./build.sh 

echo "nCompilation completedn"

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

La oss gjøre det test.sh og kjør den for å sikre at testene fungerer.

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

Vi kontrollerer at kontrakten er sammenstilt og testene er utført.

Flott, nå på oppstart test.sh Testene vil bli kompilert og kjørt umiddelbart. Her er linken til begå.

Ok, før vi fortsetter, la oss gjøre en ting til for enkelhets skyld.

La oss lage en mappe build hvor vi vil lagre den kopierte kontrakten og dens klon skrevet inn i en konstant lottery-compiled.fif, lottery-compiled-for-test.fif. La oss også lage en mappe test hvor vil testfilen bli lagret? lottery-test-suite.fif og potensielt andre støttefiler. Link til relevante endringer.

La oss fortsette å utvikle den smarte kontrakten.

Deretter skal det være en test som sjekker at meldingen er mottatt og telleren er oppdatert i butikken når vi sender riktig nummer. Men vi gjør det senere.

La oss nå tenke på hvilken datastruktur og hvilke data som må lagres i den smarte kontrakten.

Jeg vil beskrive alt vi lagrer.

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

Deretter må du skrive to funksjoner. La oss ringe den første pack_state(), som vil pakke dataene for senere lagring i den smarte kontraktlagringen. La oss ringe den andre unpack_state() vil lese og returnere data fra lagring.

_ 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 legger til disse to funksjonene i begynnelsen av den smarte kontrakten. Det vil ordne seg her er en mellomresultat.

For å lagre data må du ringe den innebygde funksjonen set_data() og den vil skrive data fra pack_state() i den smarte kontraktslagringen.

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

Nå som vi har praktiske funksjoner for å skrive og lese data, kan vi gå videre.

Vi må sjekke at meldingen som kommer utenfra er signert av eieren av kontrakten (eller en annen bruker som har tilgang til den private nøkkelen).

Når vi publiserer en smart kontrakt, kan vi initialisere den med dataene vi trenger i lagring, som vil bli lagret for fremtidig bruk. Vi vil registrere den offentlige nøkkelen der slik at vi kan bekrefte at den innkommende meldingen ble signert med den tilsvarende private nøkkelen.

Før vi fortsetter, la oss lage en privat nøkkel og skrive den til test/keys/owner.pk. For å gjøre dette, la oss starte Fift i interaktiv modus og utføre fire kommandoer.

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

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

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

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

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

La oss lage en mappe keys inne i mappen test og skriv den private nøkkelen 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 gjeldende mappe owner.pk.

Vi fjerner den offentlige nøkkelen fra stabelen og ved behov kan vi hente den fra den private.

Nå må vi skrive en signaturbekreftelse. La oss starte med testen. Først leser vi den private nøkkelen fra filen ved hjelp av funksjonen file>B og skriv det til en variabel owner_private_key, og deretter bruke funksjonen priv>pub konverter den private nøkkelen til en offentlig nøkkel og skriv resultatet inn 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 trenger begge nøklene.

Vi initialiserer den smarte kontraktlagringen med vilkårlige data i samme rekkefølge som i funksjonen pack_state()og skriv det inn 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 !

Deretter vil vi komponere en signert melding, den vil bare inneholde signaturen og tellerverdien.

Først lager vi dataene vi ønsker å overføre, deretter signerer vi dem med en privat nøkkel og til slutt genererer vi en signert melding.

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 blir meldingen som vi sender til den smarte kontrakten registrert i en variabel message_to_send, om funksjoner hashu, ed25519_sign_uint du kan lese i Fift-dokumentasjonen.

Og for å kjøre testen ringer vi igjen.

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

Her så Filen med tester skal se slik ut på dette stadiet.

La oss kjøre testen og den vil mislykkes, så vi endrer smartkontrakten slik at den kan motta meldinger i dette formatet og bekrefte signaturen.

Først teller vi 512 biter av signaturen fra meldingen og skriver den til en variabel, deretter teller vi 32 biter av tellervariabelen.

Siden vi har en funksjon for å lese data fra den smarte kontraktlagringen, vil vi bruke den.

Neste er å sjekke telleren som er overført med lagringen og sjekke signaturen. Hvis noe ikke stemmer, kaster vi et unntak med den riktige koden.

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 forpliktelse her.

La oss kjøre testene og se at den andre testen mislykkes. Av to grunner er det ikke nok biter i meldingen og det er ikke nok biter i lagringen, så koden krasjer ved parsing. Vi må legge til en signatur til meldingen vi sender og kopiere lagringen fra den siste testen.

I den andre testen vil vi legge til en meldingssignatur og endre den smarte kontraktlagringen. Her så filen med tester ser ut for øyeblikket.

La oss skrive en fjerde test, der vi sender en melding signert med andres private nøkkel. La oss lage en annen privat nøkkel og lagre den i en fil not-owner.pk. Vi signerer meldingen med denne private nøkkelen. La oss kjøre testene og sørge for at alle testene består. Begå akkurat nå.

Nå kan vi endelig gå videre til implementering av smart kontraktslogikken.
В recv_external() vi godtar to typer meldinger.

Siden vår kontrakt vil akkumulere spillernes tap, må disse pengene overføres til skaperen av lotteriet. Lommebokadressen til lotteriskaperen registreres i lageret når kontrakten opprettes.

Bare i tilfelle trenger vi muligheten til å endre adressen som vi sender gram av taperne til. Vi skal også kunne sende gram fra lotteriet til eierens adresse.

La oss starte med den første. La oss først skrive en test som vil sjekke at etter å ha sendt meldingen, lagret smartkontrakten den nye adressen i lagringen. Vær oppmerksom på at i meldingen, i tillegg til skranken og den nye adressen, sender vi også action Et 7-bits heltall ikke-negativt tall, avhengig av det, vil vi velge hvordan vi skal behandle meldingen i den smarte kontrakten.

<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 smartkontraktslagring er deserialisert storage i Fift. Deserialisering av variabler er beskrevet i Fift-dokumentasjonen.

Commit link med tilsatt deig.

La oss kjøre testen og sørge for at den mislykkes. La oss nå legge til logikk for å endre adressen til lotteriets eier.

I den smarte kontrakten fortsetter vi å analysere message, les inn action. La oss huske at vi skal ha to action: endre adresse og send gram.

Deretter leser vi den nye adressen til kontraktseieren og lagrer den på lager.
Vi kjører testene og ser at den tredje testen mislykkes. Den krasjer på grunn av at kontrakten nå i tillegg analyserer 7 biter fra meldingen, som mangler i testen. Legg til en ikke-eksisterende i meldingen action. La oss kjøre testene og se at alt består. Her forplikte seg til endringer. Flott.

La oss nå skrive logikken for å sende det angitte antallet gram til den tidligere lagrede adressen.

Først, la oss skrive en test. Vi skal skrive to tester, en når det ikke er nok balanse, den andre når alt skal bestå. Tester kan sees i denne forpliktelsen.

La oss nå legge til koden. La oss først skrive to hjelpemetoder. Den første get-metoden er å finne ut den nåværende saldoen til en smart kontrakt.

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

Og den andre er for å sende gram til en annen smart kontrakt. Jeg kopierte denne metoden fullstendig fra en annen 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
}

La oss legge til disse to metodene til den smarte kontrakten og skrive logikken. Først analyserer vi antall gram fra meldingen. Deretter sjekker vi saldoen, hvis det ikke er nok kaster vi et unntak. Hvis alt er i orden, sender vi grammene til den lagrede adressen og oppdaterer telleren.

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å ser ut som den smarte kontrakten for øyeblikket. La oss kjøre testene og sørge for at de består.

Det blir forresten trukket provisjon fra smartkontrakten hver gang for en behandlet melding. For at de smarte kontraktsmeldingene skal utføre forespørselen, må du ringe etter grunnleggende kontroller accept_message().

La oss nå gå videre til interne meldinger. Faktisk vil vi bare akseptere gram og sende tilbake dobbelt beløp til spilleren hvis han vinner og en tredjedel til eieren hvis han taper.

La oss først skrive en enkel test. For å gjøre dette trenger vi en testadresse til smartkontrakten som vi angivelig sender gram til smartkontrakten fra.

Den smarte kontraktsadressen består av to tall, et 32-bits heltall som er ansvarlig for arbeidskjeden og et 256-bits ikke-negativt heltalls unikt kontonummer i denne arbeidskjeden. For eksempel -1 og 12345, dette er adressen vi vil lagre i en fil.

Jeg kopierte funksjonen for å lagre 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

La oss se på hvordan funksjonen fungerer, dette vil gi en forståelse av hvordan Fift fungerer. Start Fift i interaktiv modus.

~/TON/build/crypto/fift -i 

Først trykker vi -1, 12345 og navnet på den fremtidige filen "sender.addr" på stabelen:

-1 12345 "sender.addr" 

Det neste trinnet er å utføre funksjonen -rot, som forskyver stabelen på en slik måte at på toppen av stabelen er det et unikt smart kontraktnummer:

"sender.addr" -1 12345

256 u>B konverterer et 256-bits ikke-negativt heltall til byte.

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap bytter de to øverste elementene i stabelen.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

32 i>B konverterer et 32-bits heltall til byte.

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ kobler sammen to sekvenser med byte.

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

igjen swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

Og til slutt skrives bytene til filen B>file. Etter dette er stabelen vår tom. Vi stopper Fift. En fil er opprettet i gjeldende mappe sender.addr. La oss flytte filen til den opprettede mappen test/addresses/.

La oss skrive en enkel test som vil sende gram til en smart kontrakt. Her er forpliktelsen.

La oss nå se på logikken til lotteriet.

Det første vi gjør er å sjekke meldingen bounced eller ikke hvis bounced, så ignorerer vi det. bounced betyr at kontrakten vil returnere gram dersom det oppstår en feil. Vi returnerer ikke gram hvis det plutselig oppstår en feil.

Vi sjekker, hvis saldoen er mindre enn et halvt gram, så godtar vi bare meldingen og ignorerer den.

Deretter analyserer vi adressen til den smarte kontrakten som meldingen kom fra.

Vi leser dataene fra lagringen og sletter deretter gamle spill fra historikken hvis det er mer enn tjue av dem. For enkelhets skyld skrev jeg tre tilleggsfunksjoner pack_order(), unpack_order(), remove_old_orders().

Deretter ser vi om saldoen ikke er nok for betalingen, så vurderer vi at dette ikke er et veddemål, men et påfyll og lagrer påfyllet i orders.

Så til slutt essensen av den smarte kontrakten.

Først, hvis spilleren taper, lagrer vi det i spillhistorikken og hvis beløpet er mer enn 3 gram, sender vi 1/3 til eieren av smartkontrakten.

Hvis spilleren vinner, sender vi det dobbelte av beløpet til spillerens adresse og lagrer deretter informasjonen om innsatsen 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 var det. Tilsvarende forpliktelse.

Nå er alt som gjenstår enkelt, la oss lage get-metoder slik at vi kan få informasjon om kontraktens tilstand fra omverdenen (faktisk les dataene fra deres smarte kontraktlagring).

La oss legge til get-metoder. Vi vil skrive nedenfor om hvordan du mottar informasjon om en smart kontrakt.

Jeg glemte også å legge til koden som skal behandle den aller første forespørselen som oppstår ved publisering av en smart kontrakt. Tilsvarende forpliktelse. Og videre rettet opp feil med å sende 1/3 av beløpet til eiers konto.

Neste trinn er å publisere den smarte kontrakten. La oss lage en mappe requests.

Jeg tok publiseringskoden til grunn simple-wallet-code.fc hvilken kan finne i det offisielle depotet.

Noe verdt å være oppmerksom på. Vi genererer en smart kontraktlagring og en inndatamelding. Etter dette genereres adressen til den smarte kontrakten, det vil si at adressen er kjent allerede før publisering i TON. Deretter må du sende flere gram til denne adressen, og først etter det må du sende en fil med selve smartkontrakten, siden nettverket tar en provisjon for å lagre smartkontrakten og operasjoner i den (validatorer som lagrer og utfører smart kontrakter). Koden kan sees her.

Deretter kjører vi publiseringskoden og får lottery-query.boc smart kontraktsfil og adresse.

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

Ikke glem å lagre de genererte filene: lottery-query.boc, lottery.addr, lottery.pk.

Vi vil blant annet se adressen til smartkontrakten i utfø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 moro skyld, la oss sende en forespørsel til TON

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

Og vi vil se at kontoen med denne adressen er tom.

account state is empty

Vi sender til adressen 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 gram og etter noen sekunder utfører vi den samme kommandoen. For å sende gram bruker jeg offisiell lommebok, og du kan spørre noen fra chatten om testgram, som jeg vil snakke om på slutten av artikkelen.

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Ser ut som en uinitialisert (state:account_uninit) en smart kontrakt med samme adresse og en saldo på 1 000 000 000 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

La oss nå publisere den smarte kontrakten. La oss starte lite-klient og kjø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 

La oss sjekke at kontrakten er publisert.

> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

Vi får blant annet.

  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 forpliktelse med endringer her.

La oss nå lage forespørsler om å samhandle med den smarte kontrakten.

Mer presist vil vi la den første for å endre adressen som et uavhengig verk, og vi vil gjøre den andre for å sende gram til eierens adresse. Faktisk må vi gjøre det samme som i testen for å sende gram.

Dette er meldingen vi vil sende til smartkontrakten, hvor msg_seqno 165, action 2 og 9.5 gram for sending.

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

Ikke glem å signere meldingen med din private nøkkel lottery.pk, som ble generert tidligere da den smarte kontrakten ble opprettet. Her er den tilsvarende forpliktelsen.

Motta informasjon fra en smart kontrakt ved hjelp av get-metoder

La oss nå se på hvordan du kjører smarte kontraktshentingsmetoder.

Lansering lite-client og kjør get-metodene som vi skrev.

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

В result inneholder verdien som funksjonen returnerer balance() fra vår smarte kontrakt.
Vi vil gjøre det samme for flere flere metoder.

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

La oss spørre om innsatshistorikken din.

> 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 bruke lite-klient og få metoder for å vise informasjon om smartkontrakten på siden.

Viser smart kontraktsdata på nettstedet

Jeg skrev en enkel nettside i Python for å vise dataene fra den smarte kontrakten på en praktisk måte. Her vil jeg ikke dvele i detalj og vil publisere siden i en forpliktelse.

Forespørsler til TON er gjort fra Python via lite-client. For enkelhets skyld er nettstedet pakket i Docker og publisert på Google Cloud. Link.

Prøver

La oss nå prøve å sende gram dit for påfyll fra lommebok. Vi sender 40 gram. Og la oss gjøre et par innsatser for klarhet. Vi ser at siden viser historien til innsatser, den nåværende vinnerprosenten og annen nyttig informasjon.

Vi serat vi vant den første, tapte den andre.

etterord

Artikkelen viste seg å være mye lengre enn jeg forventet, kanskje den kunne vært kortere, eller kanskje bare for en person som ikke vet noe om TON og ønsker å skrive og publisere en ikke-så-enkel smart kontrakt med mulighet til å samhandle med den. Noen ting kunne kanskje vært forklart enklere.

Kanskje noen aspekter ved implementeringen kunne vært gjort mer effektivt og elegant, men da hadde det tatt enda mer tid å utarbeide artikkelen. Det er også mulig at jeg har gjort en feil et sted eller ikke forsto noe, så hvis du gjør noe alvorlig, må du stole på den offisielle dokumentasjonen eller det offisielle depotet med TON-koden.

Det skal bemerkes at siden TON selv fortsatt er i det aktive utviklingsstadiet, kan det forekomme endringer som vil bryte noen av trinnene i denne artikkelen (som skjedde mens jeg skrev, den er allerede korrigert), men den generelle tilnærmingen er neppe endres.

Jeg vil ikke snakke om fremtiden til TON. Kanskje plattformen blir noe stort og vi bør bruke tid på å studere den og fylle en nisje med produktene våre nå.

Det er også Libra fra Facebook, som har et potensielt publikum av brukere som er større enn TON. Jeg vet nesten ingenting om Libra, etter forumet å dømme er det mye mer aktivitet der enn i TON-samfunnet. Selv om utviklerne og fellesskapet til TON er mer som underground, noe som også er kult.

referanser

  1. Offisiell TON-dokumentasjon: https://test.ton.org
  2. Offisielt TON-lager: https://github.com/ton-blockchain/ton
  3. Offisiell lommebok for forskjellige plattformer: https://wallet.ton.org
  4. Smart kontraktlager fra denne artikkelen: https://github.com/raiym/astonished
  5. Link til nettsiden for smart kontrakt: https://ton-lottery.appspot.com
  6. Repository for utvidelsen for Visual Studio Code for FunC: https://github.com/raiym/func-visual-studio-plugin
  7. Chat om TON i Telegram, som virkelig hjalp til med å finne ut av det i den innledende fasen. Jeg tror det ikke vil være en feil hvis jeg sier at alle som har skrevet noe for TON er der. Du kan også be om testgram der. https://t.me/tondev_ru
  8. Nok en prat om TON der jeg fant nyttig informasjon: https://t.me/TONgramDev
  9. Første etappe av konkurransen: https://contest.com/blockchain
  10. Andre etappe av konkurransen: https://contest.com/blockchain-2

Kilde: www.habr.com

Legg til en kommentar