Over het schrijven en publiceren van een slim contract in TON
Waar gaat dit artikel over?
In het artikel zal ik vertellen hoe ik deelnam aan de eerste (van twee) Telegram-blockchainwedstrijd, geen prijs won en besloot mijn ervaring in een artikel vast te leggen, zodat deze niet in de vergetelheid raakt en misschien helpt iemand.
Omdat ik geen abstracte code wilde schrijven, maar iets werkends wilde doen, schreef ik voor het artikel een slim contract voor een onmiddellijke loterij en een website die slimme contractgegevens rechtstreeks van TON toont zonder gebruik te maken van tussentijdse opslag.
Het artikel zal nuttig zijn voor degenen die hun eerste slimme contract in TON willen maken, maar niet weten waar ze moeten beginnen.
Met de loterij als voorbeeld ga ik van het installeren van de omgeving naar het publiceren van een slim contract, de interactie ermee en het schrijven van een website voor het ontvangen en publiceren van gegevens.
Over deelname aan de competitie
Afgelopen oktober kondigde Telegram een blockchain-wedstrijd met nieuwe talen aan Fift и FunC. Het was noodzakelijk om te kiezen uit het schrijven van een van de vijf voorgestelde slimme contracten. Het leek mij leuk om iets anders te doen, een taal te leren en iets te maken, ook al hoef ik in de toekomst niets anders te schrijven. Bovendien ligt het onderwerp voortdurend op de lippen.
Het is de moeite waard om te zeggen dat ik geen ervaring had met het ontwikkelen van slimme contracten.
Ik was van plan om tot het einde mee te doen totdat ik kon en daarna een recensieartikel te schrijven, maar bij het eerste faalde ik meteen. I met multi-handtekening ingeschakeld FunC en het werkte over het algemeen. Ik heb het als basis genomen .
Destijds dacht ik dat dit zeker genoeg was om op zijn minst een prijsplaats te veroveren. Als gevolg hiervan werden ongeveer 40 van de 60 deelnemers prijswinnaars en ik behoorde daar niet toe. Over het algemeen is hier niets mis mee, maar één ding stoorde me. Op het moment dat de resultaten bekend werden gemaakt, was de beoordeling van de test voor mijn contract nog niet gedaan. Ik vroeg de deelnemers aan de chat of er iemand anders was die deze niet had, die waren er niet.
Blijkbaar met aandacht voor mijn berichten, publiceerden de juryleden twee dagen later een commentaar en ik begrijp nog steeds niet of ze tijdens de jurering per ongeluk mijn slimme contract hebben gemist of simpelweg dachten dat het zo erg was dat het geen commentaar nodig had. Ik stelde een vraag op de pagina, maar kreeg geen antwoord. Hoewel het geen geheim is wie er oordeelde, vond ik het niet nodig om persoonlijke berichten te schrijven.
Er werd veel tijd besteed aan begrip, dus werd besloten een artikel te schrijven. Omdat er nog niet veel informatie is, zal dit artikel tijd besparen voor alle geïnteresseerden.
Het concept van slimme contracten in TON
Voordat je iets schrijft, moet je uitzoeken van welke kant je dit ding moet benaderen. Daarom zal ik je nu vertellen uit welke delen het systeem bestaat. Meer precies, welke onderdelen u moet weten om op zijn minst een soort arbeidscontract te schrijven.
We zullen ons concentreren op het schrijven van een slim contract en het werken ermee TON Virtual Machine (TVM), Fift и FunC, dus het artikel lijkt meer op een beschrijving van de ontwikkeling van een regulier programma. We zullen hier niet stilstaan bij hoe het platform zelf werkt.
In het algemeen over hoe het werkt TVM en taal Fift er is goede officiële documentatie. Tijdens de deelname aan de wedstrijd en nu tijdens het schrijven van het huidige contract wendde ik mij vaak tot haar.
De belangrijkste taal waarin slimme contracten worden geschreven is FunC. Er is momenteel geen documentatie over, dus om iets te schrijven moet je voorbeelden van slimme contracten uit de officiële repository en de implementatie van de taal zelf daar bestuderen, en je kunt voorbeelden van slimme contracten uit de afgelopen twee bekijken. wedstrijden. Links aan het einde van het artikel.
Laten we zeggen dat we al een slim contract hebben geschreven FunC, daarna compileren we de code in Fift assembler.
Het samengestelde slimme contract moet nog worden gepubliceerd. Om dit te doen moet je een functie inschrijven Fift, die de slimme contractcode en enkele andere parameters als invoer zal gebruiken, en de uitvoer zal een bestand zijn met de extensie .boc (wat ‘zak met cellen’ betekent), en, afhankelijk van hoe we het schrijven, een privésleutel en adres, die worden gegenereerd op basis van de slimme contractcode. Je kunt nu al grammen sturen naar het adres van een slim contract dat nog niet is gepubliceerd.
Om een slim contract te publiceren in TON ontvangen .boc het bestand moet met een light-client naar de blockchain worden verzonden (meer daarover hieronder). Maar voordat u publiceert, moet u grammen overbrengen naar het gegenereerde adres, anders wordt het slimme contract niet gepubliceerd. Na publicatie kunt u met het slimme contract communiceren door het berichten van buitenaf te sturen (bijvoorbeeld met behulp van een light client) of van binnenuit (het ene slimme contract stuurt bijvoorbeeld een ander slim contract binnen TON).
Zodra we begrijpen hoe de code wordt gepubliceerd, wordt het eenvoudiger. We weten ongeveer wat we willen schrijven en hoe ons programma zal werken. En al schrijvend zoeken we hoe dit al geïmplementeerd is in bestaande slimme contracten, of we kijken in de implementatiecode Fift и FunC in de officiële repository, of kijk in de officiële documentatie.
Heel vaak zocht ik naar trefwoorden in de Telegram-chat waar alle wedstrijddeelnemers en Telegram-medewerkers samenkwamen, en het gebeurde zo dat tijdens de wedstrijd iedereen daar samenkwam en over Fift en FunC begon te praten. Link aan het einde van het artikel.
Het is tijd om van theorie naar praktijk te gaan.
Het voorbereiden van de omgeving op het werken met TON
Ik heb alles gedaan wat in het artikel over macOS wordt beschreven en het vervolgens nogmaals gecontroleerd op een schone installatie. Ubuntu 18.04 LTS op Docker.
Het eerste dat u hoeft te doen, is downloaden en installeren lite-client waarmee je verzoeken naar TON kunt sturen.
De instructies op de officiële website beschrijven het installatieproces vrij uitgebreid en duidelijk, hoewel sommige details worden weggelaten. We volgen hier de instructies en installeren gaandeweg alle ontbrekende afhankelijkheden. Ik heb niet elk project zelf gecompileerd, maar heb alles vanuit de officiële repository geïnstalleerd. Ubuntu (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 Zodra alle afhankelijkheden zijn geïnstalleerd, kunt u installeren lite-client, Fift, FunC.
Eerst klonen we de TON-repository samen met zijn afhankelijkheden. Voor het gemak doen we alles in een map ~/TON.
cd ~/TON
git clone https://github.com/ton-blockchain/ton.git
cd ./ton
git submodule update --init --recursiveIn de repository worden ook implementaties opgeslagen Fift и FunC.
Nu zijn we klaar om het project samen te stellen. De repositorycode wordt naar een map gekloond ~/TON/ton. In ~/TON maak een map build en verzamel het project daarin.
mkdir ~/TON/build
cd ~/TON/build
cmake ../tonOmdat we een slim contract gaan schrijven, hebben we dat niet alleen nodig lite-clientMaar Fift с FunC, dus laten we alles compileren. Het is geen snel proces, dus we wachten af.
cmake --build . --target lite-client
cmake --build . --target fift
cmake --build . --target funcDownload vervolgens het configuratiebestand dat gegevens bevat over het knooppunt waarnaar lite-client zal verbinden.
wget https://test.ton.org/ton-lite-client-test1.config.jsonHet doen van de eerste verzoeken aan TON
Laten we nu lanceren lite-client.
cd ~/TON/build
./lite-client/lite-client -C ton-lite-client-test1.config.jsonAls de build succesvol is geweest, ziet u na de lancering een logboek van de verbinding van de light client met het knooppunt.
[ 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)
...U kunt de opdracht uitvoeren help en kijk welke commando's beschikbaar zijn.
helpLaten we de opdrachten vermelden die we in dit artikel zullen gebruiken.
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 parameterslast получает последний созданный блок с сервера.
sendfile <filename> отправляет в TON файл с сообщением, именно с помощью этой команды публикуется смарт-контракт и запрсосы к нему.
getaccount <addr> загружает текущее состояние смарт-контракта с указанным адресом.
runmethod <addr> [<block-id-ext>] <method-id> <params> запускает get-методы смартконтракта. Nu zijn we klaar om het contract zelf te schrijven.
uitvoering
Idee
Zoals ik hierboven schreef, is het slimme contract dat we schrijven een loterij.
Bovendien is dit geen loterij waarbij je een lot moet kopen en een uur, dag of maand moet wachten, maar een instantloterij waarbij de gebruiker overgaat naar het contractadres N gram, en krijgt het onmiddellijk terug 2 * N gram of verliest. We maken de kans om te winnen ongeveer 40%. Indien er niet genoeg grammen zijn voor betaling, beschouwen wij de transactie als een opwaardering.
Bovendien is het belangrijk dat weddenschappen realtime en in een handige vorm te zien zijn, zodat de gebruiker direct kan zien of hij gewonnen of verloren heeft. Daarom moet u een website maken die weddenschappen en resultaten rechtstreeks van TON toont.
Een slim contract schrijven
Voor het gemak heb ik de code voor FunC uitgelicht; de plug-in is te vinden en te installeren in de Visual Studio Code-zoekopdracht; mocht je ineens iets willen toevoegen, dan heb ik de plug-in openbaar beschikbaar gemaakt. Ook heeft iemand eerder een plugin gemaakt voor het werken met Fift, deze kun je ook installeren en terugvinden in VSC.
Laten we onmiddellijk een repository maken waar we de tussenresultaten vastleggen.
Om ons leven gemakkelijker te maken, zullen we een slim contract schrijven en dit lokaal testen totdat het klaar is. Pas daarna publiceren we het in TON.
Het slimme contract heeft twee externe methoden waartoe toegang kan worden verkregen. Eerst, recv_external() deze functie wordt uitgevoerd wanneer een verzoek om het contract van de buitenwereld komt, dat wil zeggen niet van TON, bijvoorbeeld wanneer wij zelf een bericht genereren en dit via de lite-client verzenden. Seconde, recv_internal() dit is wanneer, binnen TON zelf, elk contract naar het onze verwijst. In beide gevallen kunt u parameters aan de functie doorgeven.
Laten we beginnen met een eenvoudig voorbeeld dat zal werken als het wordt gepubliceerd, maar er zit geen functionele belasting in.
() recv_internal(slice in_msg) impure {
;; TODO: implementation
}
() recv_external(slice in_msg) impure {
;; TODO: implementation
}Hier moeten we uitleggen wat het is slice. Alle gegevens die in TON Blockchain zijn opgeslagen, vormen een verzameling TVM cell of gewoon cell, in zo'n cel kun je maximaal 1023 bits aan gegevens opslaan en maximaal 4 koppelingen naar andere cellen.
TVM cell slice of slice dit maakt deel uit van de bestaande cell wordt gebruikt om het te ontleden, zal later duidelijk worden. Het belangrijkste voor ons is dat we kunnen overstappen slice en, afhankelijk van het type bericht, de gegevens verwerken recv_external() of recv_internal().
impure — een trefwoord dat aangeeft dat de functie slimme contractgegevens wijzigt.
Laten we de contractcode opslaan lottery-code.fc en compileren.
~/TON/build/crypto/func -APSR -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fc De betekenis van de vlaggen kan worden bekeken met behulp van het commando
~/TON/build/crypto/func -helpWe hebben de Fift-assemblercode gecompileerd 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>cHet kan lokaal gelanceerd worden, hiervoor gaan wij de omgeving voorbereiden.
Merk op dat de eerste lijn verbinding maakt Asm.fif, dit is code geschreven in Fift voor de Fift-assembler.
Omdat we het slimme contract lokaal willen uitvoeren en testen, zullen we een bestand aanmaken lottery-test-suite.fif en kopieer de gecompileerde code daarheen, waarbij u de laatste regel daarin vervangt, die de slimme contractcode naar een constante schrijft codeom het vervolgens over te dragen naar de virtuele machine:
"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
Tot nu toe lijkt het duidelijk, laten we nu aan hetzelfde bestand de code toevoegen die we zullen gebruiken om TVM te starten.
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 we leggen de context vast, dat wil zeggen de gegevens waarmee de TVM (of netwerkstatus) wordt gelanceerd. Zelfs tijdens de wedstrijd liet een van de ontwikkelaars zien hoe je moest creëren c7 en ik heb gekopieerd. In dit artikel moeten we misschien veranderen rand_seed aangezien het genereren van een willekeurig getal ervan afhangt en als het niet wordt gewijzigd, zal hetzelfde getal elke keer worden geretourneerd.
recv_internal и recv_external constanten met waarden 0 en -1 zijn verantwoordelijk voor het aanroepen van de overeenkomstige functies in het slimme contract.
Nu zijn we klaar om de eerste test voor ons lege slimme contract te maken. Voor de duidelijkheid: voorlopig zullen we alle tests aan hetzelfde bestand toevoegen lottery-test-suite.fif.
Laten we een variabele maken storage en schrijf er een lege in cell, dit zal de slimme contractopslag zijn.
message Dit is de boodschap die we van buitenaf naar het slimme contact zullen overbrengen. Wij maken hem voorlopig ook leeg.
variable storage
<b b> storage !
variable message
<b b> message ! Nadat we de constanten en variabelen hebben voorbereid, starten we TVM met behulp van de opdracht runvmctx en geef de gemaakte parameters door aan de invoer.
message @
recv_external
code
storage @
c7
runvmctx Uiteindelijk zullen we slagen tussencode voor Fift.
Nu kunnen we de resulterende code uitvoeren.
export FIFTPATH=~/TON/ton/crypto/fift/lib // выполняем один раз для удобства
~/TON/build/crypto/fift -s lottery-test-suite.fif Het programma zou zonder fouten moeten werken en in de uitvoer zullen we het uitvoeringslogboek zien:
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=0Geweldig, we hebben de eerste werkende versie van het slimme contract geschreven.
Nu moeten we functionaliteit toevoegen. Laten we eerst eens kijken naar de berichten die van de buitenwereld komen recv_external()
De ontwikkelaar kiest zelf het berichtformaat dat het contract kan accepteren.
Maar gewoonlijk
- ten eerste willen we ons contract beschermen tegen de buitenwereld en het zo maken dat alleen de eigenaar van het contract er externe berichten naar kan sturen.
- ten tweede, als we een geldig bericht naar TON sturen, willen we dat dit precies één keer gebeurt en als we hetzelfde bericht opnieuw sturen, wijst het slimme contract dit af.
Dus bijna elk contract lost deze twee problemen op, aangezien ons contract externe berichten accepteert, moeten we daar ook voor zorgen.
We doen het in omgekeerde volgorde. Laten we eerst het probleem van de herhaling oplossen; als het contract een dergelijk bericht al heeft ontvangen en verwerkt, zal het het niet een tweede keer uitvoeren. En dan zullen we het probleem oplossen, zodat alleen een bepaalde kring van mensen berichten naar het slimme contract kan sturen.
Er zijn verschillende manieren om het probleem met dubbele berichten op te lossen. Hier is hoe we het zullen doen. In het slimme contract initialiseren we de teller van ontvangen berichten met de initiële waarde 0. In elk bericht aan het slimme contract voegen we de huidige tellerwaarde toe. Als de tellerwaarde in het bericht niet overeenkomt met de waarde in het slimme contract, verwerken we deze niet; als dat wel het geval is, verwerken we deze en verhogen we de teller in het slimme contract met 1.
Wij keren terug naar lottery-test-suite.fif en voeg er een tweede test aan toe. Als we een onjuist nummer verzenden, moet de code een uitzondering genereren. Laat de contractgegevens bijvoorbeeld 166 opslaan, dan sturen wij 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"Laten we lanceren.
~/TON/build/crypto/fift -s lottery-test-suite.fif En we zullen zien dat de test wordt uitgevoerd met een fout.
[ 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 passedIn dit stadium lottery-test-suite.fif eruit zou moeten zien .
Laten we nu de tegenlogica aan het slimme contract toevoegen 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 ligt de boodschap die we sturen.
Het eerste wat we doen is controleren of het bericht gegevens bevat, zo niet, dan sluiten we gewoon af.
Vervolgens analyseren we het bericht. in_msg~load_uint(32) laadt het getal 165, 32-bit unsigned int uit het verzonden bericht.
Vervolgens laden we 32 bits uit de slimme contractopslag. We controleren of het geladen getal overeenkomt met het doorgegeven getal; zo niet, dan genereren we een uitzondering. In ons geval zou er, aangezien we een non-match passeren, een uitzondering moeten worden gegenereerd.
Laten we nu compileren.
~/TON/build/crypto/func -APSR -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fc Kopieer de resulterende code naar lottery-test-suite.fif, en vergeet niet de laatste regel te vervangen.
We controleren of de test slaagt:
~/TON/build/crypto/fift -s lottery-test-suite.fifU kunt de bijbehorende commit zien met de huidige resultaten.
Houd er rekening mee dat het lastig is om de gecompileerde code van een slim contract voortdurend naar een bestand met tests te kopiëren, dus we zullen een script schrijven dat de code voor ons in een constante zal schrijven, en we zullen de gecompileerde code eenvoudigweg aan onze tests koppelen met behulp van "include".
Maak een bestand in de projectmap 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.shVoer nu gewoon ons script uit om het contract samen te stellen. Maar daarnaast moeten we het in een constante schrijven code. We zullen dus een nieuw bestand maken lotter-compiled-for-test.fif, die we in het bestand zullen opnemen lottery-test-suite.fif.
Laten we skirpt-code toevoegen aan sh, waardoor het gecompileerde bestand eenvoudigweg wordt gedupliceerd lotter-compiled-for-test.fif en verander de laatste regel erin.
# 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.fifOm dit te controleren, laten we nu het resulterende script uitvoeren en er zal een bestand worden gegenereerd lottery-compiled-for-test.fif, die we zullen opnemen in onze lottery-test-suite.fif
В lottery-test-suite.fif verwijder de contractcode en voeg de regel toe "lottery-compiled-for-test.fif" include.
We voeren tests uit om te controleren of ze slagen.
~/TON/build/crypto/fift -s lottery-test-suite.fifGeweldig, laten we nu een bestand maken om het starten van tests te automatiseren test.sh, die als eerste wordt uitgevoerd build.shen voer vervolgens de tests uit.
touch test.sh
chmod +x test.shWij schrijven binnen
./build.sh
echo "nCompilation completedn"
export FIFTPATH=~/TON/ton/crypto/fift/lib
~/TON/build/crypto/fift -s lottery-test-suite.fifLaten we het doen test.sh en voer het uit om te controleren of de tests werken.
chmod +x ./test.sh
./test.shWij controleren of het contract tot stand komt en de tests worden uitgevoerd.
Geweldig, nu bezig met opstarten test.sh De tests worden onmiddellijk samengesteld en uitgevoerd. Hier is de link naar .
Oké, voordat we verder gaan, laten we voor het gemak nog één ding doen.
Laten we een map maken build waar we het gekopieerde contract en de kloon ervan in een constante zullen opslaan lottery-compiled.fif, lottery-compiled-for-test.fif. Laten we ook een map maken test waar wordt het testbestand opgeslagen? lottery-test-suite.fif en mogelijk andere ondersteunende bestanden. .
Laten we doorgaan met het ontwikkelen van het slimme contract.
Vervolgens moet er een test plaatsvinden die controleert of het bericht is ontvangen en dat de teller in de winkel wordt bijgewerkt wanneer we het juiste nummer verzenden. Maar dat doen we later.
Laten we nu eens nadenken over welke datastructuur en welke gegevens moeten worden opgeslagen in het slimme contract.
Ik zal alles beschrijven wat we opslaan.
`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` переменная типа словарь, хранит последние двадцать ставок. Vervolgens moet je twee functies schrijven. Laten we de eerste bellen pack_state(), die de gegevens zal inpakken voor latere opslag in de slimme contractopslag. Laten we de tweede bellen unpack_state() zal gegevens uit de opslag lezen en retourneren.
_ 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 toe aan het begin van het slimme contract. Het zal werken tussen resultaat.
Om gegevens op te slaan, moet u de ingebouwde functie oproepen set_data() en er zullen gegevens uit worden geschreven pack_state() in de slimme contractopslag.
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.
We moeten controleren of het bericht dat van buitenaf binnenkomt, is ondertekend door de eigenaar van het contract (of een andere gebruiker die toegang heeft tot de privésleutel).
Wanneer we een slim contract publiceren, kunnen we dit initialiseren met de gegevens die we nodig hebben in de opslag en die worden opgeslagen voor toekomstig gebruik. We zullen de publieke sleutel daar vastleggen, zodat we kunnen verifiëren dat het binnenkomende bericht is ondertekend met de bijbehorende privésleutel.
Voordat we verder gaan, maken we een privésleutel en schrijven deze ernaar test/keys/owner.pk. Om dit te doen, starten we Fift in de interactieve modus en voeren we vier opdrachten uit.
`newkeypair` генерация публичного и приватного ключа и запись их в стек.
`drop` удаления из стека верхнего элемента (в данном случае публичный ключ)
`.s` просто посмотреть что лежит в стеке в данный момент
`"owner.pk" B>file` запись приватного ключа в файл с именем `owner.pk`.
`bye` завершает работу с Fift. Laten we een map maken keys in de map test en schrijf daar 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 stapel en wanneer nodig kunnen we deze van de privésleutel halen.
Nu moeten we een handtekeningverificatie schrijven. Laten we beginnen met de test. Eerst lezen we de privésleutel uit het bestand met behulp van de functie file>B en schrijf het naar een variabele owner_private_keyen gebruik vervolgens de functie priv>pub converteer de privésleutel naar een openbare sleutel en schrijf het resultaat erin 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 slimme contractopslag met willekeurige gegevens in dezelfde volgorde als in de functie pack_state()en schrijf het in een variabele 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 !Vervolgens stellen we een ondertekend bericht op, dit bevat alleen de handtekening en de tellerwaarde.
Eerst creëren we de gegevens die we willen verzenden, vervolgens ondertekenen we deze met een privésleutel en ten slotte genereren we een ondertekend bericht.
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 ! Als gevolg hiervan wordt het bericht dat we naar het slimme contract sturen, vastgelegd in een variabele message_to_send, over functies hashu, ed25519_sign_uint jij kunt lezen .
En om de test uit te voeren bellen we opnieuw.
message_to_send @
recv_external
code
storage @
c7
runvmctxHet bestand met tests zou er in dit stadium zo uit moeten zien.
Laten we de test uitvoeren en deze zal mislukken. Daarom zullen we het slimme contract wijzigen zodat het berichten van dit formaat kan ontvangen en de handtekening kan verifiëren.
Eerst tellen we 512 bits van de handtekening van het bericht en schrijven deze naar een variabele, daarna tellen we 32 bits van de tellervariabele.
Omdat we een functie hebben voor het uitlezen van gegevens uit de slimme contractopslag, zullen we deze gebruiken.
Vervolgens wordt de met de opslag overgedragen teller gecontroleerd en de handtekening gecontroleerd. Als iets niet overeenkomt, genereren we een uitzondering met de juiste 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));Relevante verplichting .
Laten we de tests uitvoeren en zien dat de tweede test mislukt. Om twee redenen zijn er niet genoeg bits in het bericht en zijn er niet genoeg bits in de opslag, waardoor de code crasht tijdens het parseren. We moeten een handtekening toevoegen aan het bericht dat we verzenden en de opslag van de laatste test kopiëren.
In de tweede test zullen we een berichthandtekening toevoegen en de slimme contractopslag wijzigen. het bestand met tests ziet er momenteel uit.
Laten we een vierde test schrijven, waarin we een bericht sturen dat is ondertekend met de privésleutel van iemand anders. Laten we nog een privésleutel maken en deze in een bestand opslaan not-owner.pk. Met deze privésleutel ondertekenen wij het bericht. Laten we de tests uitvoeren en ervoor zorgen dat alle tests slagen. momenteel.
Nu kunnen we eindelijk verder gaan met het implementeren van de slimme contractlogica.
В recv_external() we accepteren twee soorten berichten.
Omdat ons contract de verliezen van de spelers zal accumuleren, moet dit geld worden overgedragen aan de maker van de loterij. Het portefeuilleadres van de maker van de loterij wordt bij het aanmaken van het contract in de opslag vastgelegd.
Voor het geval dat we de mogelijkheid nodig hebben om het adres te wijzigen waarnaar we de grammen van de verliezers sturen. We zouden ook grammen van de loterij naar het adres van de eigenaar moeten kunnen sturen.
Laten we beginnen met de eerste. Laten we eerst een test schrijven die controleert of het slimme contract na het verzenden van het bericht het nieuwe adres in de opslag heeft opgeslagen. Houd er rekening mee dat we in het bericht naast het loket en het nieuwe adres ook het bericht doorgeven action Een 7-bits geheel getal, niet-negatief getal, afhankelijk daarvan zullen we kiezen hoe we het bericht in het slimme contract verwerken.
<b 0 32 u, 1 @ 7 u, new_owner_wc @ 32 i, new_owner_account_id @ 256 u, b> message_to_sign !In de test kun je zien hoe smartcontract-opslag wordt gedeserialiseerd storage in Vijf. Deserialisatie van variabelen wordt beschreven in de Fift-documentatie.
met toegevoegd deeg.
Laten we de test uitvoeren en ervoor zorgen dat deze mislukt. Laten we nu logica toevoegen om het adres van de loterijeigenaar te wijzigen.
In het slimme contract blijven we analyseren message, lees in action. Laten we u eraan herinneren dat we er twee zullen hebben action: adres wijzigen en grammen verzenden.
Vervolgens lezen wij het nieuwe adres van de contracteigenaar uit en slaan dit op in de opslag.
We voeren de tests uit en zien dat de derde test mislukt. Het crasht omdat het contract nu bovendien 7 bits uit het bericht parseert, die ontbreken in de test. Voeg een niet-bestaande toe aan het bericht action. Laten we de tests uitvoeren en kijken of alles goed gaat. zich inzetten voor veranderingen. Geweldig.
Laten we nu de logica schrijven voor het verzenden van het opgegeven aantal grammen naar het eerder opgeslagen adres.
Laten we eerst een test schrijven. We zullen twee tests schrijven, één wanneer er niet genoeg evenwicht is, de tweede wanneer alles met succes zou moeten slagen. Testen kunnen worden bekeken .
Laten we nu de code toevoegen. Laten we eerst twee hulpmethoden schrijven. De eerste get-methode is om het huidige saldo van een slim contract te achterhalen.
int balance() inline_ref method_id {
return get_balance().pair_first();
}En de tweede is voor het verzenden van grammen naar een ander slim contract. Ik heb deze methode volledig gekopieerd van 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 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
}Laten we deze twee methoden aan het slimme contract toevoegen en de logica schrijven. Eerst analyseren we het aantal grammen uit het bericht. Vervolgens controleren we het saldo, als dit niet genoeg is, gooien we een uitzondering. Als alles in orde is, sturen we de grammen 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));lijkt momenteel op het slimme contract. Laten we de tests uitvoeren en ervoor zorgen dat ze slagen.
Voor een verwerkt bericht wordt overigens iedere keer een commissie afgetrokken van het smart contract. Om de slimme contractberichten het verzoek te laten uitvoeren, moet u na basiscontroles bellen accept_message().
Laten we nu verder gaan met interne berichten. In feite accepteren we alleen grammen en sturen we het dubbele bedrag terug naar de speler als hij wint, en een derde naar de eigenaar als hij verliest.
Laten we eerst een eenvoudige test schrijven. Om dit te doen hebben we een testadres van het slimme contract nodig van waaruit we zogenaamd grammen naar het slimme contract sturen.
Het slimme contractadres bestaat uit twee cijfers: een 32-bits geheel getal dat verantwoordelijk is voor de werkketen en een 256-bits niet-negatief geheel getal, uniek accountnummer in deze werkketen. Bijvoorbeeld -1 en 12345, dit is het adres dat we in een bestand opslaan.
Ik heb de functie voor het opslaan van het adres gekopieerd van .
// ( 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 eens kijken hoe de functie werkt, dit geeft inzicht in hoe Fift werkt. Start Fift in interactieve modus.
~/TON/build/crypto/fift -i Eerst pushen we -1, 12345 en de naam van het toekomstige bestand "sender.addr" op de stapel:
-1 12345 "sender.addr" De volgende stap is het uitvoeren van de functie -rot, die de stapel zodanig verschuift dat bovenaan de stapel een uniek slim contractnummer staat:
"sender.addr" -1 12345256 u>B converteert een 256-bits niet-negatief geheel getal naar bytes.
"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039swap verwisselt de bovenste twee elementen van de stapel.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -132 i>B converteert een 32-bits geheel getal naar bytes.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFFB+ verbindt twee reeksen bytes.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFFopnieuw swap.
BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" En ten slotte worden de bytes naar het bestand geschreven B>file. Hierna is onze stapel leeg. Wij stoppen Fift. Er is een bestand aangemaakt in de huidige map sender.addr. Laten we het bestand naar de gemaakte map verplaatsen test/addresses/.
Laten we een eenvoudige test schrijven die grammen naar een slim contract stuurt. .
Laten we nu eens kijken naar de logica van de loterij.
Het eerste wat we doen is het bericht controleren bounced of niet als bounced, dan negeren we het. bounced betekent dat het contract grammen retourneert als er een fout optreedt. Wij retourneren geen grammen als er plotseling een fout optreedt.
We controleren of het saldo minder dan een halve gram bedraagt, dan accepteren we het bericht gewoon en negeren het.
Vervolgens parseren we het adres van het slimme contract waarvan het bericht afkomstig is.
We lezen de gegevens uit de opslag en verwijderen vervolgens oude weddenschappen uit de geschiedenis als er meer dan twintig zijn. Voor het gemak heb ik drie extra functies geschreven pack_order(), unpack_order(), remove_old_orders().
Vervolgens kijken we of het saldo niet genoeg is voor de betaling, dan gaan we ervan uit dat dit geen weddenschap is, maar een aanvulling en slaan we de aanvulling op in orders.
Dan eindelijk de essentie van het slimme contract.
Als de speler verliest, slaan we dit eerst op in de wedgeschiedenis en als het bedrag meer dan 3 gram bedraagt, sturen we 1/3 naar de eigenaar van het slimme contract.
Als de speler wint, sturen we het dubbele bedrag naar het adres van de speler en slaan we de informatie over de weddenschap 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) { ;; 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));
}Dat is het. .
Nu is het enige dat overblijft eenvoudig: laten we get-methoden creëren zodat we informatie over de status van het contract van de buitenwereld kunnen verkrijgen (in feite de gegevens uit hun slimme contractopslag kunnen lezen).
. We zullen hieronder schrijven over hoe u informatie over een slim contract kunt ontvangen.
Ik vergat ook de code toe te voegen die het allereerste verzoek zal verwerken dat optreedt bij het publiceren van een slim contract. . En verder bug bij het sturen van 1/3 van het bedrag naar de rekening van de eigenaar.
De volgende stap is het publiceren van het slimme contract. Laten we een map maken requests.
Ik heb de publicatiecode als basis genomen die in de officiële repository.
Iets wat de moeite waard is om op te letten. We genereren een slimme contractopslag en een invoerbericht. Hierna wordt het adres van het slimme contract gegenereerd, dat wil zeggen dat het adres al vóór publicatie in TON bekend is. Vervolgens moet u enkele grammen naar dit adres sturen, en pas daarna moet u een bestand met het slimme contract zelf sturen, aangezien het netwerk een commissie vraagt voor het opslaan van het slimme contract en de bewerkingen daarin (validators die slimme contracten opslaan en uitvoeren contracten). .
Vervolgens voeren we de publicatiecode uit en krijgen lottery-query.boc slim contractbestand en adres.
~/TON/build/crypto/fift -s requests/new-lottery.fif 0Vergeet niet de gegenereerde bestanden op te slaan: lottery-query.boc, lottery.addr, lottery.pk.
We zullen onder meer het adres van het slimme contract zien in de uitvoeringslogboeken.
new wallet address = 0:044910149dbeaf8eadbb2b28722e7d6a2dc6e264ec2f1d9bebd6fb209079bc2a
(Saving address to file lottery.addr)
Non-bounceable address (for init): 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd
Bounceable address (for later access): kQAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KpFYLaten we voor de lol een verzoek indienen bij TON
$ ./lite-client/lite-client -C ton-lite-client-test1.config.json
getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydEn we zullen zien dat het account met dit adres leeg is.
account state is emptyWij sturen naar het adres 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 Gram en na een paar seconden voeren we hetzelfde commando uit. Om grammen te verzenden gebruik ik , en je kunt iemand uit de chat om testgrammen vragen, waarover ik aan het einde van het artikel zal praten.
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydLijkt op een niet-geïnitialiseerde (state:account_uninit) een slim contract met hetzelfde adres en een saldo van 1 nanogram.
account state is (account
addr:(addr_std
anycast:nothing workchain_id:0 address:x044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A)
storage_stat:(storage_info
used:(storage_used
cells:(var_uint len:1 value:1)
bits:(var_uint len:1 value:103)
public_cells:(var_uint len:0 value:0)) last_paid:1583257959
due_payment:nothing)
storage:(account_storage last_trans_lt:3825478000002
balance:(currencies
grams:(nanograms
amount:(var_uint len:4 value:2000000000))
other:(extra_currencies
dict:hme_empty))
state:account_uninit))
x{C00044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A20259C2F2F4CB3800000DEAC10776091DCD650004_}
last transaction lt = 3825478000001 hash = B043616AE016682699477FFF01E6E903878CDFD6846042BA1BFC64775E7AC6C4
account balance is 2000000000ngLaten we nu het slimme contract publiceren. Laten we Lite-client starten en uitvoeren.
> 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 Laten we controleren of het contract is gepubliceerd.
> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydWij krijgen onder andere.
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.
Overeenkomstige commit met wijzigingen .
Laten we nu verzoeken maken om te communiceren met het slimme contract.
Om precies te zijn, laten we de eerste voor het wijzigen van het adres als een zelfstandig werk, en de tweede voor het verzenden van grammen naar het adres van de eigenaar. In feite zullen we hetzelfde moeten doen als in de test voor het verzenden van grammen.
Dit is de boodschap die we naar het slimme contract zullen sturen, waar msg_seqno 165, action 2 en 9.5 gram voor verzending.
<b 165 32 u, 2 7 u, 9500000000 Gram, b>Vergeet niet het bericht te ondertekenen met uw privésleutel lottery.pk, die eerder werd gegenereerd bij het maken van het slimme contract. .
Informatie ontvangen van een slim contract met behulp van get-methoden
Laten we nu eens kijken hoe we methoden voor het verkrijgen van slimme contracten kunnen uitvoeren.
Lancering lite-client en voer de get-methoden uit die we hebben geschreven.
$ ./lite-client/lite-client -C ton-lite-client-test1.config.json
> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd balance
arguments: [ 104128 ]
result: [ 64633878952 ]
...В result bevat de waarde die de functie retourneert balance() van ons slimme contract.
We zullen hetzelfde doen voor nog een aantal methoden.
> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_seqno
...
arguments: [ 77871 ]
result: [ 1 ] Laten we uw wedgeschiedenis opvragen.
> 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]) ] We zullen Lite-client gebruiken en methoden krijgen om informatie over het slimme contract op de site weer te geven.
Het weergeven van slimme contractgegevens op de website
Ik heb een eenvoudige website in Python geschreven om de gegevens uit het slimme contract op een handige manier weer te geven. Hier zal ik er niet in detail op ingaan en de site publiceren .
Verzoeken aan TON worden gedaan vanaf Python via lite-client. Voor het gemak is de site verpakt in Docker en gepubliceerd op Google Cloud. .
Laten we proberen
Laten we nu proberen daar grammen naar toe te sturen voor aanvulling . Wij sturen 40 gram. En laten we een paar weddenschappen afsluiten voor de duidelijkheid. We zien dat de site de geschiedenis van weddenschappen, het huidige winstpercentage en andere nuttige informatie toont.
dat we de eerste wonnen en de tweede verloren.
nawoord
Het artikel bleek veel langer te zijn dan ik had verwacht, misschien had het korter kunnen zijn, of misschien gewoon voor iemand die niets van TON weet en een niet zo eenvoudig slim contract wil schrijven en publiceren met de mogelijkheid om te communiceren met Het. Misschien hadden sommige dingen eenvoudiger uitgelegd kunnen worden.
Misschien hadden sommige aspecten van de implementatie efficiënter en eleganter kunnen gebeuren, maar dan zou het nog meer tijd hebben gekost om het artikel voor te bereiden. Het is ook mogelijk dat ik ergens een fout heb gemaakt of iets niet heb begrepen, dus als je iets serieus doet, moet je vertrouwen op de officiële documentatie of de officiële repository met de TON-code.
Opgemerkt moet worden dat, aangezien TON zelf nog in de actieve ontwikkelingsfase verkeert, er veranderingen kunnen optreden die een van de stappen in dit artikel zullen doorbreken (wat gebeurde terwijl ik aan het schrijven was, het is al gecorrigeerd), maar de algemene aanpak is het is onwaarschijnlijk dat dit zal veranderen.
Ik zal niet praten over de toekomst van TON. Misschien wordt het platform iets groots en moeten we tijd besteden aan het bestuderen ervan en nu een niche vullen met onze producten.
Er is ook Libra van Facebook, dat een potentieel gebruikerspubliek heeft dat groter is dan TON. Ik weet bijna niets over Libra, afgaande op het forum is daar veel meer activiteit dan in de TON-gemeenschap. Hoewel de ontwikkelaars en community van TON meer underground zijn, wat ook cool is.
referenties
- Officiële TON-documentatie:
- Officiële TON-repository:
- Officiële portemonnee voor verschillende platforms:
- Slimme contractrepository uit dit artikel:
- Link naar de slimme contractwebsite:
- Repository voor de extensie voor Visual Studio Code voor FunC:
- Praat over TON in Telegram, wat in de beginfase echt heeft geholpen om erachter te komen. Ik denk dat het geen vergissing is als ik zeg dat iedereen die iets voor TON heeft geschreven daar is. Ook kunt u daar proefgrammen opvragen.
- Nog een gesprek over TON waarin ik nuttige informatie vond:
- Eerste fase van de competitie:
- Tweede fase van de competitie:
Bron: www.habr.com
