Hoe je een smart contract in TON schrijft en publiceert
Waar gaat dit artikel over?
In dit artikel vertel ik over mijn deelname aan de eerste (van de twee) Telegram-wedstrijd over blockchain, waar ik geen prijs behaalde, en besloot mijn ervaringen in een artikel vast te leggen, zodat ze niet verloren gaan en misschien iemand helpen.
Omdat ik geen abstracte code wilde schrijven, maar iets werkends wilde doen, heb ik voor het artikel een instant-loterij smart contract en een website gemaakt die de gegevens van het smart contract direct uit TON toont zonder gebruik te maken van tussenopslag.
Het artikel is nuttig voor degenen die hun eerste smart contract in TON willen maken, maar niet weten waar te beginnen.
Aan de hand van de loterij zal ik van de installatie van de omgeving tot de publicatie van het smart contract gaan, ermee interactie hebben en een website schrijven om gegevens te verkrijgen en te publiceren.
Over deelname aan de wedstrijd
In oktober vorig jaar kondigde Telegram een wedstrijd aan over blockchain met nieuwe talen Fift en FunC. Men moest kiezen uit vijf voorgestelde smart contracts. Ik dacht dat het leuk zou zijn om iets ongewoons te doen, de taal te bestuderen en iets te maken, zelfs als ik in de toekomst niets anders zou hoeven te schrijven. Bovendien is het onderwerp voortdurend actueel.
Het is goed om te zeggen dat ik geen ervaring had met het ontwikkelen van smart contracts.
Ik was van plan om tot het einde deel te nemen zolang het kon en daarna een overzichtelijk artikel te schrijven, maar ik faalde al meteen bij de eerste. Ik met multi-handtekening op FunC en het werkte in het algemeen goed. Ik nam als basis .
Op dat moment dacht ik dat dit zeker genoeg zou zijn om ten minste een prijs te winnen. Uiteindelijk werden ongeveer 40 van de 60 deelnemers prijswinnaars en ik was niet een van hen. Over het algemeen is er niets ergs aan, maar er was één ding dat me stoorde. Op het moment van de resultadoankondiging was er geen beoordeling met een test van mijn contract gedaan; ik vroeg de deelnemers in de chat of er nog iemand was die dat niet had, maar niemand had het.
Blijkbaar, aandacht trekkend via mijn berichten, publiceerden de juryleden na twee dagen een opmerking en ik begreep niet of ze mijn smart contract per ongeluk tijdens de beoordeling hadden gemist of dat ze gewoon dachten dat het zo slecht was dat het geen opmerkingen verdiende. Ik stelde een vraag op de pagina, maar kreeg geen antwoord. Hoewel wie beoordeelde - is geen geheim, vond ik het overbodig om persoonlijke berichten te sturen.
Er is veel tijd besteed aan het begrijpen, dus werd besloten om een artikel te schrijven. Aangezien er momenteel niet veel informatie is, zal het artikel tijd besparen voor iedereen die geïnteresseerd is.
Het concept van smart contracts in TON
Voordat we iets gaan schrijven, moeten we begrijpen hoe we deze materie moeten benaderen. Daarom zal ik nu uitleggen uit welke delen het systeem bestaat. Of beter gezegd, welke delen we moeten kennen om minstens een werkend contract te kunnen schrijven.
We zullen ons richten op het schrijven van een smart contract en het werken met TON Virtual Machine (TVM), Fift en FunC, daarom lijkt het artikel meer op een beschrijving van de ontwikkeling van een gewone applicatie. We zullen hier niet stilstaan bij hoe het platform zelf werkt.
Over hoe TVM en de taal Fift is er goede officiële documentatie. Tijdens mijn deelname aan de competitie en nu tijdens het schrijven van het huidige contract heb ik hier vaak naar verwezen.
De primaire taal waarin smart contracts worden geschreven is FunC. Er is momenteel geen documentatie beschikbaar, dus om iets te kunnen schrijven, moet je voorbeelden van smart contracts uit de officiële repository bestuderen en de implementatie van de taal daar, plus je kunt kijken naar voorbeelden van smart contracts uit de afgelopen twee wedstrijden. Links staan aan het einde van het artikel.
Stel dat we al een smart contract hebben geschreven in FunC, daarna compilen we de code naar Fift-assembler.
Het gecompileerde smart contract moet worden gepubliceerd. Hiervoor moet er een functie in worden geschreven op Fift, die als invoer de code van het smart contract en enkele andere parameters accepteert, en als uitvoer een bestand met de extensie .boc (wat "bag of cells" betekent), en, afhankelijk van hoe we het schrijven, een privésleutel en een adres dat wordt gegenereerd op basis van de code van het smart contract. Op het adres van het smart contract, dat nog niet is gepubliceerd, kunnen al grammen worden verzonden.
Om het smart contract in TON te publiceren, moet het verkregen .boc bestand naar de blockchain worden gestuurd met behulp van een light client (waaronder hieronder). Maar voordat we publiceren, moeten we grammen naar het gegenereerde adres overmaken, anders wordt het smart contract niet gepubliceerd. Na publicatie kan er met het smart contract worden gecommuniceerd door het van buitenaf berichten te sturen (bijvoorbeeld met een light client) of van binnenuit (bijvoorbeeld een smart contract stuurt een bericht naar een ander binnen TON).
Zodra we begrijpen hoe code gepubliceerd wordt, wordt het eenvoudiger. We weten ongeveer wat we willen schrijven en hoe ons programma zal werken. Tijdens het schrijven zoeken we naar hoe dit al is geïmplementeerd in bestaande slimme contracten of kijken we in de implementatiecode. Fift en FunC in de officiële repository, of we bekijken de officiële documentatie.
Ik zocht vaak op sleutelwoorden in de Telegram-chat waar alle deelnemers van de wedstrijd en ook medewerkers van Telegram zich hadden verzameld. Tijdens de wedstrijd kwamen iedereen daar samen en begonnen ze Fift en FunC te bespreken. De link staat aan het einde van het artikel.
Het is tijd om van theorie naar praktijk over te schakelen.
Omgeving voorbereiden voor het werken met TON
Alles wat in dit artikel wordt beschreven heb ik gedaan op MacOS en gecontroleerd op een schone Ubuntu 18.04 LTS op Docker.
Het eerste wat je moet doen is downloaden en installeren lite-client waarmee je verzoeken naar TON kunt verzenden.
De instructie op de officiële website beschrijft het installatieproces vrij gedetailleerd en duidelijk, en laat enkele details weg. Hier volgen we de instructies terwijl we de ontbrekende afhankelijkheden installeren. Ik heb niet elk project zelf gecompileerd, maar heb het geïnstalleerd vanuit de officiële Ubuntu-repository (op MacOS gebruikte ik 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 Nadat alle afhankelijkheden zijn geïnstalleerd, kunnen we lite-client, Fift, FunC.
Eerst klonen we de TON-repository samen met de afhankelijkheden. Voor de eenvoud doen we alles in de map ~\/TON.
cd ~\/TON
git clone https:\/\/github.com\/ton-blockchain\/ton.git
cd .\/ton
git submodule update --init --recursiveIn de repository zijn ook de implementaties opgeslagen. Fift en FunC.
Nu zijn we klaar om het project te bouwen. De code van de repository is gekloond naar de map ~\/TON\/tonwordt een tabel met wijzigingen en instructies voor de overgang naar de nieuwe configuratie gegeven. Voor meer informatie, zie ~\/TON we maken een map aan build en bouwen het project erin.
mkdir ~\/TON\/build
cd ~\/TON\/build
cmake ..\/tonAangezien we van plan zijn een slim contract te schrijven, hebben we niet alleen lite-clientmaar ook Fift met FunC, daarom compileren we alles. Het is geen snel proces, dus we wachten.
cmake --build . --target lite-client
cmake --build . --target fift
cmake --build . --target funcVervolgens downloaden we het configuratiebestand waarin de gegevens staan over de node waarmee lite-client we verbinding zullen maken.
wget https://test.ton.org/ton-lite-client-test1.config.jsonLaten we onze eerste verzoeken naar TON maken.
Nu gaan we starten. lite-client.
cd ~/TON/build
./lite-client/lite-client -C ton-lite-client-test1.config.jsonAls de bouw succesvol is verlopen, zie je na de start het log van de verbinding van de lite-client met de node.
[ 1][t 2][1582054822.963129282][lite-client.h:201][!testnode] conn ready
[ 2][t 2][1582054823.085654020][lite-client.cpp:277][!testnode] server versie is 1.1, mogelijkheden 7
[ 3][t 2][1582054823.085725069][lite-client.cpp:286][!testnode] server tijd is 1582054823 (delta 0)
...Je kunt het commando uitvoeren help en zien welke commando's beschikbaar zijn.
helpLaten we de commando's opsommen die we in dit artikel zullen gebruiken.
lijst van beschikbare commando's:
last Haal de laatste blok- en staatinformatie van de server
sendfile Laad een geserialiseerd bericht van en stuur het naar de server
getaccount [] Laadt de meest recente staat van het opgegeven account; is in [:] formaat
runmethod [] ... Voert de GET-methode van het account uit met de opgegeven parameterslast haalt het laatst aangemaakte blok van de server op.
sendfile verstuurt een bestand met een bericht naar TON, deze opdracht publiceert het slimme contract en verzoeken ernaar.
getaccount laadt de huidige staat van het slimme contract op het opgegeven adres.
runmethod [] voert de get-methoden van het slimme contract uit. Nu zijn we klaar om het contract zelf te schrijven.
Implementatie
Idee
Zoals ik hierboven al aangaf, is het slimme contract dat we schrijven een loterij.
Dit is geen loterij waarbij je een ticket moet kopen en een uur, dag of maand moet wachten, maar een onmiddellijke loterij waarbij de gebruiker een bedrag naar het contractadres overmaakt, N grammen, en onmiddellijk terugkrijgt 2 * N grammen of verliest. We maken de kans op winst ongeveer 40%. Als de grammen voor uitbetaling niet voldoende zijn, beschouwen we de transactie als een aanvulling.
Het is belangrijk dat de inzetten in realtime en op een handige manier zichtbaar zijn, zodat de gebruiker direct kan begrijpen of hij gewonnen of verloren heeft. Daarom moeten we een website maken die de inzetten en resultaten rechtstreeks vanuit TON laat zien.
Het schrijven van een slim contract
Voor gemak heb ik syntax highlighting gemaakt voor FunC, de plugin kan worden gevonden en geïnstalleerd via de zoekfunctie in Visual Studio Code. Mocht je iets willen toevoegen, heb ik de plugin openbaar gemaakt. Eerder was er ook een plugin gemaakt voor Fift, deze kan ook in VSC worden gevonden en geïnstalleerd.
Laten we eerst een repository aanmaken waar we de voortgangsresultaten zullen committen.
Om het onszelf gemakkelijker te maken, zullen we het slimme contract schrijven en lokaal testen totdat het klaar is. Pas daarna publiceren we het in TON.
Het slimme contract heeft twee externe methodes waar we toegang toe kunnen krijgen. De eerste, recv_external() deze functie wordt uitgevoerd wanneer er een verzoek naar het contract komt uit de externe wereld, dat wil zeggen niet vanuit TON, bijvoorbeeld wanneer we zelf een bericht formuleren en het via de lite-client verzenden. De tweede, recv_internal() dit is wanneer een contract binnen TON ons contract aanroept. In beide gevallen kunnen parameters aan de functie worden doorgegeven.
Laten we beginnen met een eenvoudig voorbeeld, dat zal werken als het gepubliceerd wordt, maar het heeft geen functionele belasting.
() recv_internal(slice in_msg) impure {
;; TODO: implementatie
}
() recv_external(slice in_msg) impure {
;; TODO: implementatie
}Hier moet worden uitgelegd wat slice. Alle opgeslagen gegevens in de TON Blockchain zijn een verzameling TVM cell of gewoon cell, in zo'n cel kan tot 1023 bits aan gegevens en tot 4 links naar andere cellen worden opgeslagen.
TVM cell slice of slice is een deel van een bestaande cell die wordt gebruikt voor parsing, later zal het duidelijk worden. Het belangrijkste voor ons is dat we in een smart contract kunnen doorgeven slice en afhankelijk van het type bericht de gegevens in recv_external() of recv_internal().
impure — het sleutelwoord dat aangeeft dat de functie de gegevens van het smart contract wijzigd.
Laten we de code van het contract opslaan in lottery-code.fc en compileren.
~\/TON\/build\/crypto\/func -APSR -o lottery-compiled.fif ~\/TON\/ton\/crypto\/smartcont\/stdlib.fc .\/lottery-code.fc De waarden van de vlaggen kunnen worden bekeken met het commando
~\/TON\/build\/crypto\/func -helpWe hebben nu gecompileerde Fift-assemblercode in 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>cDit kan lokaal worden uitgevoerd, dus laten we de omgeving voorbereiden.
Opmerking: de eerste regel bevat Asm.fif, dit is code geschreven in Fift voor de Fift-assembler.
Aangezien we het smart contract lokaal willen draaien en testen, creëren we een bestand lottery-test-suite.fif en kopiëren de gecompileerde code daarin, waarbij we de laatste regel vervangen, die de code van het smart contract in een constante schrijft code, zodat we het later naar de virtuele machine kunnen doorgeven:
"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 constante code
Tot nu toe duidelijk, nu voegen we in hetzelfde bestand de code toe die we gaan gebruiken om TVM uit te voeren.
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 , , \/\/ resterend saldo
0 , dictnew , \/\/ contract_address, global_config
1 tuple \/\/ wikkel naar een andere tuple
constante c7
0 constante recv_internal \/\/ voor het uitvoeren van recv_internal()
-1 constante recv_external \/\/ om recv_external() aan te roepenIn c7 we schrijven de context op, dat wil zeggen, de gegevens waarmee TVM wordt uitgevoerd (of de status van het netwerk). Tijdens de competitie toonde een van de ontwikkelaars hoe dit werd gedaan c7 en ik heb het gekopieerd. In dit artikel zullen we mogelijk rand_seed Aangezien de generatie van een willekeurig getal hiervan afhangt en niet kan worden gewijzigd, zal telkens hetzelfde getal worden teruggegeven.
recv_internal en recv_external Constanten met de waarden 0 en -1 zullen verantwoordelijk zijn voor het aanroepen van de corresponderende functies in het smart contract.
Nu zijn we klaar om onze eerste test voor ons lege smart contract te maken. Voor de duidelijkheid zullen we voorlopig alle tests in ditzelfde bestand toevoegen. lottery-test-suite.fif.
Laten we een variabele creëren opslag en daarin een lege waarde opslaan cell, dit zal de opslag van het smart contract zijn.
bericht dit is het bericht dat we aan het smart contract van buitenaf zullen doorgeven. We maken het voorlopig ook leeg.
variabele opslag
<b b> opslag !
variabele bericht
<b b> bericht ! Nadat we de constanten en variabelen hebben voorbereid, starten we de TVM met behulp van het commando runvmctx en geven de gemaakte parameters als invoer door.
bericht @
recv_external
code
storage @
c7
runvmctx Uiteindelijk krijgen we tussenliggende code in Fift.
Nu kunnen we de verkregen code uitvoeren.
export FIFTPATH=~\/TON\/ton\/crypto\/fift\/lib \/\/ voer dit eenmaal uit voor gemak
~\/TON\/build\/crypto\/fift -s lottery-test-suite.fif Het programma moet zonder fouten werken en in de uitvoer zien we het log van de uitvoering:
execute SETCP 0
execute DICTPUSHCONST 19 (xC_,1)
execute DICTIGETJMPZ
execute DROP
execute implicit RET
[ 3][t 0][1582281699.325381279][vm.cpp:479] stappen: 5 gas: gebruikt=304, max=9223372036854775807, limiet=9223372036854775807, krediet=0Geweldig, we hebben de eerste werkende versie van het smart contract geschreven.
Nu moeten we functionaliteit toevoegen. Laten we eerst kijken naar de berichten die van buiten de wereld naar binnen komen in recv_external()
De ontwikkelaar kiest zelf het formaat van het bericht dat het contract kan accepteren.
Maar gewoonlijk,
- ten eerste willen we ons contract beschermen tegen de buitenwereld en ervoor zorgen dat alleen de eigenaar van het contract externe berichten kan verzenden.
- Ten tweede willen we dat wanneer we een geldig bericht naar TON verzenden, dit precies één keer gebeurt en dat het smart contract het opnieuw verzenden van hetzelfde bericht afwijst.
Daarom worden deze twee problemen in bijna elk contract opgelost, aangezien ons contract externe berichten accepteert, moeten we hier ook voor zorgen.
We zullen dit in omgekeerde volgorde aanpakken. Laten we eerst het probleem van het herhalen oplossen: als het contract zo'n bericht al heeft ontvangen en verwerkt, zal het het niet nog een keer uitvoeren. En dan zullen we het probleem oplossen zodat alleen een bepaalde kring van personen berichten naar het smart contract kan sturen.
Er zijn verschillende manieren om het probleem van herhaalde berichten op te lossen. We zullen het als volgt aanpakken. In het smart contract initialiseren we een teller voor ontvangen berichten met een initiële waarde van 0. Bij elk bericht voegen we de huidige waarde van de teller toe aan het smart contract. Als de waarde van de teller in het bericht niet overeenkomt met de waarde in het smart contract, dan verwerken we het niet; als het overeenkomt, verwerken we het en verhogen we de teller in het smart contract met 1.
Laten we terugkeren naar lottery-test-suite.fif en een tweede test toevoegen. We zullen een verkeerd nummer versturen, de code zou een uitzondering moeten gooien. Laten we zeggen dat in de gegevens van het contract 166 is opgeslagen, maar we sturen 165.
<b 166 32 u, b> opslag !
<b 165 32 u, b> bericht !
bericht @
ontvang_extern
code
opslag @
c7
runvmctx
drop
exit_code !
."Exitcode " exit_code @ . cr
exit_code @ 33 - abort"Test #2 niet geslaagd"Laten we starten.
~\/TON\/build\/crypto\/fift -s lottery-test-suite.fif En we zullen zien dat de test met een fout wordt uitgevoerd.
[ 1][t 0][1582283084.210902214][words.cpp:3046] lottery-test-suite.fif:67: abort": Test #2 Niet geslaagd
[ 1][t 0][1582283084.210941076][fift-main.cpp:196] Fout bij het interpreteren van bestand `lottery-test-suite.fif`: fout bij het interpreteren van het ingesloten bestand `lottery-test-suite.fif`: lottery-test-suite.fif:67: abort": Test #2 Niet geslaagdIn deze fase lottery-test-suite.fif zou eruit moeten zien als .
Laten we nu de logica van de teller in het smart contract toevoegen in lottery-code.fc.
() recv_internal(slice in_msg) impure {
;; TODO: implementatie
}
() 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);
}In slice in_msg bevat het bericht dat we verzenden.
Het eerste wat we doen is controleren of er gegevens in het bericht zitten. Zo niet, dan stoppen we gewoon.
Daarna parseren we het bericht. in_msg~load_uint(32) laadt het getal 165, 32-bits unsigned int uit het verzonden bericht.
Daarna laden we 32 bits uit de opslag van het smart contract. We controleren of het geladen getal overeenkomt met het verzonden getal; als dat niet het geval is, gooien we een uitzondering. In ons geval, aangezien we een niet-overeenkomstig getal verzenden, zou er een uitzondering moeten worden gegooid.
Laten we nu compileren.
~\/TON\/build\/crypto\/func -APSR -o lottery-compiled.fif ~\/TON\/ton\/crypto\/smartcont\/stdlib.fc .\/lottery-code.fc We kopiëren de resulterende code naar lottery-test-suite.fif, vergeet niet de laatste regel te vervangen.
Laten we controleren of de test slaagt:
~\/TON\/build\/crypto\/fift -s lottery-test-suite.fifwe kunnen de bijbehorende commit met de huidige resultaten bekijken.
Laten we opmerken dat het constant kopiëren van de gecompileerde code van het smart contract naar het testbestand onhandig is, dus laten we een script schrijven dat de code voor ons in een constante schrijft, en wij voegen gewoon de gecompileerde code in onze tests in met behulp van "include".
In de map van het project maken we een bestand aan build.sh met de volgende inhoud.
#!/bin/bash
~/TON/build/crypto/func -SPA -R -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fcLaten we het uitvoerbaar maken.
chmod +x .\/build.shNu hoeven we alleen nog maar ons script uit te voeren om het contract te compileren. Maar daarnaast moeten we het ook in een constante opslaan. code. Daarom creëren we een nieuw bestand. lotter-compiled-for-test.fif, dat we in het bestand opnemen. lottery-test-suite.fif.
Laten we de sh-script code toevoegen die gewoon het gecompileerde bestand zal dupliceren naar lotter-compiled-for-test.fif en de laatste regel daarin zal wijzigen.
# 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.fifNu, om te controleren, laten we het resulterende script uitvoeren en zal er een bestand worden gegenereerd. lottery-compiled-for-test.fif, dat we in ons opnemen. lottery-test-suite.fif
In lottery-test-suite.fif verwijder de contract code en voeg de regel toe "lottery-compiled-for-test.fif" include.
Voer de tests uit om te controleren of ze slagen.
~\/TON\/build\/crypto\/fift -s lottery-test-suite.fifGeweldig, nu, om de testuitvoering te automatiseren, maken we een bestand aan. test.sh, dat eerst zal uitvoeren build.sh, en daarna de tests zal starten.
touch test.sh
chmod +x test.shSchrijf erin
.\/build.sh
echo "nCompilatie voltooidn"
export FIFTPATH=~\/TON\/ton\/crypto\/fift\/lib
~\/TON\/build\/crypto\/fift -s lottery-test-suite.fifLaten we maken test.sh en laten we het uitvoeren om ervoor te zorgen dat de tests werken.
chmod +x .\/test.sh
.\/test.shControleer of het contract compileert en de tests worden uitgevoerd.
Geweldig, nu bij het uitvoeren test.sh zal de compilatie en het uitvoeren van de tests direct plaatsvinden. Hier is de link naar .
Oké, voordat we verder gaan, laten we voor de duidelijkheid nog één ding doen.
Laten we een map aanmaken build waar we het gecompileerde contract en zijn kloon in een constante zullen opslaan. lottery-compiled.fif, lottery-compiled-for-test.fif. Laten we ook een map aanmaken test waar het bestand met de tests zal worden opgeslagen lottery-test-suite.fif en mogelijk andere ondersteunende bestanden. .
Laten we de ontwikkeling van het slimme contract voortzetten.
Verder moet er een test zijn die controleert of het bericht wordt ontvangen en de teller wordt bijgewerkt in de opslag wanneer we het juiste getal verzenden. Maar dat doen we later.
Laten we nu nadenken over wat de datastructuur is en welke gegevens in het slimme contract moeten worden opgeslagen.
Ik zal alles beschrijven wat we opslaan.
`seqno` een 32-bits positief geheel getal dat fungeert als teller.
`pubkey` een 256-bits positief geheel getal dat de publieke sleutel is waarmee we de handtekening van het ontvangen bericht van buitenaf zullen controleren, hierover later meer.
`order_seqno` een 32-bits positief geheel getal dat het aantal biedingen bijhoudt.
`number_of_wins` een 32-bits positief geheel getal dat het aantal overwinningen bijhoudt.
`incoming_amount` een datatype Gram (de eerste 4 bits geven de lengte aan), houdt het totale aantal gram bij dat naar het contract is verzonden.
`outgoing_amount` het totale aantal gram dat naar de winnaars is verzonden.
`owner_wc` het werkchain-nummer, een 32-bits (op sommige plaatsen wordt geschreven dat het 8-bits is) geheel getal. Momenteel zijn er maar twee -1 en 0.
`owner_account_id` een 256-bits positief geheel getal, het adres van het contract in de huidige werkchain.
`orders` een variabele van het type woordenboek, die de laatste twintig biedingen opslaat. Daarna moeten we twee functies schrijven. We noemen de eerste pack_state(), die de gegevens zal verpakken voor latere opslag in het smart contract. De tweede, die we unpack_state() noemen, zal de gegevens uitlezen en retourneren vanuit de opslag.
_ 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;
}We voegen deze twee functies aan het begin van het smart contract toe. Het resultaat wordt een tussenresultaat.
Om de gegevens op te slaan, moeten we de ingebouwde functie set_data() aanroepen en deze zal de gegevens opschrijven in pack_state() de opslag van het smart contract.
cell packed_state = pack_state(arg_1, .., arg_n);
set_data(packed_state);Nu we handige functies hebben voor het schrijven en lezen van gegevens, kunnen we verder gaan.
We moeten controleren of het binnenkomende bericht van buitenaf is ondertekend door de eigenaar van het contract (of een andere gebruiker die toegang heeft tot de privésleutel).
Wanneer we een smart contract publiceren, kunnen we het initialiseren met de gegevens die we in de opslag willen, die bewaard blijven voor toekomstig gebruik. We schrijven daar de publieke sleutel in, zodat we kunnen controleren of de handtekening van het binnenkomende bericht is gemaakt met de bijbehorende privésleutel.
Voordat we doorgaan, creëren we een privésleutel en schrijven deze naar test/keys/owner.pk. Hiervoor starten we Fift in interactieve modus en voeren we vier commando's uit.
`newkeypair` genereert een publieke en privésleutel en schrijft deze naar de stack.
`drop` verwijdert het bovenste element uit de stack (in dit geval de publieke sleutel)
`.s` laat gewoon zien wat er momenteel in de stack ligt
`"owner.pk" B>file` schrijft de privésleutel naar een bestand met de naam `owner.pk`.
`bye` beëindigt de sessie met Fift. Laten we een map aanmaken sleutels binnen de map test en daar schrijven we de privésleutel.
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
byeWe zien een bestand in de huidige map owner.pk.
We verwijderen de publieke sleutel uit de stack, wanneer nodig kunnen we deze uit de privésleutel ophalen.
Nu moeten we een handtekeningcontrole schrijven. Laten we beginnen met een test. Eerst lezen we de privésleutel uit het bestand met behulp van de functie file>B en schrijven deze naar de variabele owner_private_key, vervolgens gebruiken we de functie priv>pub om de privésleutel naar publiek om te zetten en schrijven we het resultaat naar 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 !We hebben beide sleutels nodig.
We initialiseren de opslag van het smart contract met willekeurige gegevens in dezelfde volgorde als in de functie pack_state()en schrijven deze naar de variabele opslag.
variabele eigenaar_privatesleutel
variabele eigenaar_publieksleutel
variabele bestellingen
variabele eigenaar_wc
variabele eigenaar_account_id
"./keys/eigenaar.pk" bestand>B eigenaar_privatesleutel !
eigenaar_privatesleutel @ priv>pub eigenaar_publieksleutel !
dictnieuw bestellingen !
0 eigenaar_wc !
0 eigenaar_account_id !
<b 0 32 u, owner_public_key @ b, gram, owner_wc i, owner_account_id 256 orders dict, b> opslag !Dan stellen we een ondertekend bericht samen, dat alleen de handtekening en de waarde van de teller bevat.
Eerst creëren we de gegevens die we willen verzenden, vervolgens ondertekenen we deze met de privésleutel en tenslotte vormen we het ondertekende bericht.
variabele message_to_sign
variabele message_to_send
variabele handtekening
<b 0 32 u, b> message_to_sign !
message_to_sign @ hashu owner_private_key @ ed25519_sign_uint handtekening !
<b signature @ b, 0 32 u, b> <s ! Uiteindelijk is het bericht dat we naar het smart contract zullen verzenden opgeslagen in de variabele message_to_send, over de functies hashu, ed25519_sign_uint kan hier worden gelezen .
En om de test opnieuw uit te voeren, roepen we weer aan.
message_to_send @
recv_external
code
storage @
c7
runvmctxhet bestand met tests zou er op dit moment zo uit moeten zien.
Laten we de test uitvoeren en hij zal falen, dus laten we het smart contract wijzigen, zodat het berichten van dit formaat kan ontvangen en de handtekening kan controleren.
Eerst lezen we 512 bits van de handtekening uit het bericht en slaan we deze op in een variabele, daarna lezen we 32 bits van de teller.
Aangezien we een functie hebben om gegevens uit de slimme contractopslag te lezen, zullen we deze gebruiken.
Vervolgens controleren we de teller die met de opslag is doorgegeven en controleren we de handtekening. Als iets niet klopt, gooien we een uitzondering met de bijbehorende code.
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));Bijbehorende commit .
We zullen de tests uitvoeren en zien dat de tweede test faalt. Om twee redenen: een gebrek aan bits in het bericht en een gebrek aan bits in de opslag, daarom faalt de code bij het parseren. We moeten de handtekening van het bericht dat we versturen toevoegen en de opslag van de laatste test kopiëren.
In de tweede test voegen we de handtekening van het bericht toe en wijzigen we de opslag van het slimme contract. dit is het huidige testbestand.
Laten we een vierde test schrijven, waarin we een bericht verzenden dat is ondertekend met een andere privé-sleutel. We creëren nog een privé-sleutel en slaan deze op in een bestand not-owner.pk. We ondertekenen het bericht met deze privésleutel. We voeren de tests uit en zorgen ervoor dat alle tests slagen. op dit moment.
Nu kunnen we eindelijk overgaan tot de implementatie van de logica van het slimme contract.
In recv_external() We zullen twee soorten berichten ontvangen.
Aangezien ons contract de verliezen van spelers zal accumuleren, moeten deze bedragen naar de maker van de loterij worden overgemaakt. Het adres van de portemonnee van de maker van de loterij wordt tijdens het maken van het contract in de opslag vastgelegd.
Voor alle gevallen hebben we de mogelijkheid nodig om het adres waar de verliezen naartoe moeten worden gestuurd te wijzigen. Ook moeten we in staat zijn om gram van de loterij naar het adres van de eigenaar te sturen.
Laten we met de eerste beginnen. We schrijven eerst een test die zal controleren of het slimme contract het nieuwe adres in de opslag heeft opgeslagen na het verzenden van het bericht. Let op dat we naast de teller en het nieuwe adres ook actie een 7-bits niet-negatief geheel getal doorgeven, afhankelijk daarvan zullen we kiezen hoe we het bericht in het slimme contract verwerken.
<b 0 32 u, 1 @ 7 new_owner_wc i, new_owner_account_id 256 b> bericht_om_teondertekenen !In de test is te zien hoe de deserialisatie van de opslag van het slimme contract plaatsvindt. opslag In Fift. De-serialisatie van variabelen is beschreven in de documentatie van Fift.
met toevoeging van een test.
We starten de test en zorgen ervoor dat deze faalt. Laten we nu de logica voor het wijzigen van het adres van de loterij-eigenaar toevoegen.
In het slimme contract blijven we parsen bericht, lezen in actie. Laten we herinneren dat we twee zullen hebben actie: het wijzigen van het adres en het verzenden van grams.
Vervolgens lezen we het nieuwe adres van de contracteigenaar en slaan dit op in de opslag.
We starten de tests en zien dat de derde test faalt. Dit faalt omdat het contract nu extra 7 bits uit het bericht parseert, die ontbreken in de test. Laten we een niet-bestaande toevoegen aan het bericht actie. We starten de tests en zien dat alles slaagt. commit voor de wijzigingen. Geweldig.
Laten we nu de logica schrijven voor het verzenden van het opgegeven aantal grams naar het eerder opgeslagen adres.
Laten we eerst een test schrijven. We zullen twee tests schrijven, één wanneer het saldo niet voldoende is, en de tweede wanneer alles succesvol zou moeten verlopen. De tests kunnen worden bekeken .
Laten we nu de code aanvullen. Laten we eerst twee hulpfuncties schrijven. De eerste is een get-functie om het huidige saldo van het slimme contract te achterhalen.
int balance() inline_ref method_id {
return get_balance().pair_first();
}En de tweede om grams naar een ander slim contract te verzenden. Deze methode heb ik volledig gekopieerd uit een ander slim contract.
() 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 uitgeschakeld
;; .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 werkchain
.store_uint (196, 9)
.store_int(wc, 8)
.store_uint(addr, 256)
.store_grams(grams)
.store_uint(0, 107) ;; 106 nullen + 0 als indicator dat er geen cel met de data is.
.end_cell();
send_raw_message(msg, 3); ;; mode, 2 voor het negeren van fouten, 1 voor zender betaalt kosten, 64 voor het retourneren van de waarde van het binnenkomende bericht
}Laten we deze twee methoden in het slimme contract voegen en de logica schrijven. Laten we eerst het aantal grams uit het bericht parsen. Vervolgens controleren we het saldo, als dit niet voldoende is, gooien we een uitzondering. Als alles goed gaat, sturen we grams naar het opgeslagen adres en werken we de teller bij.
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));dit is hoe het slimme contract er op dit moment uitziet. Laten we de tests uitvoeren en ervoor zorgen dat ze slagen.
Overigens wordt er elke keer een vergoeding in rekening gebracht voor het verwerkte bericht van het smart contract. Om de berichten te laten uitvoeren, moeten we na de basiscontroles accept_message().
Laten we nu de interne berichten behandelen. In feite zullen we alleen grammen ontvangen en terugsturen naar de speler in dubbele hoeveelheid bij winst en een derde aan de eigenaar bij verlies.
Laten we eerst een eenvoudige test schrijven. Hiervoor hebben we een testadres van het smart contract nodig waarvandaan we zogenaamd grammen naar het smart contract sturen.
Het adres van het smart contract bestaat uit twee getallen, een 32-bits geheel getal dat verantwoordelijk is voor de werkchain en een 256-bits uniek niet-negatief accountnummer in die werkchain. Bijvoorbeeld, -1 en 12345, dit adres slaan we op in een bestand.
Ik heb de functie voor het opslaan van het adres gekopieerd uit .
// ( wc addr fname -- ) Save address to file in 36-byte format
{ -rot 256 u>B swap 32 i>B B+ swap B>file } : save-addressLaten we analyseren hoe de functie werkt, dit geeft ons inzicht in hoe Fift werkt. We starten Fift in interactieve modus.
~\/TON\/build\/crypto\/fift -i Eerst plaatsen we -1, 12345 en de naam van het toekomstige bestand "sender.addr":
-1 12345 "sender.addr" De volgende stap is het uitvoeren van de functie -rot, die de stack verschuift, zodat het unieke nummer van het smart contract bovenop de stack komt:
"sender.addr" -1 12345256 u>B converteert het 256-bits niet-negatieve geheel getal naar bytes.
"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039swap verandert de plaats van de twee bovenste elementen van de stack.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -132 i>B converteert het 32-bits geheel getal naar bytes.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFFB+ voegt twee byte-sequenties samen.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFFWeer swap.
BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" En eindelijk wordt het schrijven van bytes naar het bestand uitgevoerd B>file. Daarna is onze stack leeg. We stoppen Fift. In de huidige map is een bestand aangemaakt sender.addr. We verplaatsen het bestand naar de gemaakte map test\/addresses\/.
Laten we een eenvoudige test schrijven die grammen naar het smart contract zal verzenden. .
Laten we nu de logica van de loterij behandelen.
Het eerste wat we doen, is controleren of het bericht bounced of niet, als bounced, dan negeren we het. bounced dit betekent dat het contract grammen zal teruggeven als er een fout optreedt. We zullen grammen niet teruggeven als er plotseling een fout optreedt.
We controleren het saldo; als het minder is dan een halve gram, accepteren we gewoon het bericht en negeren we het.
Vervolgens parsers we het adres van het smart contract waarvan het bericht afkomstig is.
We lezen de gegevens uit de opslag en verwijderen vervolgens oude inzetten uit de geschiedenis als er meer dan twintig zijn. Voor gemak heb ik drie extra functies geschreven pack_order(), unpack_order(), remove_old_orders().
Daarna controleren we of het saldo voldoende is voor de uitbetaling; indien niet, beschouwen we het als een aanvulling en slaan we de aanvulling op in orders.
Vervolgens komt de essentie van het smart contract.
Eerst, als de speler verliest, slaan we hem op in de geschiedenis van inzetten en als het bedrag meer dan 3 gram is, sturen we 1/3 naar de eigenaar van het smart contract.
Als de speler wint, sturen we het dubbele bedrag naar het adres van de speler en slaan we vervolgens de informatie over de inzet op in de geschiedenis.
() 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) { ;; negeer bounced
return ();
}
if (order_amount < 500000000) { ;; ontvang gewoon grams zonder de toestand te veranderen
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));
}Dat is alles. .
Nu blijft het eenvoudig: we maken get-methoden zodat informatie over de status van het contract vanuit de externe wereld kan worden verkregen (in feite de gegevens uit de opslag van het smart contract lezen).
. We zullen hieronder beschrijven hoe informatie over het smart contract kan worden verkregen.
Ik ben ook vergeten de code toe te voegen die de eerste aanvraag zal verwerken die plaatsvindt bij het publiceren van het slimme contract. . En daarnaast is er een bug bij het overmaken van 1/3 van het bedrag naar het account van de eigenaar.
Daarna blijft het om het slimme contract te publiceren. Laten we een map aanmaken requests.
Ik heb de publicatiecode als basis genomen die in de officiële repository.
Waar we op moeten letten. We vormen de opslag van het slimme contract en de invoermelding. Daarna wordt het adres van het slimme contract gegenereerd, dat wil zeggen dat het adres al bekend is voordat het in TON wordt gepubliceerd. Vervolgens moet er een aantal grams naar dit adres worden verzonden en pas daarna moet het bestand met het slimme contract zelf worden verzonden, omdat het netwerk commissie in rekening brengt voor het opslaan van het slimme contract en de uitvoering ervan (validators die de slimme contracten opslaan en uitvoeren). .
Vervolgens voeren we de publicatiecode uit en ontvangen we lottery-query.boc het bestand en het adres van het slimme contract.
~\/TON\/build\/crypto\/fift -s requests\/new-lottery.fif 0Vergeet niet de gegenereerde bestanden op te slaan: lottery-query.boc, lottery.addr, lottery.pk.
Daarnaast zien we in de uitvoerlogs het adres van het slimme contract.
new wallet address = 0:044910149dbeaf8eadbb2b28722e7d6a2dc6e264ec2f1d9bebd6fb209079bc2a
(Adres opslaan in bestand lottery.addr)
Niet-bouncebaar adres (voor initiatie): 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd
Bouncebaar adres (voor latere toegang): kQAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KpFYVoor de interesse doen we een aanvraag in TON
$ .\/lite-client\/lite-client -C ton-lite-client-test1.config.json
getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydEn we zullen zien dat het account met dat adres leeg is.
account status is leegWe sturen naar het adres 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 Gram en na enkele seconden voeren we dezelfde opdracht opnieuw uit. Voor het verzenden van grams gebruik ik , en test grams kunnen worden gevraagd aan iemand uit de chat, waarover ik aan het einde van het artikel zal zeggen.
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydKijkt of er in het netwerk een niet-geïnitialiseerd (state:account_uninit) slim contract met dat adres en een saldo van 1 000 000 000 nanogram is verschenen.
account status 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 2000000000ngLaten we het smart contract publiceren. We starten de lite-client en voeren het uit.
> sendfile lottery-query.boc
[ 1][t 2][1583008371.631410122][lite-client.cpp:966][!testnode] verzenden query uit bestand lottery-query.boc
[ 3][t 1][1583008371.828550100][lite-client.cpp:976][!query] externe berichtstatus is 1 Laten we controleren of het contract gepubliceerd is.
> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydOnder andere ontvangen we.
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_activeWe zien dat account_active.
De overeenkomstige commit met wijzigingen .
Laten we nu verzoeken creëren voor interactie met het smart contract.
Specifieker, de eerste voor adreswijziging laten we als zelfstandige taak, en de tweede voor het verzenden van grams naar het adres van de eigenaar maken we. In feite moeten we hetzelfde doen als in de test voor het verzenden van grams.
Dit soort bericht zullen we naar het smartcontract sturen, waar msg_seqno 165, actie 2 en 9.5 grams voor verzending.
<b 165 32 u, 2 7 9500000000 gram, b>Vergeet niet het bericht te ondertekenen met de privésleutel lottery.pk, die eerder is gegenereerd bij het maken van het smart contract. .
We verkrijgen informatie uit het smart contract met behulp van de get-methoden
Laten we nu kijken hoe we de get-methoden van het smart contract kunnen starten.
We starten lite-client en we starten de get-methoden die we hebben geschreven.
$ ./lite-client/lite-client -C ton-lite-client-test1.config.json
> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd balance
argumenten: [ 104128 ]
resultaat: [ 64633878952 ]
...In resultaat bevat de waarde die de functie retourneert balance() uit ons smart contract.
Hetzelfde doen we ook voor een aantal andere methoden.
> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_seqno
...
argumenten: [ 77871 ]
resultaat: [ 1 ] Laten we de geschiedenis van inzet verzoeken.
> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_orders
...
argumenten: [ 67442 ]
resultaat: [ ([0 1 1583258284 10000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [1 3 1583258347 4000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [2 1 1583259901 50000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308]) ] We zullen de lite-client en GET-methoden gebruiken om informatie over het smart contract op de website weer te geven.
We tonen de gegevens van het smart contract op de website.
Ik heb een eenvoudige website in Python geschreven om de gegevens van het smart contract op een gebruiksvriendelijke manier te tonen. Hier zal ik niet in detail treden en de website publiceren. .
Verzoeken naar TON worden gemaakt vanuit. Python met behulp van lite-client. Voor het gemak wordt de website verpakt in Docker en gepubliceerd op Google Cloud. .
Laten we het proberen.
Laten we nu proberen daar grams naartoe te sturen ter aanvulling vanuit. . We zullen 40 grams verzenden en een paar inzetten voor de illustratie. We zien dat de website de inzetgeschiedenis, de huidige winpercentages en andere nuttige informatie toont.
, dat we de eerste hebben gewonnen, de tweede verloren.
Naschrift
Dit artikel is veel langer geworden dan ik had verwacht; misschien had het korter gekund, maar het kan juist nuttig zijn voor iemand die niets weet over TON en niet het meest eenvoudige smart contract wil schrijven en publiceren met de mogelijkheid om ermee te interageren. Misschien hadden sommige dingen eenvoudiger uitgelegd kunnen worden.
Misschien konden sommige aspecten van de implementatie efficiënter en eleganter worden gedaan, maar dan zou het nog meer tijd kosten om het artikel voor te bereiden. Ook is het mogelijk dat ik ergens een fout heb gemaakt of iets niet heb begrepen, dus als je iets serieus doet, moet je je baseren op de officiële documentatie of de officiële repository met de TON code.
Het is belangrijk op te merken dat TON nog in actieve ontwikkeling is, en er kunnen veranderingen plaatsvinden die een van de stappen in dit artikel kunnen breken (wat gebeurde terwijl ik dit schreef, ik heb het al gecorrigeerd), maar de algemene aanpak zal waarschijnlijk niet veranderen.
Ik ga het niet hebben over de toekomst van TON. Misschien wordt het platform iets groters en is het de moeite waard om nu tijd te investeren in het leren ervan en om nu al een niche te vullen met onze producten.
Er is ook Libra van Facebook, waarvan de potentiële gebruikersbasis groter is dan die van TON. Ik weet bijna niets over Libra, maar volgens het forum is de activiteit daar veel hoger dan in de TON gemeenschap. Hoewel de ontwikkelaars en de TON gemeenschap meer op de ondergrond lijken, wat ook cool is.
Links
- Officiële documentatie over TON:
- Officiële repository van TON:
- Officiële wallet voor verschillende platforms:
- Repository van het smart contract uit dit artikel:
- Link naar de website van het smart contract:
- Repository voor de extensie voor Visual Studio Code voor FunC:
- Een Telegram-chat over TON, die echt heeft geholpen om de basics te begrijpen. Het zou geen fout zijn om te zeggen dat iedereen die iets voor TON heeft geschreven daar aanwezig is. Je kunt daar ook om testgrammen vragen.
- Nog een chat over TON waarin ik nuttige informatie heb gevonden:
- Eerste fase van de wedstrijd:
- Tweede fase van de wedstrijd:
Bron: habr.com
