Pri kiel skribi kaj publikigi inteligentan kontrakton en TON
Pri kio temas ĉi tiu artikolo?
En la artikolo mi parolos pri kiel mi partoprenis en la unua (el du) Telegram-blokĉeno-konkurso, ne prenis premion, kaj decidis registri mian sperton en artikolo, por ke ĝi ne enprofundiĝu en forgeson kaj, eble, helpi. iu.
Ĉar mi ne volis skribi abstraktan kodon, sed fari ion laborantan, por la artikolo mi verkis inteligentan kontrakton por tuja loterio kaj retejon, kiu montras inteligentajn kontraktajn datumojn rekte de TON sen uzi mezan stokadon.
La artikolo estos utila al tiuj, kiuj volas fari sian unuan inteligentan kontrakton en TON, sed ne scias kie komenci.
Uzante la loterion kiel ekzemplon, mi iros de instali la medion al publikigado de inteligenta kontrakto, interagado kun ĝi kaj verkado de retejo por ricevi kaj publikigi datumojn.
Pri partopreno en la konkurso
La pasintan oktobron, Telegram anoncis konkurson pri blokĉeno kun novaj lingvoj Fift и FunC. Necesis elekti de verki iun el la kvin proponitaj inteligentaj kontraktoj. Mi pensis, ke estus bone fari ion alian, lerni lingvon kaj fari ion, eĉ se mi ne devos skribi ion alian estonte. Krome, la temo estas konstante sur la lipoj.
Indas diri, ke mi ne havis sperton pri disvolvi inteligentajn kontraktojn.
Mi planis partopreni ĝis la fino ĝis mi povos kaj poste verki recenzan artikolon, sed mi malsukcesis tuj ĉe la unua. mi kun plursubskribo sur FunC kaj ĝi ĝenerale funkciis. Mi prenis ĝin kiel bazon .
Tiutempe mi pensis, ke tio certe sufiĉas por preni almenaŭ ian premion. Rezulte, ĉirkaŭ 40 el 60 partoprenantoj iĝis premiitoj kaj mi ne estis inter ili. Ĝenerale ĉi tio estas nenio malbona, sed unu afero ĝenis min. En la momento de la anonco de la rezultoj, la revizio de la testo por mia kontrakto ne estis farita, mi demandis al la partoprenantoj en la babilejo, ĉu estas iu alia, kiu ne havas ĝin, ne estis.
Ŝajne atentante miajn mesaĝojn, du tagojn poste la juĝistoj publikigis komenton kaj mi ankoraŭ ne komprenas, ĉu ili hazarde maltrafis mian inteligentan kontrakton dum la juĝado aŭ simple pensis, ke ĝi estas tiel malbona, ke ĝi ne bezonas komenton. Mi faris demandon sur la paĝo, sed ne ricevis respondon. Kvankam ne estas sekreto kiu juĝis, mi konsideris nenecesa skribi personajn mesaĝojn.
Oni elspezis multe da tempo por kompreni, do oni decidis verki artikolon. Ĉar ankoraŭ ne ekzistas multaj informoj, ĉi tiu artikolo helpos ŝpari tempon por ĉiuj interesatoj.
La koncepto de inteligentaj kontraktoj en TON
Antaŭ ol vi skribas ion ajn, vi devas eltrovi de kiu flanko alproksimigi ĉi tiun aferon. Tial nun mi diros al vi, el kiuj partoj konsistas la sistemo. Pli precize, kiajn partojn vi bezonas scii por verki almenaŭ ian laborkontrakton.
Ni koncentriĝos pri verkado de inteligenta kontrakto kaj laborado kun TON Virtual Machine (TVM), Fift и FunC, do la artikolo pli similas al priskribo de la evoluo de regula programo. Ni ne traktos kiel la platformo mem funkcias ĉi tie.
Ĝenerale pri kiel ĝi funkcias TVM kaj lingvo Fift estas bona oficiala dokumentaro. Partoprenante en la konkurso kaj nun skribante la nunan kontrakton, mi ofte turnis min al ŝi.
La ĉefa lingvo en kiu inteligentaj kontraktoj estas skribitaj estas FunC. Ne estas dokumentaro pri ĝi nuntempe, do por skribi ion vi devas studi ekzemplojn de inteligentaj kontraktoj el la oficiala deponejo kaj la efektivigon de la lingvo mem tie, krome vi povas rigardi ekzemplojn de inteligentaj kontraktoj el la pasintaj du. konkursoj. Ligiloj ĉe la fino de la artikolo.
Ni diru, ke ni jam skribis inteligentan kontrakton por FunC, post tio ni kompilas la kodon en Fift-asemblero.
La kompilita inteligenta kontrakto restas publikigota. Por fari tion, vi devas skribi funkcion en Fift, kiu prenos la inteligentan kontraktokodon kaj iujn aliajn parametrojn kiel enigaĵon, kaj la eligo estos dosiero kun la etendo .boc (kiu signifas "sako da ĉeloj"), kaj, depende de kiel ni skribas ĝin, privatan ŝlosilon kaj adreson, kiu estas generita surbaze de la inteligenta kontraktokodo. Vi jam povas sendi gramojn al la adreso de inteligenta kontrakto, kiu ankoraŭ ne estis publikigita.
Eldoni inteligentan kontrakton en TON ricevita .boc la dosiero devos esti sendita al la blokĉeno uzante malpezan klienton (pli pri tio ĉi sube). Sed antaŭ ol publikigi, vi devas translokigi gramojn al la generita adreso, alie la inteligenta kontrakto ne estos publikigita. Post publikigo, vi povas interagi kun la inteligenta kontrakto sendante al ĝi mesaĝojn de ekstere (ekzemple, uzante malpezan klienton) aŭ de interne (ekzemple, unu inteligenta kontrakto sendas al alia mesaĝon ene de TON).
Post kiam ni komprenas kiel la kodo estas publikigita, ĝi fariĝas pli facila. Ni proksimume scias kion ni volas skribi kaj kiel nia programo funkcios. Kaj skribante, ni serĉas kiel ĉi tio jam estas efektivigita en ekzistantaj inteligentaj kontraktoj, aŭ ni rigardas la efektivigkodon Fift и FunC en la oficiala deponejo, aŭ rigardu en la oficiala dokumentaro.
Tre ofte mi serĉis ŝlosilvortojn en la Telegram-babilejo kie kunvenis ĉiuj konkursanoj kaj Telegram-dungitoj, kaj okazis, ke dum la konkurso ĉiuj kunvenis tie kaj komencis diskuti Fift kaj FunC. Ligo ĉe la fino de la artikolo.
Estas tempo transiri de teorio al praktiko.
Preparante la medion por labori kun TON
Mi faris ĉion, kio estos priskribita en la artikolo pri MacOS, kaj duoble kontrolis ĝin pure. Ubuntu 18.04 LTS ĉe Docker.
La unua afero, kiun vi devas fari, estas elŝuti kaj instali lite-client per kiu vi povas sendi petojn al TON.
La instrukcioj en la oficiala retejo priskribas la instalan procezon sufiĉe detale kaj klare, preterlasante kelkajn detalojn. Ĉi tie ni sekvas la instrukciojn, instalante iujn ajn mankantajn dependecojn laŭvoje. Mi ne kompilis ĉiun projekton mem kaj instalis el la oficiala deponejo. Ubuntu (sur MacOS mi uzis 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 Post kiam ĉiuj dependecoj estas instalitaj, vi povas instali lite-client, Fift, FunC.
Unue, ni klonas la TON-deponejon kune kun ĝiaj dependecoj. Por komforto, ni faros ĉion en dosierujo ~/TON.
cd ~/TON
git clone https://github.com/ton-blockchain/ton.git
cd ./ton
git submodule update --init --recursiveLa deponejo ankaŭ stokas efektivigojn Fift и FunC.
Nun ni pretas kunmeti la projekton. La deponeja kodo estas klonita en dosierujon ~/TON/ton. la ~/TON krei dosierujon build kaj kolektu la projekton en ĝi.
mkdir ~/TON/build
cd ~/TON/build
cmake ../tonĈar ni skribos inteligentan kontrakton, ni bezonas ne nur lite-clientSed Fift с FunC, do ni kompilu ĉion. Ĝi ne estas rapida procezo, do ni atendas.
cmake --build . --target lite-client
cmake --build . --target fift
cmake --build . --target funcPoste, elŝutu la agordan dosieron, kiu enhavas datumojn pri la nodo al kiu lite-client konektos.
wget https://test.ton.org/ton-lite-client-test1.config.jsonFarante la unuajn petojn al TON
Nun ni lanĉu lite-client.
cd ~/TON/build
./lite-client/lite-client -C ton-lite-client-test1.config.jsonSe la konstruo sukcesis, tiam post lanĉo vi vidos protokolon pri la konekto de la malpeza kliento al la nodo.
[ 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)
...Vi povas ruli la komandon help kaj vidu, kiaj komandoj disponeblas.
helpNi listigu la komandojn, kiujn ni uzos en ĉi tiu artikolo.
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-методы смартконтракта. Nun ni pretas skribi la kontrakton mem.
Реализация
Ideo
Kiel mi skribis supre, la inteligenta kontrakto, kiun ni skribas, estas loterio.
Krome, ĉi tio ne estas loterio, en kiu vi devas aĉeti bileton kaj atendi horon, tagon aŭ monaton, sed tuja, en kiu la uzanto translokiĝas al la kontrakto-adreso. N gramojn, kaj tuj reakiras ĝin 2 * N gramojn aŭ perdas. Ni faros la probablecon gajni ĉirkaŭ 40%. Se ne estas sufiĉe da gramoj por pago, tiam ni konsideros la transakcion kiel aldonaĵon.
Krome, gravas, ke vetoj povas esti viditaj en reala tempo kaj en oportuna formo, por ke la uzanto tuj komprenu ĉu li venkis aŭ perdis. Tial vi devas fari retejon, kiu montros vetojn kaj rezultojn rekte de TON.
Skribante inteligentan kontrakton
Por komforto, mi emfazis la kodon por FunC; la kromprogramon troveblas kaj instaleblas en la serĉo de Visual Studio Code; se vi subite volas aldoni ion, mi disponigis la kromprogramon publike. Ankaŭ, iu antaŭe faris kromprogramon por labori kun Fift, vi ankaŭ povas instali ĝin kaj trovi ĝin en VSC.
Ni tuj kreu deponejon, kie ni transdonos la mezajn rezultojn.
Por faciligi nian vivon, ni skribos inteligentan kontrakton kaj testos ĝin loke ĝis ĝi estos preta. Nur post tio ni publikigos ĝin en TON.
La inteligenta kontrakto havas du eksterajn metodojn alireblajn. Unue, recv_external() ĉi tiu funkcio estas efektivigita kiam peto al la kontrakto venas de la ekstera mondo, tio estas, ne de TON, ekzemple, kiam ni mem generas mesaĝon kaj sendas ĝin tra la lite-kliento. Due, recv_internal() jen kiam, ene de TON mem, ajna kontrakto rilatas al la nia. En ambaŭ kazoj, vi povas transdoni parametrojn al la funkcio.
Ni komencu per simpla ekzemplo, kiu funkcios se eldonita, sed ne estas funkcia ŝarĝo en ĝi.
() recv_internal(slice in_msg) impure {
;; TODO: implementation
}
() recv_external(slice in_msg) impure {
;; TODO: implementation
}Ĉi tie ni devas klarigi kio ĝi estas slice. Ĉiuj datumoj stokitaj en TON Blockchain estas kolekto TVM cell aŭ simple cell, en tia ĉelo vi povas konservi ĝis 1023 bitojn da datumoj kaj ĝis 4 ligilojn al aliaj ĉeloj.
TVM cell slice aŭ slice ĉi tio estas parto de la ekzistanta cell estas uzata por analizi ĝin, ĝi evidentiĝos poste. La ĉefa afero por ni estas, ke ni povas translokiĝi slice kaj depende de la speco de mesaĝo, prilaboru la datumojn recv_external() aŭ recv_internal().
impure — ŝlosilvorto, kiu indikas, ke la funkcio modifas inteligentajn kontraktajn datumojn.
Ni konservu la kontraktokodon lottery-code.fc kaj kompili.
~/TON/build/crypto/func -APSR -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fc La signifo de la flagoj povas esti vidita per la komando
~/TON/build/crypto/func -helpNi kompilis Fift-asemblerkodon en 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Ĝi povas esti lanĉita surloke, por tio ni preparos la medion.
Notu, ke la unua linio ligas Asm.fif, ĉi tio estas kodo skribita en Fift por la Fift-asemblero.
Ĉar ni volas ruli kaj testi la inteligentan kontrakton loke, ni kreos dosieron lottery-test-suite.fif kaj kopiu la kompilitan kodon tie, anstataŭigante la lastan linion en ĝi, kiu skribas la inteligentan kontraktokodon al konstanto codepor poste transdoni ĝin al la virtuala maŝino:
"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
Ĝis nun ŝajnas klare, nun ni aldonu al la sama dosiero la kodon, kiun ni uzos por lanĉi TVM.
0 tuple 0x076ef1ea , // magic
0 , 0 , // actions msg_sents
1570998536 , // unix_time
1 , 1 , 3 , // block_lt, trans_lt, rand_seed
0 tuple 100000000000000 , dictnew , , // remaining balance
0 , dictnew , // contract_address, global_config
1 tuple // wrap to another tuple
constant c7
0 constant recv_internal // to run recv_internal()
-1 constant recv_external // to invoke recv_external()В c7 ni registras la kuntekston, tio estas, la datumojn per kiuj la TVM (aŭ retoŝtato) estos lanĉita. Eĉ dum la konkurso, unu el la programistoj montris kiel krei c7 kaj mi kopiis. En ĉi tiu artikolo ni eble bezonos ŝanĝi rand_seed ĉar la generacio de hazarda nombro dependas de ĝi kaj se ne ŝanĝita, la sama nombro estos redonita ĉiufoje.
recv_internal и recv_external konstantoj kun valoroj 0 kaj -1 respondecas pri vokado de la respondaj funkcioj en la inteligenta kontrakto.
Nun ni pretas krei la unuan teston por nia malplena inteligenta kontrakto. Por klareco, nuntempe ni aldonos ĉiujn provojn al la sama dosiero lottery-test-suite.fif.
Ni kreu variablon storage kaj skribu malplenan en gxin cell, ĉi tio estos la inteligenta kontrakto-stokado.
message Ĉi tiu estas la mesaĝo, kiun ni transdonos al la inteligenta kontakto de ekstere. Ni ankaŭ malplenigos ĝin nuntempe.
variable storage
<b b> storage !
variable message
<b b> message ! Post kiam ni preparis la konstantojn kaj variablojn, ni lanĉas TVM per la komando runvmctx kaj transdonu la kreitajn parametrojn al la enigo.
message @
recv_external
code
storage @
c7
runvmctx Fine ni sukcesos meza kodo por Fift.
Nun ni povas ruli la rezultan kodon.
export FIFTPATH=~/TON/ton/crypto/fift/lib // выполняем один раз для удобства
~/TON/build/crypto/fift -s lottery-test-suite.fif La programo devus funkcii sen eraroj kaj en la eligo ni vidos la ekzekutprotokolo:
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=0Bonege, ni skribis la unuan funkciantan version de la inteligenta kontrakto.
Nun ni devas aldoni funkciojn. Unue ni traktu mesaĝojn, kiuj venas de la ekstera mondo al recv_external()
La programisto mem elektas la mesaĝoformaton, kiun la kontrakto povas akcepti.
Sed kutime
- unue, ni volas protekti nian kontrakton de la ekstera mondo kaj fari ĝin tiel ke nur la posedanto de la kontrakto povas sendi eksterajn mesaĝojn al ĝi.
- due, kiam ni sendas validan mesaĝon al TON, ni volas, ke ĉi tio okazu ĝuste unufoje kaj kiam ni sendas la saman mesaĝon denove, la inteligenta kontrakto malakceptas ĝin.
Do preskaŭ ĉiu kontrakto solvas ĉi tiujn du problemojn, ĉar nia kontrakto akceptas eksterajn mesaĝojn, ni ankaŭ devas zorgi pri tio.
Ni faros ĝin en inversa ordo. Unue, ni solvu la problemon per ripeto; se la kontrakto jam ricevis tian mesaĝon kaj prilaboris ĝin, ĝi ne plenumos ĝin duan fojon. Kaj tiam ni solvos la problemon por ke nur certa rondo de homoj povu sendi mesaĝojn al la inteligenta kontrakto.
Estas malsamaj manieroj solvi la problemon kun duplikataj mesaĝoj. Jen kiel ni faros ĝin. En la inteligenta kontrakto, ni pravigas la nombrilon de ricevitaj mesaĝoj kun la komenca valoro 0. En ĉiu mesaĝo al la inteligenta kontrakto, ni aldonos la nunan nombrilon valoron. Se la nombrilo en la mesaĝo ne kongruas kun la valoro en la inteligenta kontrakto, tiam ni ne prilaboras ĝin; se ĝi faras, tiam ni procesas ĝin kaj pliigas la nombrilon en la inteligenta kontrakto je 1.
Ni revenu al lottery-test-suite.fif kaj aldonu al ĝi duan provon. Se ni sendas malĝustan numeron, la kodo devus ĵeti escepton. Ekzemple, lasu la kontraktajn datumojn stoki 166, kaj ni sendos 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"Ni lanĉu.
~/TON/build/crypto/fift -s lottery-test-suite.fif Kaj ni vidos, ke la testo estas efektivigita kun eraro.
[ 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 passedEn ĉi tiu etapo lottery-test-suite.fif devus aspekti kiel .
Nun ni aldonu la kontraŭlogikon al la inteligenta kontrakto en 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 mensogas la mesaĝo, kiun ni sendas.
La unua afero, kiun ni faras, estas kontroli ĉu la mesaĝo enhavas datumojn, se ne, tiam ni simple eliras.
Poste ni analizas la mesaĝon. in_msg~load_uint(32) ŝarĝas la numeron 165, 32-bit unsigned int de la elsendita mesaĝo.
Poste ni ŝarĝas 32 bitojn el la inteligenta kontrakto-stokado. Ni kontrolas, ke la ŝarĝita nombro kongruas kun la preterpasita; se ne, ni ĵetas escepton. En nia kazo, ĉar ni pasas ne-matĉon, escepto devus esti ĵetita.
Nun ni kompilu.
~/TON/build/crypto/func -APSR -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fc Kopiu la rezultan kodon al lottery-test-suite.fif, ne forgesante anstataŭigi la lastan linion.
Ni kontrolas, ke la testo trapasas:
~/TON/build/crypto/fift -s lottery-test-suite.fifVi povas vidi la respondan devontigon kun la nunaj rezultoj.
Notu, ke estas maloportune konstante kopii la kompilitan kodon de inteligenta kontrakto en dosieron kun testoj, do ni skribos skripton, kiu skribos la kodon en konstanton por ni, kaj ni simple konektos la kompilitan kodon al niaj testoj uzante "include".
Kreu dosieron en la projekta dosierujo build.sh kun la sekva enhavo.
#!/bin/bash
~/TON/build/crypto/func -SPA -R -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fcNi faru ĝin efektivigebla.
chmod +x ./build.shNun, nur rulu nian skripton por kompili la kontrakton. Sed krom ĉi tio, ni devas skribi ĝin en konstanton code. Do ni kreos novan dosieron lotter-compiled-for-test.fif, kiun ni inkludos en la dosieron lottery-test-suite.fif.
Ni aldonu skipkodon al sh, kiu simple duobligos la kompilitan dosieron enen lotter-compiled-for-test.fif kaj ŝanĝu la lastan linion en ĝi.
# 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.fifNun, por kontroli, ni rulu la rezultan skripton kaj dosiero estos generita lottery-compiled-for-test.fif, kiun ni inkludos en nia lottery-test-suite.fif
В lottery-test-suite.fif forigu la kontraktokodon kaj aldonu la linion "lottery-compiled-for-test.fif" include.
Ni faras provojn por kontroli, ke ili trapasas.
~/TON/build/crypto/fift -s lottery-test-suite.fifBonege, nun por aŭtomatigi la lanĉon de testoj, ni kreu dosieron test.sh, kiu unue efektivigos build.sh, kaj poste rulu la testojn.
touch test.sh
chmod +x test.shNi skribas interne
./build.sh
echo "nCompilation completedn"
export FIFTPATH=~/TON/ton/crypto/fift/lib
~/TON/build/crypto/fift -s lottery-test-suite.fifNi faru ĝin test.sh kaj rulu ĝin por certigi, ke la testoj funkcias.
chmod +x ./test.sh
./test.shNi kontrolas, ke la kontrakto kompilas kaj la testoj estas plenumitaj.
Bonege, nun ĉe ekfunkciigo test.sh La testoj estos kompilitaj kaj kuritaj tuj. Jen la ligilo al .
Bone, antaŭ ol ni daŭrigu, ni faru ankoraŭ unu aferon por oportuno.
Ni kreu dosierujon build kie ni stokos la kopiitan kontrakton kaj ĝian klonon skribitan en konstanton lottery-compiled.fif, lottery-compiled-for-test.fif. Ni ankaŭ kreu dosierujon test kie la testdosiero estos konservita? lottery-test-suite.fif kaj eble aliaj subtenaj dosieroj. .
Ni daŭre disvolvu la inteligentan kontrakton.
Poste devus esti testo, kiu kontrolas, ke la mesaĝo estas ricevita kaj la nombrilo estas ĝisdatigita en la vendejo kiam ni sendas la ĝustan numeron. Sed ni faros tion poste.
Nun ni pensu pri kia datumstrukturo kaj kiaj datumoj devas esti stokitaj en la inteligenta kontrakto.
Mi priskribos ĉion, kion ni stokas.
`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` переменная типа словарь, хранит последние двадцать ставок. Poste vi devas skribi du funkciojn. Ni voku la unuan pack_state(), kiu pakos la datumojn por posta konservado en la inteligenta kontrakto-stokado. Ni voku la duan unpack_state() legos kaj resendos datumojn el stokado.
_ 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;
}Ni aldonas ĉi tiujn du funkciojn al la komenco de la inteligenta kontrakto. Ĝi funkcios meza rezulto.
Por konservi datumojn vi devos voki la enkonstruitan funkcion set_data() kaj ĝi skribos datumojn de pack_state() en la inteligenta kontrakto-stokado.
cell packed_state = pack_state(arg_1, .., arg_n);
set_data(packed_state);Nun kiam ni havas oportunajn funkciojn por skribi kaj legi datumojn, ni povas pluiri.
Ni devas kontroli, ke la mesaĝo envenanta de ekstere estas subskribita de la posedanto de la kontrakto (aŭ alia uzanto, kiu havas aliron al la privata ŝlosilo).
Kiam ni publikigas inteligentan kontrakton, ni povas pravalorigi ĝin per la datumoj, kiujn ni bezonas en stokado, kiuj estos konservitaj por estonta uzo. Ni registros la publikan ŝlosilon tie, por ke ni povu kontroli, ke la envenanta mesaĝo estis subskribita per la responda privata ŝlosilo.
Antaŭ ol daŭrigi, ni kreu privatan ŝlosilon kaj skribu ĝin al test/keys/owner.pk. Por fari tion, ni lanĉu Fift en interaga reĝimo kaj faru kvar komandojn.
`newkeypair` генерация публичного и приватного ключа и запись их в стек.
`drop` удаления из стека верхнего элемента (в данном случае публичный ключ)
`.s` просто посмотреть что лежит в стеке в данный момент
`"owner.pk" B>file` запись приватного ключа в файл с именем `owner.pk`.
`bye` завершает работу с Fift. Ni kreu dosierujon keys ene de la dosierujo test kaj skribu la privatan ŝlosilon tie.
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
byeNi vidas dosieron en la nuna dosierujo owner.pk.
Ni forigas la publikan ŝlosilon de la stako kaj kiam necesas ni povas ricevi ĝin de la privata.
Nun ni devas skribi subskriban konfirmon. Ni komencu per la testo. Unue ni legas la privatan ŝlosilon el la dosiero uzante la funkcion file>B kaj skribu ĝin al variablo owner_private_key, tiam uzante la funkcion priv>pub konverti la privatan ŝlosilon al publika ŝlosilo kaj skribu la rezulton enen 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 !Ni bezonos ambaŭ ŝlosilojn.
Ni pravigas la inteligentan kontrakton-stokadon kun arbitraj datumoj en la sama sinsekvo kiel en la funkcio pack_state()kaj skribu ĝin en variablon 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 !Poste, ni komponos subskribitan mesaĝon, ĝi enhavos nur la subskribon kaj la nombrilon.
Unue ni kreas la datumojn, kiujn ni volas transdoni, poste ni subskribas ĝin per privata ŝlosilo kaj fine ni generas subskribitan mesaĝon.
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 ! Kiel rezulto, la mesaĝo, kiun ni sendos al la inteligenta kontrakto, estas registrita en variablo message_to_send, pri funkcioj hashu, ed25519_sign_uint vi povas legi .
Kaj por ruli la teston ni vokas denove.
message_to_send @
recv_external
code
storage @
c7
runvmctxLa dosiero kun testoj devus aspekti tiel en ĉi tiu etapo.
Ni faru la teston kaj ĝi malsukcesos, do ni ŝanĝos la inteligentan kontrakton por ke ĝi povu ricevi mesaĝojn de ĉi tiu formato kaj kontroli la subskribon.
Unue, ni kalkulas 512 bitojn de la subskribo de la mesaĝo kaj skribas ĝin al variablo, tiam ni kalkulas 32 bitojn de la nombrilo variablo.
Ĉar ni havas funkcion por legi datumojn de la inteligenta kontrakto-stokado, ni uzos ĝin.
Poste estas kontroli la nombrilon transdonitan kun la stokado kaj kontroli la subskribon. Se io ne kongruas, tiam ni ĵetas escepton kun la taŭga kodo.
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));Rilata kompromiso .
Ni faru la provojn kaj vidu, ke la dua provo malsukcesas. Pro du kialoj, ne estas sufiĉe da bitoj en la mesaĝo kaj ne estas sufiĉe da bitoj en la stokado, do la kodo kraŝas dum analizado. Ni devas aldoni subskribon al la mesaĝo, kiun ni sendas, kaj kopii la stokadon de la lasta testo.
En la dua testo, ni aldonos mesaĝan subskribon kaj ŝanĝos la inteligentan kontrakton-stokadon. la dosiero kun testoj aspektas kiel nuntempe.
Ni skribu kvaran teston, en kiu ni sendos mesaĝon subskribitan per la privata ŝlosilo de aliulo. Ni kreu alian privatan ŝlosilon kaj konservu ĝin al dosiero not-owner.pk. Ni subskribos la mesaĝon per ĉi tiu privata ŝlosilo. Ni faru la testojn kaj certigu, ke ĉiuj testoj trapasas. en ĉi tiu momento.
Nun ni povas finfine pluiri al efektivigo de la inteligenta kontrakta logiko.
В recv_external() ni akceptos du specojn de mesaĝoj.
Ĉar nia kontrakto akumulos la perdojn de la ludantoj, ĉi tiu mono devas esti transdonita al la kreinto de la loterio. La monujo-adreso de la loteriokreinto estas registrita en la stokado kiam la kontrakto estas kreita.
Ĉiaokaze, ni bezonas la kapablon ŝanĝi la adreson, al kiu ni sendas gramojn de la perdantoj. Ni ankaŭ devus povi sendi gramojn de la loterio al la adreso de la posedanto.
Ni komencu per la unua. Ni unue skribu teston, kiu kontrolos, ke post sendi la mesaĝon, la inteligenta kontrakto konservis la novan adreson en la stokado. Bonvolu noti, ke en la mesaĝo, krom la vendotablo kaj la nova adreso, ni ankaŭ transdonas action 7-bita entjera nenegativa nombro, depende de ĝi, ni elektos kiel prilabori la mesaĝon en la inteligenta kontrakto.
<b 0 32 u, 1 @ 7 u, new_owner_wc @ 32 i, new_owner_account_id @ 256 u, b> message_to_sign !En la testo vi povas vidi kiel smartcontract-stokado estas deserialigita storage en Kvin. Deseriigo de variabloj estas priskribita en la Fift-dokumentaro.
kun aldonita pasto.
Ni faru la teston kaj certigu, ke ĝi malsukcesas. Nun ni aldonu logikon por ŝanĝi la adreson de la loterioposedanto.
En la inteligenta kontrakto ni daŭre analizas message, legu enen action. Ni memorigu vin, ke ni havos du action: ŝanĝu adreson kaj sendu gramojn.
Poste ni legas la novan adreson de la kontraktoposedanto kaj konservas ĝin en stokado.
Ni faras la provojn kaj vidas, ke la tria testo malsukcesas. Ĝi kraŝas pro tio, ke la kontrakto nun aldone analizas 7 bitojn de la mesaĝo, kiuj mankas en la testo. Aldonu neekzistantan al la mesaĝo action. Ni faru la provojn kaj vidu, ke ĉio trapasas. engaĝiĝu al ŝanĝoj. Bonege.
Nun ni skribu la logikon por sendi la specifitan nombron da gramoj al la antaŭe konservita adreso.
Unue, ni skribu teston. Ni skribos du provojn, unu kiam ne estas sufiĉe da ekvilibro, la dua kiam ĉio devus pasi sukcese. Testoj povas esti rigardataj .
Nun ni aldonu la kodon. Unue, ni skribu du helpajn metodojn. La unua akiri metodo estas ekscii la nunan bilancon de inteligenta kontrakto.
int balance() inline_ref method_id {
return get_balance().pair_first();
}Kaj la dua estas por sendi gramojn al alia inteligenta kontrakto. Mi tute kopiis ĉi tiun metodon de alia inteligenta kontrakto.
() 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
}Ni aldonu ĉi tiujn du metodojn al la inteligenta kontrakto kaj skribu la logikon. Unue, ni analizas la nombron da gramoj de la mesaĝo. Poste ni kontrolas la bilancon, se ĝi ne sufiĉas ni ĵetas escepton. Se ĉio estas en ordo, tiam ni sendas la gramojn al la konservita adreso kaj ĝisdatigas la nombrilon.
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));aspektas kiel la inteligenta kontrakto nuntempe. Ni faru la testojn kaj certigu, ke ili trapasas.
Cetere, komisiono estas subtrahita de la inteligenta kontrakto ĉiufoje por prilaborita mesaĝo. Por ke la inteligentaj kontraktomesaĝoj plenumu la peton, post bazaj kontroloj vi devas telefoni accept_message().
Nun ni transiru al internaj mesaĝoj. Fakte, ni nur akceptos gramojn kaj resendos duoble la kvanton al la ludanto se li gajnos kaj trionon al la posedanto se li perdas.
Unue, ni skribu simplan teston. Por fari tion, ni bezonas testan adreson de la inteligenta kontrakto de kiu ni supozeble sendas gramojn al la inteligenta kontrakto.
La inteligenta kontrakto-adreso konsistas el du nombroj, 32-bita entjero respondeca por la laborĉeno kaj 256-bita nenegativa entjera unika kontnumero en ĉi tiu laborĉeno. Ekzemple, -1 kaj 12345, ĉi tiu estas la adreso, kiun ni konservos al dosiero.
Mi kopiis la funkcion por konservi la adreson de .
// ( wc addr fname -- ) Save address to file in 36-byte format
{ -rot 256 u>B swap 32 i>B B+ swap B>file } : save-addressNi rigardu kiel funkcias la funkcio, ĉi tio donos komprenon pri kiel funkcias Fift. Lanĉu Fift en interaga reĝimo.
~/TON/build/crypto/fift -i Unue ni puŝas -1, 12345 kaj la nomon de la estonta dosiero "sender.addr" sur la stakon:
-1 12345 "sender.addr" La sekva paŝo estas ekzekuti la funkcion -rot, kiu ŝanĝas la stakon tiel, ke ĉe la supro de la stako estas unika inteligenta kontraktonumero:
"sender.addr" -1 12345256 u>B konvertas 256-bitan nenegativan entjeron al bajtoj.
"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039swap interŝanĝas la suprajn du elementojn de la stako.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -132 i>B konvertas 32-bitan entjeron al bajtoj.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFFB+ ligas du sekvencojn de bajtoj.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFFDenove swap.
BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" Kaj finfine la bajtoj estas skribitaj al la dosiero B>file. Post tio nia stako estas malplena. Ni haltas Fift. Dosiero estis kreita en la nuna dosierujo sender.addr. Ni movu la dosieron al la kreita dosierujo test/addresses/.
Ni skribu simplan teston, kiu sendos gramojn al inteligenta kontrakto. .
Nun ni rigardu la logikon de la loterio.
La unua afero, kiun ni faras, estas kontroli la mesaĝon bounced aŭ ne se bounced, tiam ni ignoras ĝin. bounced signifas, ke la kontrakto resendos gramojn se iu eraro okazas. Ni ne resendos gramojn se eraro subite okazas.
Ni kontrolas, se la saldo estas malpli ol duona gramo, tiam ni simple akceptas la mesaĝon kaj ignoras ĝin.
Poste, ni analizas la adreson de la inteligenta kontrakto de kiu venis la mesaĝo.
Ni legas la datumojn el la stokado kaj poste forigas malnovajn vetojn el la historio se estas pli ol dudek el ili. Por komforto, mi skribis tri pliajn funkciojn pack_order(), unpack_order(), remove_old_orders().
Poste, ni rigardas se la saldo ne sufiĉas por la pago, tiam ni konsideras, ke ĉi tio ne estas veto, sed replenigo kaj ŝparu la replenigon en orders.
Tiam finfine la esenco de la inteligenta kontrakto.
Unue, se la ludanto perdas, ni konservas ĝin en la veta historio kaj se la kvanto estas pli ol 3 gramoj, ni sendas 1/3 al la posedanto de la inteligenta kontrakto.
Se la ludanto gajnas, tiam ni sendas duoble la kvanton al la adreso de la ludanto kaj poste konservas la informojn pri la veto en la historio.
() 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));
}Jen ĉio. .
Nun ĉio, kio restas, estas simpla, ni kreu get-metodojn por ke ni povu akiri informojn pri la stato de la kontrakto de la ekstera mondo (fakte, legu la datumojn de ilia inteligenta kontrakto-stokado).
. Ni skribos sube pri kiel ricevi informojn pri inteligenta kontrakto.
Mi ankaŭ forgesis aldoni la kodon, kiu prilaboros la plej unuan peton, kiu okazas dum publikigado de inteligenta kontrakto. . Kaj plu cimo kun sendado de 1/3 de la kvanto al la konto de la posedanto.
La sekva paŝo estas publikigi la inteligentan kontrakton. Ni kreu dosierujon requests.
Mi prenis la publikigkodon kiel bazon kiu en la oficiala deponejo.
Io atentinda. Ni generas inteligentan kontrakton-stokadon kaj enigmesaĝon. Post ĉi tio, la adreso de la inteligenta kontrakto estas generita, tio estas, la adreso estas konata eĉ antaŭ publikigo en TON. Tiam vi devas sendi plurajn gramojn al ĉi tiu adreso, kaj nur post tio vi devas sendi dosieron kun la inteligenta kontrakto mem, ĉar la reto prenas komisionon por stoki la inteligentan kontrakton kaj operaciojn en ĝi (validigiloj, kiuj stokas kaj plenumas inteligentajn kontraktojn. ). .
Poste ni plenumas la eldonkodon kaj ricevas lottery-query.boc inteligenta kontrakto dosiero kaj adreso.
~/TON/build/crypto/fift -s requests/new-lottery.fif 0Ne forgesu konservi la generitajn dosierojn: lottery-query.boc, lottery.addr, lottery.pk.
Interalie, ni vidos la adreson de la inteligenta kontrakto en la ekzekutprotokoloj.
new wallet address = 0:044910149dbeaf8eadbb2b28722e7d6a2dc6e264ec2f1d9bebd6fb209079bc2a
(Saving address to file lottery.addr)
Non-bounceable address (for init): 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd
Bounceable address (for later access): kQAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KpFYNur por amuzo, ni faru peton al TON
$ ./lite-client/lite-client -C ton-lite-client-test1.config.json
getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydKaj ni vidos, ke la konto kun ĉi tiu adreso estas malplena.
account state is emptyNi sendas al la adreso 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 Gramo kaj post kelkaj sekundoj ni plenumas la saman komandon. Por sendi gramojn mi uzas , kaj vi povas peti iun el la babilejo pri testgramoj, pri kiuj mi parolos fine de la artikolo.
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydAspektas kiel nekomencigita (state:account_uninit) inteligenta kontrakto kun la sama adreso kaj saldo de 1 nanogramoj.
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 2000000000ngNun ni publikigu la inteligentan kontrakton. Ni lanĉu lite-klienton kaj ekzekutu.
> 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 Ni kontrolu, ke la kontrakto estas publikigita.
> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydInteralie ni ricevas.
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_activeNi vidas tion account_active.
Korespondanta kompromiso kun ŝanĝoj .
Nun ni kreu petojn por interagi kun la inteligenta kontrakto.
Pli precize, ni lasos la unuan por ŝanĝi la adreson kiel sendependan verkon, kaj ni faros la duan por sendi gramojn al la adreso de la posedanto. Fakte, ni devos fari la samon kiel en la provo por sendi gramojn.
Ĉi tiu estas la mesaĝo, kiun ni sendos al la inteligenta kontrakto, kie msg_seqno 165, action 2 kaj 9.5 gramoj por sendo.
<b 165 32 u, 2 7 u, 9500000000 Gram, b>Ne forgesu subskribi la mesaĝon per via privata ŝlosilo lottery.pk, kiu estis generita pli frue dum kreado de la inteligenta kontrakto. .
Ricevante informojn de inteligenta kontrakto per get-metodoj
Nun ni rigardu kiel ruli inteligentajn kontraktojn akiri metodojn.
Lanĉo lite-client kaj rulu la get-metodojn, kiujn ni skribis.
$ ./lite-client/lite-client -C ton-lite-client-test1.config.json
> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd balance
arguments: [ 104128 ]
result: [ 64633878952 ]
...В result enhavas la valoron, kiun la funkcio redonas balance() de nia inteligenta kontrakto.
Ni faros la samon por pluraj pliaj metodoj.
> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_seqno
...
arguments: [ 77871 ]
result: [ 1 ] Ni petu vian vethistorion.
> 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]) ] Ni uzos lite-klienton kaj ricevos metodojn por montri informojn pri la inteligenta kontrakto en la retejo.
Montrante datumojn pri inteligentaj kontraktoj en la retejo
Mi skribis simplan retejon en Python por montri la datumojn de la inteligenta kontrakto en oportuna maniero. Ĉi tie mi ne detale detale pri ĝi kaj publikigos la retejon .
Petoj al TON estas faritaj de Python kun helpo de lite-client. Por komforto, la retejo estas pakita en Docker kaj publikigita sur Google Cloud. .
Provante
Nun ni provu sendi gramojn tien por replenigo de . Ni sendos 40 gramojn. Kaj ni faru kelkajn vetojn por klareco. Ni vidas, ke la retejo montras la historion de vetoj, la nunan gajnan procenton kaj aliajn utilajn informojn.
ke ni gajnis la unuan, perdis la duan.
Antaŭparolo
La artikolo montriĝis multe pli longa ol mi atendis, eble ĝi povus esti pli mallonga, aŭ eble nur por homo, kiu scias nenion pri TON kaj volas skribi kaj publikigi ne tiom simplan inteligentan kontrakton kun la kapablo interagi kun. ĝi. Eble iuj aferoj povus esti klarigitaj pli simple.
Eble iuj aspektoj de la efektivigo povus esti faritaj pli efike kaj elegante, sed tiam necesus eĉ pli da tempo por prepari la artikolon. Eblas ankaŭ, ke mi ie faris eraron aŭ ne komprenis ion, do se vi faras ion seriozan, vi devas fidi la oficiala dokumentaro aŭ la oficiala deponejo kun la TON-kodo.
Oni devas rimarki, ke ĉar TON mem estas ankoraŭ en la aktiva stadio de evoluo, povas okazi ŝanĝoj, kiuj rompos iun ajn el la paŝoj en ĉi tiu artikolo (kio okazis dum mi skribis, ĝi jam estis korektita), sed la ĝenerala aliro estas verŝajne ŝanĝiĝos.
Mi ne parolos pri la estonteco de TON. Eble la platformo fariĝos io granda kaj ni devus pasigi tempon studi ĝin kaj plenigi niĉon per niaj produktoj nun.
Ekzistas ankaŭ Libra de Facebook, kiu havas eblan publikon de uzantoj pli grandaj ol TON. Mi scias preskaŭ nenion pri Libra, se juĝante laŭ la forumo estas multe pli da aktivado tie ol en la TON-komunumo. Kvankam la programistoj kaj komunumo de TON estas pli kiel subtera, kio ankaŭ estas bonega.
referencoj
- Oficiala TON-dokumentado:
- Oficiala TON-deponejo:
- Oficiala monujo por malsamaj platformoj:
- Inteligenta kontrakta deponejo de ĉi tiu artikolo:
- Ligo al la retejo de inteligenta kontrakto:
- Deponejo por la etendaĵo por Visual Studio Code por FunC:
- Babilu pri TON en Telegramo, kio vere helpis eltrovi ĝin en la komenca etapo. Mi pensas, ke ne estos eraro, se mi diros, ke ĉiuj, kiuj skribis ion por TON, estas tie. Vi ankaŭ povas peti provajn gramojn tie.
- Alia babilado pri TON en kiu mi trovis utilajn informojn:
- Unua etapo de la konkurso:
- Dua etapo de la konkurso:
fonto: www.habr.com
