ProHoster > Blog > Administratioun > Iwwer wéi een e Smart Kontrakt am Telegram Open Network (TON) schreift a publizéiert
Iwwer wéi een e Smart Kontrakt am Telegram Open Network (TON) schreift a publizéiert
Iwwer wéi e Smart Kontrakt an TON ze schreiwen an ze publizéieren
Iwwer wat geet dësen Artikel?
Am Artikel wäert ech schwätzen iwwer wéi ech un der éischter (vun zwee) Telegram Blockchain Concours deelgeholl hunn, kee Präis geholl hunn an decidéiert hunn meng Erfahrung an engem Artikel opzehuelen sou datt et net an d'Vergiess ënnerzegoen an, vläicht, hëlleft een.
Well ech wollt net abstrakt Code schreiwen, mee eppes ze schaffen schaffen, fir den Artikel geschriwwen ech e Smart Kontrakt fir eng Direktnoriichten Lotterie an eng Websäit déi Smart Kontrakt Daten direkt vun TON weist ouni Zwëschenlagerung benotzt.
Den Artikel wäert nëtzlech sinn fir déi, déi hiren éischte Smart Kontrakt an TON maachen wëllen, awer net wësse wou ufänken.
Mat der Lotterie als Beispill, wäert ech vun der Ëmwelt installéieren fir e Smart Kontrakt ze publizéieren, mat him interagéieren an eng Websäit ze schreiwen fir Daten ze kréien an ze publizéieren.
Iwwer d'Participatioun am Concours
Am leschte Oktober huet Telegram e Blockchain Concours mat neie Sproochen ugekënnegt Fift и FunC. Et war néideg fir eng vun de fënnef proposéierte Smart Kontrakter ze schreiwen. Ech hu geduecht et wier flott eppes anescht ze maachen, eng Sprooch ze léieren an eppes ze maachen, och wann ech an Zukunft näischt méi schreiwen muss. Plus, d'Thema ass permanent op de Lippen.
Et ass derwäert ze soen datt ech keng Erfahrung haten fir intelligent Kontrakter z'entwéckelen.
Ech hu geplangt bis zum Schluss matzemaachen bis ech konnt an dann en Iwwerpréiwungsartikel schreiwen, mee ech hunn direkt bei der éischter gescheitert. ech geschriwwen engem Portmonni mat Multi-Ënnerschrëft op FunC an et huet allgemeng geschafft. Ech hunn et als Basis geholl Smart Kontrakt op Soliditéit.
Deemools hunn ech geduecht datt dëst definitiv genuch wier fir op d'mannst eng Präisplaz ze huelen. Als Resultat sinn ongeféier 40 vun 60 Participanten Präis Gewënner ginn an ech war net ënnert hinnen. Am Allgemengen ass et näischt falsch mat dësem, awer eng Saach huet mech gestéiert. Zu der Zäit vun der Ukënnegung vun de Resultater war d'Iwwerpréiwung vum Test fir mäi Kontrakt net gemaach, ech hunn d'Participanten am Chat gefrot ob et een aneren ass deen et net hat, et waren keng.
Anscheinend oppassen op meng Messagen, zwee Deeg méi spéit hunn d'Riichter e Kommentar verëffentlecht an ech verstinn nach ëmmer net ob se zoufälleg mäi Smart Kontrakt während der Riichterung verpasst hunn oder einfach geduecht hunn datt et sou schlecht wier datt et kee Kommentar brauch. Ech hunn eng Fro op der Säit gestallt, awer keng Äntwert kritt. Och wann et kee Geheimnis ass wien beurteelt huet, hunn ech et onnéideg ugesinn perséinlech Messagen ze schreiwen.
Vill Zäit gouf u Verständnis verbruecht, dofir gouf decidéiert en Artikel ze schreiwen. Well et nach net vill Informatioun ass, hëlleft dësen Artikel Zäit fir jiddereen interesséiert.
D'Konzept vun Smart Kontrakter an TON
Ier Dir eppes schreift, musst Dir erausfannen, vu wéi enger Säit Dir dës Saach unzegoen. Dofir wäert ech Iech elo soen aus wéi enge Deeler de System besteet. Méi präzis, wat Deeler Dir musst wëssen, fir op d'mannst eng Zort Aarbecht Kontrakt ze schreiwen.
Mir konzentréieren eis op e Smart Kontrakt ze schreiwen an ze schaffen mat TON Virtual Machine (TVM), Fift и FunC, Also ass den Artikel méi wéi eng Beschreiwung vun der Entwécklung vun engem normale Programm. Mir wäerten net ophalen wéi d'Plattform selwer hei funktionnéiert.
Am Allgemengen iwwer wéi et funktionnéiert TVM a Sprooch Fift et gëtt gutt offiziell Dokumentatioun. Wärend ech um Concours deelgeholl hunn an elo beim Schreiwen vum aktuelle Kontrakt, hunn ech mech dacks zu hatt gedréint.
D'Haaptsprooch an där Smart Kontrakter geschriwwe sinn ass FunC. Et gëtt keng Dokumentatioun doriwwer am Moment, also fir eppes ze schreiwen musst Dir Beispiller vu Smart Kontrakter aus dem offiziellen Repository studéieren an d'Ëmsetzung vun der Sprooch selwer do, plus Dir kënnt Beispiller vu Smart Kontrakter aus de leschten zwee kucken Concoursen. Linken um Enn vum Artikel.
Loosst eis soen, mir hu schonn e Smart Kontrakt geschriwwen fir FunC, duerno kompiléiere mir de Code an Fift assembler.
De kompiléierte Smart Kontrakt bleift ze publizéieren. Fir dëst ze maachen, musst Dir eng Funktioun schreiwen Fift, déi de Smart Kontrakt Code an e puer aner Parameteren als Input huelen, an d'Ausgab gëtt e Fichier mat der Extensioun .boc (wat heescht "Täsch vun Zellen"), an, jee wéi mir et schreiwen, e private Schlëssel an Adress, déi op Basis vum Smart Kontrakt Code generéiert gëtt. Dir kënnt scho Gramm op d'Adress vun engem Smart Kontrakt schécken, datt nach net publizéiert gouf.
Fir e Smart Kontrakt ze publizéieren an TON kritt .boc d'Datei muss op de Blockchain geschéckt ginn mat engem Liichtclient (méi doriwwer hei ënnen). Awer ier Dir publizéiert, musst Dir Gramm op déi generéiert Adress transferéieren, soss gëtt de Smart Kontrakt net publizéiert. No der Verëffentlechung kënnt Dir mam Smart Kontrakt interagéieren andeems Dir et Messagen vu baussen schéckt (zum Beispill mat engem Liichtclient) oder vu bannen (zum Beispill, e Smart Kontrakt schéckt engem aneren e Message bannent TON).
Wann mir verstinn wéi de Code publizéiert gëtt, gëtt et méi einfach. Mir wëssen ongeféier wat mir wëllen schreiwen a wéi eise Programm funktionnéiert. A beim Schreiwen kucke mir no wéi dëst schonn an existente Smart Kontrakter ëmgesat gëtt, oder mir kucken an den Implementéierungscode Fift и FunC am offiziellen Repository, oder kuckt an der offizieller Dokumentatioun.
Ganz dacks hunn ech no Schlësselwierder am Telegram Chat gesicht, wou all d'Participanten vun der Konkurrenz an d'Telegram Mataarbechter sech versammelt hunn, an et ass geschitt, datt während dem Concours jidderee sech do versammelt huet an ugefaang huet mat Fift a FunC ze diskutéieren. Link um Enn vum Artikel.
Et ass Zäit vun Theorie op Praxis ze plënneren.
Preparéieren d'Ëmwelt fir mat TON ze schaffen
Ech hunn alles gemaach wat am Artikel iwwer MacOS beschriwwe gëtt an et an der propperer Ubuntu 18.04 LTS op Docker duebel gepréift.
Dat éischt wat Dir maache musst ass eroflueden an z'installéieren lite-client mat deem Dir Demanden op TON schécken kann.
D'Instruktioune op der offizieller Websäit beschreiwen den Installatiounsprozess ganz detailléiert a kloer an e puer Detailer weg. Hei verfollegen mir d'Instruktioune, installéiert déi fehlend Ofhängegkeete laanscht de Wee. Ech hunn net all Projet selwer kompiléiert an aus dem offiziellen Ubuntu Repository installéiert (op MacOS hunn ech benotzt brew).
Wann all Ofhängegkeeten installéiert sinn, kënnt Dir installéieren lite-client, Fift, FunC.
Als éischt klone mir den TON Repository zesumme mat sengen Ofhängegkeeten. Fir d'Bequemlechkeet wäerte mir alles an engem Dossier maachen ~/TON.
cd ~/TON
git clone https://github.com/ton-blockchain/ton.git
cd ./ton
git submodule update --init --recursive
De Repository späichert och Implementatiounen Fift и FunC.
Elo si mir prett de Projet ze montéieren. De Repository Code gëtt an en Dossier gekloont ~/TON/ton. d' ~/TON en Dossier erstellen build a sammelen de Projet an et.
mkdir ~/TON/build
cd ~/TON/build
cmake ../ton
Well mir e Smart Kontrakt schreiwen, brauche mir net nëmmen lite-clientmee Fift с FunC, also loosst eis alles zesummestellen. Et ass net e séiere Prozess, also mir waarden.
cd ~/TON/build
./lite-client/lite-client -C ton-lite-client-test1.config.json
Wann de Bau erfollegräich war, da gesitt Dir nom Start e Logbuch vun der Verbindung vum Liichtclient zum Node.
[ 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)
...
Dir kënnt de Kommando lafen help a kuckt wéi eng Befehle verfügbar sinn.
help
Loosst eis d'Befehle lëschten déi mir an dësem Artikel benotzen.
list of available commands:
last Get last block and state info from server
sendfile <filename> Load a serialized message from <filename> and send it to server
getaccount <addr> [<block-id-ext>] Loads the most recent state of specified account; <addr> is in [<workchain>:]<hex-or-base64-addr> format
runmethod <addr> [<block-id-ext>] <method-id> <params>... Runs GET method <method-id> of account <addr> with specified parameters
last получает последний созданный блок с сервера.
sendfile <filename> отправляет в TON файл с сообщением, именно с помощью этой команды публикуется смарт-контракт и запрсосы к нему.
getaccount <addr> загружает текущее состояние смарт-контракта с указанным адресом.
runmethod <addr> [<block-id-ext>] <method-id> <params> запускает get-методы смартконтракта.
Elo si mir prett de Kontrakt selwer ze schreiwen.
Ëmsetzung
Idea
Wéi ech uewen geschriwwen hunn, ass de Smart Kontrakt dee mir schreiwen eng Lotterie.
Ausserdeem ass dëst keng Lotterie an där Dir braucht en Ticket ze kafen an eng Stonn, Dag oder Mount ze waarden, awer en Direkt an deem de Benotzer op d'Kontraktadress transferéiert N Gramm, a kritt et direkt zréck 2 * N Gramm oder verléiert. Mir wäerten d'Wahrscheinlechkeet vun enger Victoire iwwer 40% maachen. Wann et net genuch Gramm fir d'Bezuelung gëtt, wäerte mir d'Transaktioun als Top-up betruechten.
Ausserdeem ass et wichteg datt Spillwette an Echtzäit an an enger praktescher Form gesi kënne ginn, sou datt de Benotzer direkt kann verstoen ob hien gewonnen oder verluer huet. Dofir musst Dir eng Websäit maachen déi Spillwette a Resultater direkt vun TON weist.
Schreiwen engem Smart Kontrakt
Fir d'Bequemlechkeet hunn ech de Code fir FunC markéiert; de Plugin kann an der Visual Studio Code Sich fonnt ginn an installéiert ginn; wann Dir op eemol eppes derbäi wëllt, hunn ech de Plugin ëffentlech verfügbar gemaach. Och een huet virdrun e Plugin fir mat Fift ze schaffen, Dir kënnt et och installéieren an et an VSC fannen.
Loosst eis direkt e Repository erstellen wou mir d'Tëscheresultater engagéieren.
Fir eist Liewen méi einfach ze maachen, wäerte mir e Smart Kontrakt schreiwen an et lokal testen bis et fäerdeg ass. Eréischt duerno publizéieren mir et am TON.
De Smart Kontrakt huet zwou extern Methoden déi zougänglech sinn. Éischten, recv_external() dës Funktioun gëtt ausgeführt wann eng Ufro un de Kontrakt vun der Äussewelt kënnt, dat heescht net vum TON, zum Beispill, wa mir selwer e Message generéieren an duerch de Lite-Client schécken. Zweeten, recv_internal() Dëst ass wann, bannent TON selwer, all Kontrakt op eis bezitt. A béide Fäll kënnt Dir Parameteren un d'Funktioun weiderginn.
Fänke mer mat engem einfache Beispill un dat funktionnéiert wann se publizéiert ginn, awer et gëtt keng funktionell Laascht dran.
Hei musse mir erklären wat et ass slice. All Daten, déi am TON Blockchain gespäichert sinn, sinn eng Sammlung TVM cell oder einfach cell, an esou enger Zell kënnt Dir bis zu 1023 Bits vun Daten a bis zu 4 Linken op aner Zellen späicheren.
TVM cell slice oder slice dëst ass en Deel vun der existéierender cell benotzt gëtt fir et ze analyséieren, wäert et méi spéit kloer ginn. Den Haapt Saach fir eis ass, datt mir kënnen Transfert slice an ofhängeg vun der Aart vu Message, veraarbecht d'Donnéeën an recv_external() oder recv_internal().
impure - e Schlësselwuert dat weist datt d'Funktioun Smart Kontraktdaten ännert.
Loosst eis de Kontraktcode späicheren lottery-code.fc a kompiléieren.
D'Bedeitung vun de Fändelen kann mat dem Kommando gekuckt ginn
~/TON/build/crypto/func -help
Mir hunn de Fift Assembler Code zesummegesat lottery-compiled.fif:
// lottery-compiled.fif
"Asm.fif" include
// automatically generated from `/Users/rajymbekkapisev/TON/ton/crypto/smartcont/stdlib.fc` `./lottery-code.fc`
PROGRAM{
DECLPROC recv_internal
DECLPROC recv_external
recv_internal PROC:<{
// in_msg
DROP //
}>
recv_external PROC:<{
// in_msg
DROP //
}>
}END>c
Et kann lokal lancéiert ginn, dofir wäerte mir d'Ëmwelt virbereeden.
Bedenkt datt déi éischt Linn verbënnt Asm.fif, Dëst ass Code geschriwwen am Fift fir de Fift Assembler.
Well mir de Smart Kontrakt lokal ausféieren an testen, wäerte mir e Fichier erstellen lottery-test-suite.fif a kopéiert de kompiléierte Code do, ersetzt déi lescht Zeil dran, déi de Smart Kontrakt Code op e konstante schreift codefir se dann op déi virtuell Maschinn ze transferéieren:
"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
Bis elo schéngt et kloer, loosst eis elo dee selwechte Fichier de Code addéieren dee mir benotze fir TVM ze starten.
В c7 mir Rekord de Kontext, dat ass, d'Donnéeën mat deenen der TVM (oder Reseau Staat) lancéiert ginn. Och während dem Concours huet ee vun den Entwéckler gewisen wéi een erstellt c7 an ech kopéiert. An dësem Artikel musse mir eventuell änneren rand_seed well d'Generatioun vun enger zoufälleger Zuel hänkt dovun of a wann net geännert gëtt, gëtt déi selwecht Zuel all Kéier zréckginn.
recv_internal и recv_external Konstante mat Wäerter 0 an -1 wäerte verantwortlech sinn fir déi entspriechend Funktiounen am Smart Kontrakt ze ruffen.
Elo si mir prett den éischten Test fir eisen eidele Smart Kontrakt ze kreéieren. Fir Kloerheet, fir elo wäerte mir all Tester an déi selwecht Datei derbäi lottery-test-suite.fif.
Loosst eis eng Variabel erstellen storage a schreift eng eidel dran cell, dëst wäert de Smart Kontrakt Stockage ginn.
message Dëst ass de Message dee mir op de Smart Kontakt vu baussen iwwerdroen. Mir wäerten et fir de Moment och eidel maachen.
Great, mir hunn déi éischt Aarbecht Versioun vum Smart Kontrakt geschriwwen.
Elo musse mir Funktionalitéit derbäi. Loosst eis éischt mat Messagen beschäftegen, déi aus der Äussewelt kommen recv_external()
Den Entwéckler selwer wielt de Message Format datt de Kontrakt akzeptéieren kann.
Awer normalerweis
éischtens, mir wëllen eise Kontrakt vun der Äussewelt schützen an et esou maachen, datt nëmmen de Besëtzer vum Kontrakt extern Messagen un et schécken kann.
zweetens, wann mir eng valabel Message schécken ze TON, mir wëllen dat genee eemol geschéien a wann mir déi selwecht Message schécken erëm, de Smart Kontrakt refuséiert et.
Also bal all Kontrakt léist dës zwee Problemer, well eise Kontrakt extern Messagen akzeptéiert, musse mir eis och dofir këmmeren.
Mir maachen et an ëmgedréint Uerdnung. Als éischt, loosst eis de Problem mat der Widderhuelung léisen; wann de Kontrakt scho sou e Message kritt huet an et veraarbecht huet, gëtt et net eng zweete Kéier ausgefouert. An da wäerte mir de Problem léisen, sou datt nëmmen e bestëmmte Krees vu Leit Messagen un de Smart Kontrakt schécken kann.
Et gi verschidde Weeër fir de Problem mat duplizéierte Messagen ze léisen. Hei ass wéi mir et maachen. Am Smart Kontrakt initialiséieren mir de Compteur vun erhalen Messagen mam initialen Wäert 0. An all Message un de Smart Kontrakt addéiere mir den aktuelle Konterwäert. Wann de Konterwäert an der Noriicht net mam Wäert am Smart Kontrakt entsprécht, da veraarbechte mir et net; wann et geschitt, da veraarbechte mir et an erhéijen de Konter am Smart Kontrakt ëm 1.
Komme mer zréck op lottery-test-suite.fif a füügt en zweeten Test derbäi. Wa mir eng falsch Nummer schécken, soll de Code eng Ausnam werfen. Zum Beispill, loosst de Kontrakt Daten späicheren 166, a mir schécken 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"
Loosst eis starten.
~/TON/build/crypto/fift -s lottery-test-suite.fif
A mir wäerte gesinn datt den Test mat engem Feeler ausgefouert gëtt.
[ 1][t 0][1582283084.210902214][words.cpp:3046] lottery-test-suite.fif:67: abort": Test #2 Not passed
[ 1][t 0][1582283084.210941076][fift-main.cpp:196] Error interpreting file `lottery-test-suite.fif`: error interpreting included file `lottery-test-suite.fif` : lottery-test-suite.fif:67: abort": Test #2 Not passed
An dëser Phase lottery-test-suite.fif soll ausgesinn Link.
Loosst eis elo d'Konterlogik zum Smart Kontrakt addéieren 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 läit de Message mir schécken.
Dat éischt wat mir maachen ass kucken ob de Message Daten enthält, wann net, da gi mer einfach eraus.
Als nächst parse mir de Message. in_msg~load_uint(32) lued d'Zuel 165, 32-bëssen unsigned int aus dem iwwerdroe Message.
Als nächst luede mir 32 Bits vun der Smart Kontraktlagerung. Mir kontrolléieren datt déi gelueden Zuel mat der passéierter entsprécht; wann net, werfe mir eng Ausnam. An eisem Fall, well mir en Net-Match passéieren, sollt eng Ausnam geworf ginn.
Kopéiert de resultéierende Code op lottery-test-suite.fif, net vergiessen déi lescht Zeil ze ersetzen.
Mir kontrolléieren ob den Test passéiert:
~/TON/build/crypto/fift -s lottery-test-suite.fif
Genau hei Dir kënnt de entspriechende Verpflichtung mat den aktuellen Resultater gesinn.
Notéiert datt et onbequem ass de kompiléierte Code vun engem Smart Kontrakt dauernd an eng Datei mat Tester ze kopéieren, also loosst eis e Skript schreiwen, deen de Code an eng Konstante fir eis schreift, a mir verbannen einfach de kompiléierte Code mat eisen Tester mat "include".
Erstellt eng Datei am Projet Dossier build.sh mat folgendem Inhalt.
Elo, lafen just eise Skript fir de Kontrakt ze kompiléieren. Awer nieft dësem musse mir et an eng konstant schreiwen code. Also wäerte mir eng nei Datei erstellen lotter-compiled-for-test.fif, déi mir an de Fichier enthalen lottery-test-suite.fif.
Loosst eis Skirpt Code op sh addéieren, wat d'kompiléiert Datei einfach duplizéiert lotter-compiled-for-test.fif an änneren déi lescht Zeil an et.
# copy and change for test
cp lottery-compiled.fif lottery-compiled-for-test.fif
sed '$d' lottery-compiled-for-test.fif > test.fif
rm lottery-compiled-for-test.fif
mv test.fif lottery-compiled-for-test.fif
echo -n "}END>s constant code" >> lottery-compiled-for-test.fif
Elo, fir ze kontrolléieren, loosst eis de resultéierende Skript lafen an eng Datei gëtt generéiert lottery-compiled-for-test.fif, déi mir an eisem lottery-test-suite.fif
В lottery-test-suite.fif läschen de Kontrakt Code a füügt d'Linn derbäi "lottery-compiled-for-test.fif" include.
Mir lafen Tester fir ze kontrolléieren ob se passéieren.
~/TON/build/crypto/fift -s lottery-test-suite.fif
Super, elo fir de Start vun Tester ze automatiséieren, loosst eis eng Datei erstellen test.sh, déi als éischt ausféieren build.sh, an dann d'Tester lafen.
Loosst eis et maachen test.sh a lafen et fir sécherzestellen datt d'Tester funktionnéieren.
chmod +x ./test.sh
./test.sh
Mir kontrolléieren datt de Kontrakt kompiléiert an d'Tester ausgefouert ginn.
Super, elo um Startup test.sh D'Tester ginn zesummegesat an direkt lafen. Hei ass de Link op engagéieren.
Okay, ier mer weidergoen, loosst eis nach eng Saach maachen fir d'Kamoudheet.
Loosst eis en Dossier erstellen build wou mir de kopéierte Kontrakt a säi Klon späicheren an eng Konstant geschriwwe ginn lottery-compiled.fif, lottery-compiled-for-test.fif. Loosst eis och en Dossier erstellen test wou gëtt d'Testdatei gespäichert? lottery-test-suite.fif a potenziell aner ënnerstëtzend Dateien. Link op relevant Ännerungen.
Loosst eis weider de Smart Kontrakt entwéckelen.
Als nächst sollt et en Test ginn, dee kontrolléiert datt de Message kritt gëtt an de Comptoir am Geschäft aktualiséiert gëtt wa mir déi richteg Nummer schécken. Mä mir maachen dat spéider.
Loosst eis elo iwwerdenken wéi eng Datestruktur a wéi eng Daten am Smart Kontrakt gespäichert musse ginn.
Ech wäert alles beschreiwen wat mir späicheren.
`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` переменная типа словарь, хранит последние двадцать ставок.
Als nächst musst Dir zwou Funktiounen schreiwen. Loosst eis déi éischt ruffen pack_state(), déi d'Donnéeën packen fir spéider ze späicheren an der Smart Kontraktspäicherung. Loosst eis déi zweet ruffen unpack_state() wäert Daten aus der Späichere liesen an zréckginn.
_ 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;
}
Mir addéieren dës zwou Funktiounen un den Ufank vum Smart Kontrakt. Et wäert geschéien esou Tëscheresultat.
Fir Daten ze späicheren, musst Dir déi agebaute Funktioun uruffen set_data() an et wäert schreiwen Daten aus pack_state() am Smart Kontrakt Stockage.
Elo datt mir praktesch Funktiounen hunn fir Daten ze schreiwen an ze liesen, kënne mir weidergoen.
Mir mussen iwwerpréiwen datt de Message, dee vu baussen erakënnt, vum Besëtzer vum Kontrakt ënnerschriwwe gëtt (oder engem anere Benotzer deen Zougang zum private Schlëssel huet).
Wa mir e Smart Kontrakt publizéieren, kënne mir et initialiséieren mat den Donnéeën déi mir an der Späichere brauchen, déi fir zukünfteg Benotzung gespäichert ginn. Mir wäerten den ëffentleche Schlëssel do notéieren, fir datt mir verifizéiere kënnen datt den erakommende Message mam entspriechende private Schlëssel ënnerschriwwe gouf.
Ier Dir weider geet, loosst eis e private Schlëssel erstellen a schreiwen test/keys/owner.pk. Fir dëst ze maachen, loosst eis Fift am interaktiven Modus starten a véier Kommandoen ausféieren.
`newkeypair` генерация публичного и приватного ключа и запись их в стек.
`drop` удаления из стека верхнего элемента (в данном случае публичный ключ)
`.s` просто посмотреть что лежит в стеке в данный момент
`"owner.pk" B>file` запись приватного ключа в файл с именем `owner.pk`.
`bye` завершает работу с Fift.
Loosst eis en Dossier erstellen keys am Dossier test a schreift de private Schlëssel do.
mkdir test/keys
cd test/keys
~/TON/build/crypto/fift -i
newkeypair
ok
.s
BYTES:128DB222CEB6CF5722021C3F21D4DF391CE6D5F70C874097E28D06FCE9FD6917 BYTES:DD0A81AAF5C07AAAA0C7772BB274E494E93BB0123AA1B29ECE7D42AE45184128
drop
ok
"owner.pk" B>file
ok
bye
Mir gesinn e Fichier am aktuellen Dossier owner.pk.
Mir läschen den ëffentleche Schlëssel aus dem Stack a wann néideg kënne mir et vum private kréien.
Elo musse mir eng Ënnerschrëft Verifizéierung schreiwen. Loosst eis mam Test ufänken. Als éischt liesen mir de private Schlëssel aus der Datei mat der Funktioun file>B a schreift et op eng Variabel owner_private_key, dann benotzt d'Funktioun priv>pub konvertéiert de private Schlëssel an en ëffentleche Schlëssel a schreift d'Resultat an owner_public_key.
Mir initialiséieren de Smart Kontraktlagerung mat arbiträren Donnéeën an der selwechter Sequenz wéi an der Funktioun pack_state()a schreift et an eng Variabel storage.
Als nächst wäerte mir en ënnerschriwwene Message komponéieren, et enthält nëmmen d'Ënnerschrëft an de Konterwäert.
Als éischt kreéiere mir d'Donnéeën déi mir wëllen iwwerdroen, dann ënnerschreiwen mir se mat engem private Schlëssel a schliisslech generéiere mir eng ënnerschriwwen Noriicht.
Als Resultat gëtt de Message, dee mir un de Smart Kontrakt schécken, an enger Variabel opgeholl message_to_send, iwwer Funktiounen hashu, ed25519_sign_uint kann liesen an der Fift Dokumentatioun.
A fir den Test ze lafen, ruffe mir nach eng Kéier.
Hei ass esou Den Dossier mat Tester soll op dëser Etapp esou ausgesinn.
Loosst eis den Test ausféieren an et wäert versoen, also wäerte mir de Smart Kontrakt änneren, sou datt et Messagen vun dësem Format ka kréien an d'Ënnerschrëft verifizéieren.
Als éischt ziele mir 512 Bits vun der Ënnerschrëft aus dem Message a schreiwen se op eng Variabel, da ziele mir 32 Bits vun der Kontervariabel.
Well mir eng Funktioun hunn fir Daten aus dem Smart Kontraktlagerung ze liesen, wäerte mir se benotzen.
Als nächst gëtt de Konter iwwerpréift mat der Späichere iwwerpréift an d'Ënnerschrëft iwwerpréift. Wann eppes net passt, da werfe mir eng Ausnahm mam passenden 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));
Loosst eis d'Tester lafen a kucken datt den zweeten Test feelt. Aus zwee Grënn gëtt et net genuch Bits an der Noriicht an et ginn net genuch Bits an der Späichere, sou datt de Code beim Parsing klappt. Mir mussen eng Ënnerschrëft op de Message bäidroen, dee mir schécken an d'Späichere vum leschten Test kopéieren.
Am zweeten Test fügen mir eng Message Ënnerschrëft an änneren de Smart Kontrakt Stockage. Hei ass esou den Dossier mat Tester gesäit am Moment aus.
Loosst eis e véierten Test schreiwen, an deem mir e Message schécken, ënnerschriwwen mat engem anere säi private Schlëssel. Loosst eis en anere private Schlëssel erstellen an en an eng Datei späicheren not-owner.pk. Mir ënnerschreiwen de Message mat dësem private Schlëssel. Loosst eis d'Tester lafen a sécherstellen datt all Tester passéieren. Engagéieren an dësem Moment.
Elo kënne mir endlech weidergoen fir déi intelligent Kontraktlogik ëmzesetzen.
В recv_external() mir wäerten zwou Zorte vu Messagen akzeptéieren.
Well eise Kontrakt d'Verloschter vun de Spiller sammelt, mussen dës Suen un den Ersteller vun der Lotterie transferéiert ginn. D'Portemonnaie Adress vum Lotterie Creator gëtt an der Späichere opgeholl wann de Kontrakt erstallt gëtt.
Just am Fall, mir brauchen d'Fähegkeet d'Adress ze änneren, op déi mir Gramm vun de Verléierer schécken. Mir sollten och fäeg sinn Gramm vun der Lotterie op d'Adress vum Besëtzer ze schécken.
Loosst eis mat deem éischten ufänken. Loosst eis als éischt en Test schreiwen, deen iwwerpréift datt nom Schécken vun der Noriicht de Smart Kontrakt déi nei Adress an der Späichere gerett huet. Notéiert w.e.g. datt mir an der Noriicht, nieft dem Comptoir an der neier Adress, och weiderginn action Eng 7-Bit ganz Zuel net-negativ Zuel, ofhängeg dovun, wäerte mir wielen wéi d'Botschaft am Smart Kontrakt veraarbecht gëtt.
<b 0 32 u, 1 @ 7 u, new_owner_wc @ 32 i, new_owner_account_id @ 256 u, b> message_to_sign !
Am Test kënnt Dir gesinn wéi d'Smartkontraktlagerung deserialiséiert gëtt storage an fift. Deserialiséierung vu Variabelen gëtt an der Fift Dokumentatioun beschriwwen.
Loosst eis den Test ausféieren a sécherstellen datt et feelt. Loosst eis elo Logik derbäi fir d'Adress vum Lotteriebesëtzer z'änneren.
Am Smart Kontrakt fuere mir weider message, liesen an action. Loosst eis Iech drun erënneren datt mir zwee wäerten hunn action: Adress änneren a Gramm schécken.
Duerno liesen mir déi nei Adress vum Kontraktbesëtzer a späicheren se an der Lagerung.
Mir lafen d'Tester a gesinn datt den drëtten Test feelt. Et klappt wéinst der Tatsaach datt de Kontrakt elo zousätzlech 7 Bits aus dem Message parséiert, déi am Test fehlen. Füügt en net existent un de Message action. Loosst eis d'Tester lafen a kucken datt alles passéiert. hei engagéieren fir Ännerungen. Super.
Loosst eis elo d'Logik schreiwen fir déi spezifizéiert Zuel vu Gramm op déi virdru gespäichert Adress ze schécken.
Als éischt schreiwen mer en Test. Mir schreiwen zwee Tester, eent wann et net genuch Gläichgewiicht ass, déi zweet wann alles erfollegräich passéiere soll. Tester kënne gekuckt ginn an dësem Engagement.
Loosst eis elo de Code addéieren. Als éischt schreiwen mer zwou Hëllefsmethoden. Déi éischt kréien Method ass déi aktuell Gläichgewiicht vun engem Smart Kontrakt erauszefannen.
int balance() inline_ref method_id {
return get_balance().pair_first();
}
An déi zweet ass fir Gramm op en anere Smart Kontrakt ze schécken. Ech hunn dës Method komplett vun engem anere Smart Kontrakt kopéiert.
() 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
}
Loosst eis dës zwou Methoden zum Smart Kontrakt addéieren a schreiwen d'Logik. Als éischt parse mir d'Zuel vu Gramm aus dem Message. Als nächst kucken mir d'Gläichgewiicht, wann et net genuch ass, werfe mir eng Ausnam. Wann alles gutt ass, da schécken mir d'Gramm op déi gespäichert Adress an aktualiséieren de Comptoir.
Hei ass esou gesäit wéi de Smart Kontrakt am Moment. Loosst eis d'Tester lafen a sécherstellen datt se passéieren.
Iwwregens gëtt all Kéiers eng Kommissioun vum Smart Kontrakt fir e veraarbechte Message ofgezunn. Fir datt d'Smart Kontrakt Messagen d'Ufro ausféieren, no Basiskontrollen musst Dir uruffen accept_message().
Loosst eis elo op intern Messagen weidergoen. An Tatsaach, wäerte mir nëmmen Gramm akzeptéieren an zréck duebel Zomm un de Spiller schécken wann hien gewënnt an en Drëttel un de Besëtzer wann hie verléiert.
Als éischt schreiwen mer en einfachen Test. Fir dëst ze maachen, brauche mir eng Testadress vum Smart Kontrakt aus deem mir vermeintlech Gramm un de Smart Kontrakt schécken.
D'Smart Kontrakt Adress besteet aus zwou Zuelen, engem 32-bëssen Ganzt verantwortlech fir d'workchain an eng 256-bëssen net-negativ ganz eenzegaarteg Kont Zuel an dëser workchain. Zum Beispill, -1 an 12345, dëst ass d'Adress déi mir an eng Datei späicheren.
Ech hunn d'Funktioun kopéiert fir d'Adress ze späicheren aus TonUtil.fif.
// ( wc addr fname -- ) Save address to file in 36-byte format
{ -rot 256 u>B swap 32 i>B B+ swap B>file } : save-address
Loosst eis kucken wéi d'Funktioun funktionnéiert, dëst wäert e Verständnis ginn wéi Fift funktionnéiert. Lancéiere Fift am interaktive Modus.
~/TON/build/crypto/fift -i
Als éischt drécke mir -1, 12345 an den Numm vun der zukünfteger Datei "sender.addr" op de Stack:
-1 12345 "sender.addr"
De nächste Schrëtt ass d'Funktioun auszeféieren -rot, wat de Stack sou verännert datt am Top vum Stack eng eenzegaarteg Smart Kontrakt Nummer ass:
"sender.addr" -1 12345
256 u>B konvertéiert en 256-Bit net-negativ Ganzt op Bytes.
A schliisslech ginn d'Bytes an d'Datei geschriwwen B>file. Duerno ass eise Stack eidel. Mir stoppen Fift. E Fichier gouf am aktuellen Dossier erstallt sender.addr. Loosst eis d'Datei an den erstallten Dossier réckelen test/addresses/.
Loosst eis en einfachen Test schreiwen deen Gramm op e Smart Kontrakt schéckt. Hei ass d'Verpflichtung.
Loosst eis elo d'Logik vun der Lotterie kucken.
Dat éischt wat mir maachen ass de Message ze kontrolléieren bounced oder net wann bounced, dann ignoréiere mir et. bounced heescht, datt de Kontrakt Gramm zréck wäert wann e puer Feeler geschitt. Mir ginn net Gramm zréck wann e Feeler op eemol geschitt.
Mir kontrolléieren, wann d'Gläichgewiicht manner wéi en halleft Gramm ass, da akzeptéiere mir einfach de Message an ignoréieren se.
Als nächstes parse mir d'Adress vum Smart Kontrakt, aus deem de Message koum.
Mir liesen d'Donnéeën aus der Stockage an dann al Spillwette aus der Geschicht läschen wann et méi wéi zwanzeg vun hinnen. Fir d'Bequemlechkeet hunn ech dräi zousätzlech Funktiounen geschriwwen pack_order(), unpack_order(), remove_old_orders().
Als nächst kucken mir ob d'Gläichgewiicht net genuch ass fir d'Bezuelung, da betruechte mir datt dëst net eng Wette ass, awer eng Erhuelung a späichert d'Ersatzstéck an orders.
Dann endlech d'Essenz vum Smart Kontrakt.
Als éischt, wann de Spiller verléiert, späichere mir et an der Wettengeschicht a wann de Betrag méi wéi 3 Gramm ass, schécken mir 1/3 un de Besëtzer vum Smart Kontrakt.
Wann de Spiller gewënnt, da schécken mir duebel de Betrag op d'Adress vum Spiller an späichert dann d'Informatioun iwwer d'Wette an der Geschicht.
() 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));
}
Elo alles wat bleift ass einfach, loosst eis Get-Methoden erstellen, fir datt mir Informatioun iwwer den Zoustand vum Kontrakt vun der Äussewelt kréien (tatsächlech liesen d'Donnéeën aus hirem Smart Kontraktlagerung).
Ech hunn och vergiess de Code derbäi ze ginn, deen déi éischt Ufro veraarbecht, déi geschitt wann Dir e Smart Kontrakt publizéiert. Entspriechend Verpflichtung. A weider korrigéiert Feeler mat 1/3 vum Betrag op de Kont vum Besëtzer ze schécken.
De nächste Schrëtt ass de Smart Kontrakt ze publizéieren. Loosst eis en Dossier erstellen requests.
Eppes derwäert opmierksam ze maachen. Mir generéieren e Smart Kontrakt Stockage an en Input Message. Duerno gëtt d'Adress vum Smart Kontrakt generéiert, dat heescht, d'Adress ass och virun der Verëffentlechung am TON bekannt. Als nächst musst Dir e puer Gramm op dës Adress schécken, an nëmmen duerno musst Dir e Fichier mam Smart Kontrakt selwer schécken, well d'Netzwierk eng Kommissioun hëlt fir de Smart Kontrakt an d'Operatiounen dran ze späicheren (Validateuren déi Smart späicheren an ausféieren Kontrakter). De Code kann hei gekuckt ginn.
Als nächst maache mir de Verëffentlechungscode aus a kréien lottery-query.boc Smart Kontrakt Datei an Adress.
A mir wäerte gesinn datt de Kont mat dëser Adress eidel ass.
account state is empty
Mir schécken op d'Adress 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 Gramm an no e puer Sekonnen fuere mir datselwecht Kommando aus. Ze schécken Gramm benotzen ech offiziell Portemonnaie, an Dir kënnt een aus dem Chat fir Testgramm froen, iwwer déi ech um Enn vum Artikel schwätzen.
Entspriechend Verpflichtung mat Ännerungen hei riets.
Loosst eis elo Ufroe erstellen fir mam Smart Kontrakt ze interagéieren.
Méi präzis, wäerte mir déi éischt verloossen fir d'Adress als onofhängeg Aarbecht z'änneren, a mir wäerten déi zweet maachen fir Gramm op d'Adress vum Besëtzer ze schécken. Tatsächlech musse mir datselwecht maachen wéi am Test fir Gramm ze schécken.
Dëst ass de Message dee mir un de Smart Kontrakt schécken, wou msg_seqno 165, action 2 an 9.5 Gramm fir schécken.
<b 165 32 u, 2 7 u, 9500000000 Gram, b>
Vergiesst net de Message mat Ärem private Schlëssel z'ënnerschreiwen lottery.pk, déi virdru generéiert gouf beim Schafe vum Smart Kontrakt. Hei ass déi entspriechend Verpflichtung.
Kritt Informatioun vun engem Smart Kontrakt mat Get Methoden
Loosst eis elo kucken wéi Dir Smart Kontrakt Get Methoden ausféiert.
Lancéiere lite-client a lafen d'Get-Methoden déi mir geschriwwen hunn.
Mir benotze Lite-Client a kréien Methoden fir Informatioun iwwer de Smart Kontrakt um Site ze weisen.
Weist Smart Kontrakt Daten op der Websäit
Ech hunn eng einfach Websäit am Python geschriwwen fir d'Donnéeën vum Smart Kontrakt op eng bequem Manéier ze weisen. Hei wäert ech net am Detail op et ophalen a wäert de Site publizéieren an engem Engagement.
Ufro un TON sinn gemaach vun Python mat der Hëllef vun lite-client. Fir d'Bequemlechkeet ass de Site am Docker verpackt a publizéiert op Google Cloud. Link.
Loosst eis probéieren
Loosst eis elo probéieren Gramm dohinner ze schécken fir Ersatz vun Portemonnaie. Mir schécken 40 Gramm. A loosst eis e puer Wette fir Kloerheet maachen. Mir gesinn, datt de Site d'Geschicht vun Spillwette weist, déi aktuell Gewënn Prozentsaz an aner nëtzlech Informatiounen.
Mir gesinndatt mir déi éischt gewonnen hunn, déi zweet verluer.
Afterword
Den Artikel war vill méi laang wéi ech erwaart hunn, vläicht hätt et méi kuerz gewiescht, oder vläicht just fir eng Persoun déi näischt iwwer TON weess an en net sou einfachen Smart Kontrakt mat der Fäegkeet ze interagéieren wëll schreiwen a publizéieren et. Villäicht hätt een e puer Saache méi einfach kënnen erklären.
Vill Aspekter vun der Ëmsetzung hätte vläicht méi effizient an elegant kënne gemaach ginn, mä dann hätt et nach méi Zäit gedauert fir den Artikel virzebereeden. Et ass och méiglech datt ech iergendwou e Feeler gemaach hunn oder eppes net verstanen hunn, also wann Dir eppes sérieux maacht, musst Dir op déi offiziell Dokumentatioun oder den offiziellen Repository mam TON Code vertrauen.
Et sollt bemierkt datt well TON selwer nach ëmmer an der aktiver Etapp vun der Entwécklung ass, Ännerungen kënnen optrieden, déi irgendeng vun de Schrëtt an dësem Artikel briechen (wat geschitt wärend ech geschriwwen hunn, et ass scho korrigéiert), awer déi allgemeng Approche ass onwahrscheinlech ze änneren.
Ech wäert net iwwer d'Zukunft vun TON schwätzen. Vläicht wäert d'Plattform eppes Grousses ginn a mir sollten Zäit verbréngen fir se ze studéieren an elo eng Nisch mat eise Produkter ze fëllen.
Et gëtt och Libra vu Facebook, déi e potenzielle Publikum vu Benotzer méi grouss wéi TON huet. Ech weess bal näischt iwwer Libra, vum Forum beurteelen ass et vill méi Aktivitéit do wéi an der TON Gemeinschaft. Och wann d'Entwéckler an d'Gemeinschaft vun TON méi wéi ënnerierdesch sinn, wat och cool ass.
Chat iwwer TON am Telegram, wat wierklech gehollef huet et an der éischter Etapp erauszefannen. Ech mengen et wäert kee Feeler sinn wann ech soen datt jiddereen deen eppes fir TON geschriwwen huet do ass. Dir kënnt och Testgramm do froen. https://t.me/tondev_ru
En aneren Chat iwwer TON an deem ech nëtzlech Informatioun fonnt hunn: https://t.me/TONgramDev