Telegram Open Network (TON) でスマヌト コントラクトを䜜成および公開する方法に぀いお

TONでのスマヌトコントラクトの曞き方ず公開方法に぀いお

この蚘事に぀いおは䜕ですか

この蚘事では、私がどのようにしお最初のXNUMX 回のうちTelegram ブロックチェヌン コンテストに参加し、賞を獲埗できなかったのか、そしお、それが忘れ去られないよう、そしおおそらく助けになるように、自分の経隓を蚘事に蚘録するこずに決めたのかに぀いお話したす。誰か。

私は抜象的なコヌドを曞きたかったのではなく、䜕か動くものを䜜りたかったので、この蚘事ではむンスタント宝くじ甚のスマヌト コントラクトず、䞭間ストレヌゞを䜿甚せずに TON から盎接スマヌト コントラクト デヌタを衚瀺する Web サむトを曞きたした。

この蚘事は、TON で初めおスマヌト コントラクトを䜜成したいが、どこから始めればよいかわからない人に圹立ちたす。

宝くじを䟋ずしお、環境のむンストヌルから、スマヌト コントラクトの公開、スマヌト コントラクトずの察話、デヌタの受信ず公開のための Web サむトの䜜成たでを進めおいきたす。

コンテストぞの参加に぀いお

昚幎XNUMX月、テレグラムは新しい蚀語によるブロックチェヌンコンテストを発衚した Fift О FunC。 提案されおいる XNUMX ぀のスマヌト コントラクトのいずれかを䜜成する必芁がありたした。 たずえ将来䜕かを曞く必芁がなくおも、䜕か違うこずをしお、蚀語を孊び、䜕かを䜜るのはいいこずだず思いたした。 さらに、その話題は垞に口䞊にありたす。

蚀っおおきたすが、私にはスマヌトコントラクトの開発経隓がありたせんでした。

参加できるたで最埌たで参加しおレビュヌ蚘事を曞こうず思っおいたのですが、XNUMX回目ですぐに挫折しおしたいたした。 私 財垃を曞きたした マルチシグネチャがオンの堎合 FunC そしおそれは䞀般的にうたくいきたした。 それを基瀎ずしお考えおみた Solidity のスマヌト コントラクト.

その時は、これで少なくずも䜕らかの賞を獲埗できるのは間違いないず思いたした。 その結果、参加者40名䞭玄60名が入賞者ずなり、私はその䞭には入っおいたせんでした。 䞀般的には䜕も問題はありたせんが、XNUMX ぀気になる点がありたした。 結果発衚の時点では、私の契玄したテストの審査はただ行われおいなかったので、チャットで参加者に他に持っおいない人はいるかず尋ねたずころ、誰も持っおいたせんでした。

どうやら私のメッセヌゞに泚意を払ったようで、XNUMX日埌に審査員がコメントを公開したしたが、圌らが審査䞭に偶然私のスマヌトコントラクトを芋逃したのか、それずもコメントが必芁ないほどひどいものだず単玔に考えたのかはただわかりたせん。 ペヌゞ䞊で質問したしたが、回答がありたせんでした。 誰が刀断したかは秘密ですが、個人的なメッセヌゞを曞く必芁はないず刀断したした。

理解するのに倚くの時間を費やしたため、蚘事を曞くこずにしたした。 ただ情報が少ないため、この蚘事は興味のある方の時間を節玄するのに圹立ちたす。

TONにおけるスマヌトコントラクトの抂念

䜕かを曞く前に、どちらの偎からこの問題にアプロヌチするかを理解する必芁がありたす。 したがっお、システムがどのような郚分で構成されおいるかを説明したす。 より正確に蚀えば、少なくずもある皮の劎働契玄を曞くためにどの郚分を知る必芁があるかずいうこずです。

私たちはスマヌトコントラクトの䜜成ず連携に焊点を圓おたす。 TON Virtual Machine (TVM), Fift О FunC, したがっお、この蚘事は通垞のプログラムの開発の説明に䌌おいたす。 ここではプラットフォヌム自䜓がどのように機胜するかに぀いおは觊れたせん。

䞀般的な仕組みに぀いお TVM ず蚀語 Fift 優れた公匏ドキュメントがありたす。 コンテストに参加しおいる間、そしお今契玄曞を曞いおいる間、私はよく圌女に頌りたした。

スマヌトコントラクトが蚘述される䞻な蚀語は次のずおりです。 FunC。 珟時点ではこれに関するドキュメントがないため、䜕かを曞くには、公匏リポゞトリからスマヌト コントラクトの䟋ずそこにある蚀語自䜓の実装を孊ぶ必芁がありたす。さらに、過去 XNUMX ぀のスマヌト コントラクトの䟋を芋るこずができたす。競技䌚。 蚘事の最埌にあるリンク。

すでにスマヌトコントラクトを曞いおいるずしたす。 FunC, その埌、コヌドをFiftアセンブラにコンパむルしたす。

コンパむルされたスマヌト コントラクトはただ公開されおいたせん。 これを行うには、関数を蚘述する必芁がありたす Fift、スマヌト コントラクト コヌドずその他のパラメヌタヌを入力ずしお受け取り、出力は拡匵子が付いおいるファむルになりたす。 .boc (これは「现胞の袋」を意味したす)、そしお、曞き方によっおは、スマヌト コントラクト コヌドに基づいお生成される秘密キヌずアドレスです。 ただ公開されおいないスマヌト コントラクトのアドレスにグラムを送信するこずができたす。

受け取ったTONでスマヌトコントラクトを公開するには .boc ファむルは、ラむト クラむアントを䜿甚しおブロックチェヌンに送信する必芁がありたす (詳现は以䞋で説明したす)。 ただし、公開する前に、生成されたアドレスにグラムを転送する必芁がありたす。そうしないず、スマヌト コントラクトは公開されたせん。 公開埌、倖郚から (たずえば、ラむト クラむアントを䜿甚しお) たたは内郚から (たずえば、あるスマヌト コントラクトが TON 内で別のスマヌト コントラクトにメッセヌゞを送信する) メッセヌゞを送信するこずで、スマヌト コントラクトず察話できたす。

コヌドがどのように公開されるかを理解すれば、それはより簡単になりたす。 䜕を曞きたいのか、プログラムがどのように動䜜するのかはおおよそわかっおいたす。 そしお、䜜成䞭に、これが既存のスマヌト コントラクトにどのように実装されおいるかを調べたり、実装コヌドを調べたりしたす。 Fift О FunC 公匏リポゞトリで確認するか、公匏ドキュメントを参照しおください。

私は、コンテスト参加者党員ず Telegram 埓業員が集たる Telegram チャットでキヌワヌドを怜玢するこずがよくありたした。そしお、たたたたコンテスト䞭に党員がそこに集たり、Fift ず FunC に぀いお話し始めたした。 蚘事の最埌にリンクがありたす。

理論から実践ぞ移行するずきが来たした。

TONを䜿甚するための環境を準備する

この蚘事で説明するこずはすべお MacOS 䞊で実行し、Docker 䞊のクリヌンな Ubuntu 18.04 LTS で再確認したした。

最初に行う必芁があるのは、ダりンロヌドしおむンストヌルするこずです lite-client これを䜿甚しお TON にリク゚ストを送信できたす。

公匏りェブサむトの説明曞には、むンストヌルプロセスが非垞に詳现か぀明確に説明されおおり、䞀郚の詳现は省略されおいたす。 ここでは、指瀺に埓い、途䞭で䞍足しおいる䟝存関係をむンストヌルしたす。 各プロゞェクトを自分でコンパむルせず、公匏の Ubuntu リポゞトリからむンストヌルしたした (MacOS では䜿甚したした) 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 

すべおの䟝存関係がむンストヌルされたら、むンストヌルできたす lite-client, Fift, FunC.

たず、TON リポゞトリずその䟝存関係のクロヌンを䜜成したす。 䟿宜䞊、すべおをフォルダヌ内で実行したす ~/TON.

cd ~/TON
git clone https://github.com/ton-blockchain/ton.git
cd ./ton
git submodule update --init --recursive

リポゞトリには実装も保存されたす Fift О FunC.

これで、プロゞェクトを組み立おる準備が敎いたした。 リポゞトリ コヌドがフォルダヌに耇補されたす ~/TON/ton。 で ~/TON フォルダヌを䜜成する build その䞭にプロゞェクトを収集したす。

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

スマヌト コントラクトを䜜成するので、必芁なのは次のずおりです。 lite-clientしかし Fift с FunC, それでは、すべおをコンパむルしたしょう。 すぐにできる手続きではありたせんので、お埅ちしおおりたす。

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

次に、ノヌドに関するデヌタを含む構成ファむルをダりンロヌドしたす。 lite-client ぀ながりたす。

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

TON ぞの最初のリク゚ストの実行

さあ、起動したしょう lite-client.

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

ビルドが成功した堎合は、起動埌にラむト クラむアントのノヌドぞの接続のログが衚瀺されたす。

[ 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)
...

コマンドを実行できたす help 䜿甚可胜なコマンドを確認しおください。

help

この蚘事で䜿甚するコマンドをリストしおみたしょう。

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-ЌетПЎы сЌарткПМтракта. 

これで、契玄曞自䜓を䜜成する準備が敎いたした。

具珟化

アむデア

䞊でも曞きたしたが、私たちが曞いおいるスマヌトコントラクトは宝くじです。

しかも、これはチケットを賌入しおXNUMX時間、XNUMX日、XNUMXヶ月埅぀必芁がある宝くじではなく、ナヌザヌが契玄アドレスに転送するだけの即時宝くじです。 N グラム単䜍ですぐに取り戻せたす 2 * N グラムか負けたす。 圓遞確率は玄40ずさせおいただきたす。 お支払いに必芁なグラム数が䞍足しおいる堎合は、チャヌゞずしお取匕を怜蚎させおいただきたす。

さらに、ナヌザヌが勝ったか負けたかをすぐに理解できるように、賭けをリアルタむムか぀䟿利な圢匏で確認できるこずが重芁です。 したがっお、TON から盎接ベットず結果を衚瀺する Web サむトを䜜成する必芁がありたす。

スマヌトコントラクトを曞く

䟿宜䞊、FunC のコヌドを匷調衚瀺したした。プラグむンは Visual Studio Code 怜玢で芋぀けおむンストヌルできたす。突然䜕かを远加したい堎合は、プラグむンを公開しおありたす。 たた、誰かが以前に Fift を操䜜するためのプラグむンを䜜成したした。それをむンストヌルしお VSC で芋぀けるこずもできたす。

䞭間結果をコミットするリポゞトリをすぐに䜜成したしょう。

䜜業を楜にするために、スマヌト コントラクトを䜜成し、準備が敎うたでロヌカルでテストしたす。 それが終わっお初めおTONに掲茉されたす。

スマヌト コントラクトには、アクセスできる XNUMX ぀の倖郚メ゜ッドがありたす。 初め、 recv_external() この関数は、コントラクトぞのリク゚ストが倖郚から、぀たり TON からではなく、たずえば、私たち自身がメッセヌゞを生成しおラむトクラむアント経由で送信したずきに実行されたす。 XNUMX番、 recv_internal() これは、TON 自䜓の䞭で、あらゆる契玄が圓瀟の契玄を指す堎合です。 どちらの堎合も、関数にパラメヌタを枡すこずができたす。

公開された堎合に機胜する簡単な䟋から始めたしょう。ただし、機胜的な負荷はありたせん。

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

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

ここでそれが䜕であるかを説明する必芁がありたす slice。 TON ブロックチェヌンに保存されおいるすべおのデヌタはコレクションです TVM cell たたは単に cell, このようなセルには、最倧 1023 ビットのデヌタず、他のセルぞの最倧 4 ぀のリンクを保存できたす。

TVM cell slice たたは slice これは既存のものの䞀郚です cell は解析に䜿甚されたすが、それは埌で明らかになりたす。 私たちにずっお重芁なこずは、転送できるこずです slice メッセヌゞの皮類に応じお、デヌタを凊理したす。 recv_external() たたは recv_internal().

impure — 関数がスマヌト コントラクト デヌタを倉曎するこずを瀺すキヌワヌド。

契玄コヌドを保存したしょう lottery-code.fc そしおコンパむルしたす。

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

フラグの意味は、コマンドを䜿甚しお衚瀺できたす。

~/TON/build/crypto/func -help

Fift アセンブラ コヌドをコンパむルしたした。 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

ロヌカルで起動するこずもできたすので、そのための環境を準備したす。

最初の行が接続しおいるこずに泚意しおください Asm.fif、これは Fift アセンブラ甚に Fift で曞かれたコヌドです。

スマヌトコントラクトをロヌカルで実行しおテストしたいので、ファむルを䜜成したす lottery-test-suite.fif そこにコンパむルされたコヌドをコピヌし、スマヌト コントラクト コヌドを定数に曞き蟌む最埌の行を眮き換えたす。 code次に、それを仮想マシンに転送したす。

"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

ここたでは明らかなので、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 コンテキスト、぀たり TVM (たたはネットワヌク状態) が起動されるデヌタを蚘録したす。 コンテスト䞭にも、開発者の XNUMX 人が䜜成方法を瀺したした。 c7 そしお私はコピヌしたした。 この蚘事では倉曎が必芁になる堎合がありたす rand_seed 乱数の生成は乱数に䟝存しおおり、倉曎しないず毎回同じ数倀が返されるためです。

recv_internal О recv_external 倀 0 ず -1 を持぀定数は、スマヌト コントラクト内の察応する関数を呌び出す圹割を果たしたす。

これで、空のスマヌト コントラクトの最初のテストを䜜成する準備が敎いたした。 わかりやすくするために、今のずころ、すべおのテストを同じファむルに远加したす。 lottery-test-suite.fif.

倉数を䜜成したしょう storage そこに空のものを曞き蟌みたす cell, これがスマヌトコントラクトストレヌゞになりたす。

message 倖郚からスマヌトコンタクトに送信するメッセヌゞです。 こちらもずりあえず空にしおおきたす。

variable storage 
<b b> storage ! 

variable message 
<b b> message ! 

定数ず倉数を準備したら、次のコマンドを䜿甚しお TVM を起動したす。 runvmctx そしお䜜成したパラメヌタを入力に枡したす。

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

最終的には成功するだろう そのように の䞭間コヌド Fift.

これで、結果のコヌドを実行できるようになりたす。

export FIFTPATH=~/TON/ton/crypto/fift/lib // выпПлМяеЌ ПЎОМ раз Ўля уЎПбства 
~/TON/build/crypto/fift -s lottery-test-suite.fif 

プログラムぱラヌなしで実行され、出力には実行ログが衚瀺されたす。

execute SETCP 0
execute DICTPUSHCONST 19 (xC_,1)
execute DICTIGETJMPZ
execute DROP
execute implicit RET
[ 3][t 0][1582281699.325381279][vm.cpp:479]     steps: 5 gas: used=304, max=9223372036854775807, limit=9223372036854775807, credit=0

玠晎らしい、スマヌト コントラクトの最初の実甚バヌゞョンを䜜成できたした。

次に、機胜を远加する必芁がありたす。 たず、倖の䞖界から届くメッセヌゞに察凊したしょう。 recv_external()

開発者自身が、コントラクトが受け入れるこずができるメッセヌゞ圢匏を遞択したす。

でも、普段は

  • たず、コントラクトを倖郚から保護し、コントラクトの所有者だけがコントラクトに倖郚メッセヌゞを送信できるようにしたいず考えおいたす。
  • 次に、有効なメッセヌゞを TON に送信するずきに、これが XNUMX 回だけ行われるようにし、同じメッセヌゞを再床送信するず、スマヌト コントラクトがそれを拒吊するようにしたす。

したがっお、ほずんどすべおのコントラクトはこれら XNUMX ぀の問題を解決したす。私たちのコントラクトは倖郚メッセヌゞを受け入れるため、これにも察凊する必芁がありたす。

逆の順序でやっおいきたす。 たず、繰り返しの問題を解決したしょう。コントラクトがすでにそのようなメッセヌゞを受信しお​​凊理しおいる堎合、それを再床実行するこずはありたせん。 そしお、特定のサヌクルのみがスマヌト コントラクトにメッセヌゞを送信できるように問題を解決したす。

重耇メッセヌゞの問題を解決するには、さたざたな方法がありたす。 その方法は次のずおりです。 スマヌト コントラクトでは、受信メッセヌゞのカりンタヌを初期倀 0 で初期化したす。スマヌト コントラクトぞの各メッセヌゞに、珟圚のカりンタヌ倀を远加したす。 メッセヌゞ内のカりンタヌ倀がスマヌト コントラクト内の倀ず䞀臎しない堎合は凊理したせんが、䞀臎する堎合は凊理しおスマヌト コントラクト内のカりンタヌを 1 増やしたす。

に戻りたしょう lottery-test-suite.fif そしお 166 番目のテストを远加したす。 間違った数倀を送信した堎合、コヌドは䟋倖をスロヌする必芁がありたす。 たずえば、契玄デヌタに 165 が保存されおいるずするず、XNUMX を送信したす。

<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"

起動したしょう。

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

そしお、テストが実行されお゚ラヌが発生したこずがわかりたす。

[ 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

この段階で lottery-test-suite.fif のように芋えるはずです リンク.

次に、カりンタヌ ロゞックをスマヌト コントラクトに远加したしょう。 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 私たちが送るメッセヌゞは嘘です。

最初にメッセヌゞにデヌタが含たれおいるかどうかを確認し、含たれおいない堎合は単に終了したす。

次にメッセヌゞを解析したす。 in_msg~load_uint(32) 数倀 165、32 ビットをロヌドしたす unsigned int 送信されたメッセヌゞから。

次に、スマヌト コントラクト ストレヌゞから 32 ビットをロヌドしたす。 ロヌドされた数倀が枡された数倀ず䞀臎するかどうかを確認し、䞀臎しない堎合は䟋倖をスロヌしたす。 この堎合、䞍䞀臎を枡しおいるため、䟋倖がスロヌされるはずです。

それではコンパむルしたしょう。

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

結果のコヌドを次の堎所にコピヌしたす lottery-test-suite.fif最埌の行を眮き換えるこずを忘れないでください。

テストが成功したこずを確認したす。

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

ここに 察応するコミットず珟圚の結果を確認できたす。

スマヌト コントラクトのコンパむルされたコヌドをテストを含むファむルに垞にコピヌするのは䞍䟿であるこずに泚意しおください。そのため、コヌドを定数に曞き蟌むスクリプトを䜜成し、コンパむルされたコヌドを単に次を䜿甚しおテストに接続したす。 "include".

プロゞェクトフォルダヌにファむルを䜜成したす build.sh 以䞋の内容で。

#!/bin/bash

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

実行可胜にしおみたしょう。

chmod +x ./build.sh

ここで、スクリプトを実行しおコントラクトをコンパむルするだけです。 しかし、これに加えお、それを定数に曞き蟌む必芁がありたす code。 そこで、新しいファむルを䜜成したす lotter-compiled-for-test.fif、ファむルに含めたす lottery-test-suite.fif.

sh に Skirpt コヌドを远加したしょう。これは単にコンパむルされたファむルを耇補するだけです。 lotter-compiled-for-test.fif そしおその最埌の行を倉曎したす。

# 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

ここで、確認のために、結果のスクリプトを実行しおみたしょう。ファむルが生成されたす。 lottery-compiled-for-test.fif、これを含めたす lottery-test-suite.fif

В lottery-test-suite.fif 契玄コヌドを削陀しお行を远加したす "lottery-compiled-for-test.fif" include.

テストを実行しお、それらが合栌するこずを確認したす。

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

わかりたした。テストの起動を自動化するために、ファむルを䜜成したしょう test.sh、最初に実行されたす build.shをクリックし、テストを実行したす。

touch test.sh
chmod +x test.sh

䞭に曞きたす

./build.sh 

echo "nCompilation completedn"

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

それをやりたしょう test.sh それを実行しおテストが機胜するこずを確認したす。

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

コントラクトがコンパむルされ、テストが実行されるこずを確認したす。

すばらしい、起動䞭です test.sh テストはコンパむルされ、すぐに実行されたす。 ここにリンクがありたす 専念.

さお、続行する前に、䟿宜䞊、もう XNUMX ぀やっおみたしょう。

フォルダヌを䜜成したしょう build コピヌしたコントラクトず定数に曞き蟌たれたそのクロヌンをここに保存したす lottery-compiled.fif, lottery-compiled-for-test.fif。 フォルダも䜜っおみたしょう test テストファむルはどこに保存されたすか? lottery-test-suite.fif 他のサポヌト ファむルも含たれる可胜性がありたす。 関連する倉曎ぞのリンク.

スマヌトコントラクトの開発を続けたしょう。

次に、メッセヌゞが受信され、正しい番号を送信したずきにストア内のカりンタヌが曎新されるこずを確認するテストが必芁です。 しかし、それは埌で行いたす。

次に、どのようなデヌタ構造ずスマヌト コントラクトに保存する必芁があるデヌタに぀いお考えおみたしょう。

私たちが保管しおいるものすべおに぀いお説明したす。

`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` переЌеММая тОпа слПварь, храМОт пПслеЎМОе ЎваЎцать ставПк. 

次に、XNUMX ぀の関数を䜜成する必芁がありたす。 最初に電話したしょう pack_state()、その埌スマヌト コントラクト ストレヌゞに保存するためにデヌタがパックされたす。 XNUMX番目に電話したしょう unpack_state() ストレヌゞからデヌタを読み取っお返したす。

_ 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;
}

これら XNUMX ぀の関数をスマヌト コントラクトの先頭に远加したす。 それはうたくいきたす そのように 䞭間結果。

デヌタを保存するには、組み蟌み関数を呌び出す必芁がありたす。 set_data() そしおそれはからデヌタを曞き蟌みたす pack_state() スマヌトコントラクトストレヌゞ内。

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

デヌタの曞き蟌みず読み取りに䟿利な関数が完成したので、次に進みたす。

倖郚から受信するメッセヌゞが契玄の所有者 (たたは秘密キヌにアクセスできる別のナヌザヌ) によっお眲名されおいるこずを確認する必芁がありたす。

スマヌト コントラクトを公開するずき、ストレヌゞに必芁なデヌタを䜿甚しおスマヌト コントラクトを初期化し、将来の䜿甚に備えお保存したす。 受信メッセヌゞが察応する秘密鍵で眲名されおいるこずを確認できるように、そこに公開鍵を蚘録したす。

続行する前に、秘密キヌを䜜成しお曞き蟌みたしょう。 test/keys/owner.pk。 これを行うには、Fift を察話モヌドで起動し、XNUMX ぀のコマンドを実行したしょう。

`newkeypair` геМерацОя публОчМПгП О прОватМПгП ключа О запОсь Ох в стек. 

`drop` уЎалеМОя Оз стека верхМегП элеЌеМта (в ЎаММПЌ случае публОчМый ключ)  

`.s` прПстП пПсЌПтреть чтП лежОт в стеке в ЎаММый ЌПЌеМт 

`"owner.pk" B>file` запОсь прОватМПгП ключа в файл с ОЌеМеЌ `owner.pk`. 

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

フォルダヌを䜜成したしょう keys フォルダの䞭の test そこに秘密キヌを曞き蟌みたす。

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

珟圚のフォルダヌにファむルが衚瀺されたす owner.pk.

スタックから公開キヌを削陀し、必芁に応じお秘密キヌから取埗できたす。

次に、眲名怜蚌を蚘述する必芁がありたす。 テストから始めたしょう。 たず、関数を䜿甚しおファむルから秘密キヌを読み取りたす。 file>B そしおそれを倉数に曞き蟌みたす owner_private_key、次に関数を䜿甚したす priv>pub 秘密鍵を公開鍵に倉換し、結果を次のように曞き蟌みたす。 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 !

䞡方のキヌが必芁になりたす。

関数ず同じシヌケンスで任意のデヌタを䜿甚しおスマヌト コントラクト ストレヌゞを初期化したす。 pack_state()そしおそれを倉数に曞き蟌みたす 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 !

次に、眲名付きメッセヌゞを䜜成したす。これには、眲名ずカりンタヌ倀のみが含たれたす。

たず、送信するデヌタを䜜成し、次に秘密鍵で眲名し、最埌に眲名付きメッセヌゞを生成したす。

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 !  

その結果、スマヌトコントラクトに送信するメッセヌゞが倉数に蚘録されたす。 message_to_send、機胜に぀いお hashu, ed25519_sign_uint あなたは読むこずができたす Fift ドキュメントの䞭で.

そしおテストを実行するために、もう䞀床呌び出したす。

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

このような この段階では、テストを含むファむルは次のようになりたす。

テストを実行するず倱敗するので、この圢匏のメッセヌゞを受信しお​​眲名を怜蚌できるようにスマヌト コントラクトを倉曎したす。

たず、メッセヌゞから眲名の 512 ビットをカりントしお倉数に曞き蟌み、次にカりンタヌ倉数の 32 ビットをカりントしたす。

スマヌトコントラクトのストレヌゞからデヌタを読み蟌む機胜があるので、それを利甚したす。

次はストレヌゞず䞀緒に転送されたカりンタの確認ず眲名の確認です。 䜕かが䞀臎しない堎合は、適切なコヌドで䟋倖をスロヌしたす。

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));

関連するコミット ここで.

テストを実行しお、XNUMX 番目のテストが倱敗するこずを確認しおみたしょう。 XNUMX ぀の理由により、メッセヌゞに十分なビットがなく、ストレヌゞにも十分なビットがないため、解析䞭にコヌドがクラッシュしたす。 送信するメッセヌゞに眲名を远加し、最埌のテストからストレヌゞをコピヌする必芁がありたす。

XNUMX 番目のテストでは、メッセヌゞ眲名を远加し、スマヌト コントラクト ストレヌゞを倉曎したす。 このような テストを含むファむルは珟時点では次のようになりたす。

XNUMX 番目のテストを䜜成しおみたしょう。このテストでは、他の人の秘密鍵で眲名されたメッセヌゞを送信したす。 別の秘密キヌを䜜成しおファむルに保存したしょう not-owner.pk。 この秘密鍵を䜿甚しおメッセヌゞに眲名したす。 テストを実行しお、すべおのテストが成功するこずを確認しおみたしょう。 専念 この瞬間に。

これで、いよいよスマヌト コントラクト ロゞックの実装に進むこずができたす。
В recv_external() XNUMX皮類のメッセヌゞを受け付けおおりたす。

私たちの契玄ではプレむダヌの損倱が环積されるため、このお金は宝くじの䜜成者に送金されなければなりたせん。 宝くじ䜜成者のりォレットアドレスは、契玄の䜜成時にストレヌゞに蚘録されたす。

念のため、敗者のグラムの送信先アドレスを倉曎する機胜が必芁です。 たた、宝くじから埗たグラムを所有者の䜏所に送信できるようにする必芁がありたす。

最初のものから始めたしょう。 たず、メッセヌゞの送信埌、スマヌト コントラクトが新しいアドレスをストレヌゞに保存したかどうかを確認するテストを䜜成したしょう。 メッセヌゞでは、カりンタヌず新しいアドレスに加えお、 action 7 ビットの非負の敎数。それに応じお、スマヌト コントラクトでのメッセヌゞの凊理方法を遞択したす。

<b 0 32 u, 1 @ 7 u, new_owner_wc @  32 i, new_owner_account_id @ 256 u, b> message_to_sign !

テストでは、スマヌトコントラクト ストレヌゞがどのように逆シリアル化されるかを確認できたす。 storage フィフトで。 倉数の逆シリアル化に぀いおは、Fift のドキュメントで説明されおいたす。

リンクをコミットする 生地を远加したもの。

テストを実行しお、倱敗するこずを確認しおみたしょう。 次に、宝くじ所有者の䜏所を倉曎するロゞックを远加したしょう。

スマヌトコントラクトでは解析を続けたす message、読み蟌んでください action。 XNUMX ぀あるこずを思い出させおください actionアドレスを倉曎しおグラムを送信したす。

次に、契玄所有者の新しい䜏所を読み取り、ストレヌゞに保存したす。
テストを実行するず、7 番目のテストが倱敗するこずがわかりたす。 コントラクトがメッセヌゞからさらに XNUMX ビットを解析するようになり、テストでは欠萜しおいるため、クラッシュしたす。 存圚しないものをメッセヌゞに远加する action。 テストを実行しお、すべおが成功するこずを確認しおみたしょう。 ここで 倉化にコミットしたす。 玠晎らしい。

次に、指定したグラム数を以前に保存したアドレスに送信するロゞックを䜜成したしょう。

たず、テストを曞いおみたしょう。 XNUMX ぀のテストを䜜成したす。XNUMX ぀はバランスが䞍十分な堎合、もう XNUMX ぀はすべおが正垞にパスする必芁がある堎合です。 テストが閲芧できる このコミットでは.

コヌドを远加したしょう。 たず、XNUMX ぀のヘルパヌ メ゜ッドを䜜成したしょう。 最初の get メ゜ッドは、スマヌト コントラクトの珟圚の残高を確認するこずです。

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

XNUMX ぀目は、グラムを別のスマヌト コントラクトに送信するためのものです。 このメ゜ッドを別のスマヌト コントラクトから完党にコピヌしたした。

() 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
}

これら XNUMX ぀のメ゜ッドをスマヌト コントラクトに远加し、ロゞックを蚘述しおみたしょう。 たず、メッセヌゞからグラム数を解析したす。 次にバランスをチェックし、䞍足しおいる堎合は䟋倖をスロヌしたす。 すべおが正垞であれば、保存されたアドレスにグラムを送信し、カりンタヌを曎新したす。

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));

このような 珟時点ではスマヌトコントラクトのようです。 テストを実行しお、テストが成功するこずを確認しおみたしょう。

ちなみに、メッセヌゞが凊理されるたびにスマヌトコントラクトから手数料が差し匕かれたす。 スマヌト コントラクト メッセヌゞがリク゚ストを実行するには、基本的なチェックの埌、以䞋を呌び出す必芁がありたす。 accept_message().

次に、内郚メッセヌゞに移りたしょう。 実際、私たちはグラムのみを受け取り、プレヌダヌが勝った堎合は XNUMX 倍の金額を、負けた堎合は XNUMX 分の XNUMX をオヌナヌに送り返したす。

たず、簡単なテストを曞いおみたしょう。 これを行うには、スマヌト コントラクトにグラムを送信するこずになるスマヌト コントラクトのテスト アドレスが必芁です。

スマヌト コントラクト アドレスは、ワヌクチェヌンを担圓する 32 ビット敎数ず、このワヌクチェヌン内の 256 ビットの非負の敎数の䞀意のアカりント番号の 1 ぀の数倀で構成されたす。 たずえば、-12345 ず XNUMX は、ファむルに保存するアドレスです。

からアドレスを保存する関数をコピヌしたした 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

この関数がどのように動䜜するかを芋おみたしょう。これにより、Fift がどのように動䜜するかを理解できたす。 むンタラクティブモヌドでFiftを起動したす。

~/TON/build/crypto/fift -i 

たず、-1、12345、および将来のファむル名「sender.addr」をスタックにプッシュしたす。

-1 12345 "sender.addr" 

次のステップは関数を実行するこずです -rot、スタックの最䞊郚に䞀意のスマヌト コントラクト番号が存圚するようにスタックをシフトしたす。

"sender.addr" -1 12345

256 u>B 256 ビットの負でない敎数をバむトに倉換したす。

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap スタックの䞊䜍 XNUMX ぀の芁玠を亀換したす。

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

32 i>B 32 ビット敎数をバむトに倉換したす。

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ XNUMX ぀のバむト シヌケンスを接続したす。

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

もう䞀床 swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

そしお最埌にバむトがファむルに曞き蟌たれたす B>file。 この埌、スタックは空になりたす。 やめたす Fift。 珟圚のフォルダヌにファむルが䜜成されたした sender.addr。 䜜成したフォルダヌにファむルを移動したしょう test/addresses/.

グラムをスマヌト コントラクトに送信する簡単なテストを䜜成しおみたしょう。 これがコミットです.

では、宝くじのロゞックを芋おみたしょう。

最初にメッセヌゞを確認したす bounced そうでない堎合 bounced、その埌は無芖したす。 bounced これは、䜕らかの゚ラヌが発生した堎合にコントラクトがグラムを返すこずを意味したす。 突然゚ラヌが発生した堎合でもグラムの返华は臎したせん。

残高が XNUMX グラム未満であるこずを確認し、メッセヌゞをそのたた受け入れ、無芖したす。

次に、メッセヌゞの送信元のスマヌト コントラクトのアドレスを解析したす。

ストレヌゞからデヌタを読み取り、叀いベットが XNUMX 個を超える堎合は履歎から削陀したす。 䟿宜䞊、XNUMX ぀の远加関数を䜜成したした pack_order(), unpack_order(), remove_old_orders().

次に、残高が支払いに十分ではないかどうかを確認し、これは賭けではなく補充であるずみなし、補充を保存したす。 orders.

そしお最埌にスマヌトコントラクトの本質です。

たず、プレむダヌが負けた堎合は賭け履歎に保存し、金額が 3 グラムを超える堎合は 1/3 をスマヌト コントラクトの所有者に送信したす。

プレヌダヌが勝った堎合、XNUMX 倍の金額をプレヌダヌのアドレスに送信し、賭けに関する情報を履歎に保存したす。

() 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));
}

それはそれだ。 察応するコミット.

あずは簡単です。倖郚からコントラクトの状態に関する情報を取埗できるように (実際には、スマヌト コントラクトのストレヌゞからデヌタを読み取りたす)、get メ゜ッドを䜜成したしょう。

getメ゜ッドを远加したしょう。 以䞋にスマヌトコントラクトに関する情報を受け取る方法に぀いお曞いおいきたす。

たた、スマヌト コントラクトを公開するずきに発生する最初のリク゚ストを凊理するコヌドを远加するのを忘れおいたした。 察応するコミット。 そしおさらに 修正枈み 金額の 1/3 を所有者のアカりントに送金する際のバグ。

次のステップは、スマヌト コントラクトを公開するこずです。 フォルダヌを䜜成したしょう requests.

出版コヌドをベヌスにしたした simple-wallet-code.fc кПтПрый 芋぀けるこずができたす 公匏リポゞトリにありたす。

泚目に倀するものがありたす。 スマヌト コントラクト ストレヌゞず入力メッセヌゞを生成したす。 この埌、スマヌト コントラクトのアドレスが生成されたす。぀たり、アドレスは TON で公開される前からわかっおいたす。 次に、このアドレスに数グラムを送信する必芁がありたす。その埌、スマヌト コントラクト自䜓を含むファむルを送信する必芁がありたす。これは、ネットワヌクがスマヌト コントラクトずその操䜜を保存するために手数料を取るためです (スマヌト コントラクトを保存しお実行するバリデヌタ)契玄。 コヌドはここで芋るこずができたす.

次に、公開コヌドを実行しお取埗したす。 lottery-query.boc スマヌト コントラクト ファむルずアドレス。

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

生成されたファむルを忘れずに保存しおください。 lottery-query.boc, lottery.addr, lottery.pk.

ずりわけ、実行ログにはスマヌト コントラクトのアドレスが衚瀺されたす。

new wallet address = 0:044910149dbeaf8eadbb2b28722e7d6a2dc6e264ec2f1d9bebd6fb209079bc2a 
(Saving address to file lottery.addr)
Non-bounceable address (for init): 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd
Bounceable address (for later access): kQAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KpFY

楜しみのために TON にリク゚ストしおみたしょう

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

そしお、このアドレスのアカりントが空であるこずがわかりたす。

account state is empty

アドレスにお送りしたす 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2グラムを実行し、数秒埌に同じコマンドを実行したす。 グラムを送信するために䜿甚したす 公匏りォレット、チャットから誰かにテスト グラムを䟝頌するこずもできたす。これに぀いおは蚘事の最埌で説明したす。

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

初期化されおいないようです (state:account_uninit) 同じアドレスず 1 ナノグラムの残高を持぀スマヌト コントラクト。

account state is (account
  addr:(addr_std
    anycast:nothing workchain_id:0 address:x044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A)
  storage_stat:(storage_info
    used:(storage_used
      cells:(var_uint len:1 value:1)
      bits:(var_uint len:1 value:103)
      public_cells:(var_uint len:0 value:0)) last_paid:1583257959
    due_payment:nothing)
  storage:(account_storage last_trans_lt:3825478000002
    balance:(currencies
      grams:(nanograms
        amount:(var_uint len:4 value:2000000000))
      other:(extra_currencies
        dict:hme_empty))
    state:account_uninit))
x{C00044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A20259C2F2F4CB3800000DEAC10776091DCD650004_}
last transaction lt = 3825478000001 hash = B043616AE016682699477FFF01E6E903878CDFD6846042BA1BFC64775E7AC6C4
account balance is 2000000000ng

次に、スマヌト コントラクトを公開したしょう。 lite-clientを起動しお実行しおみたしょう。

> 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 

契玄曞が発行されたこずを確認しおみたしょう。

> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

ずりわけ、私たちは埗るものがありたす。

  storage:(account_storage last_trans_lt:3825499000002
    balance:(currencies
      grams:(nanograms
        amount:(var_uint len:4 value:1987150999))
      other:(extra_currencies
        dict:hme_empty))
    state:(account_active

それがわかりたす account_active.

倉曎を含む察応するコミット ここで.

次に、スマヌト コントラクトず察話するためのリク゚ストを䜜成したしょう。

より正確には、最初のアドレス倉曎は独立した䜜業ずしお残し、XNUMX 番目は所有者のアドレスにグラムを送信するために実行したす。 実際には、グラムを送信するテストず同じこずを行う必芁がありたす。

これはスマヌト コントラクトに送信するメッセヌゞです。 msg_seqno 165、 action 送信甚は2グラムず9.5グラム。

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

秘密鍵を䜿甚しおメッセヌゞに眲名するこずを忘れないでください lottery.pk、これはスマヌト コントラクトの䜜成時に生成されたした。 察応するコミットは次のずおりです.

get メ゜ッドを䜿甚しおスマヌト コントラクトから情報を受信する

次に、スマヌト コントラクトの get メ゜ッドを実行する方法を芋おみたしょう。

打ち䞊げ lite-client そしお、䜜成した get メ゜ッドを実行したす。

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

В result 関数が返す倀が含たれたす balance() 私たちのスマヌトコントラクトから。
さらにいく぀かのメ゜ッドに぀いおも同じこずを行いたす。

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

あなたのベット履歎を聞いおみたしょう。

> 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]) ] 

Lite-client を䜿甚しお、サむト䞊のスマヌト コントラクトに関する情報を衚瀺するメ゜ッドを取埗したす。

スマヌトコントラクトデヌタをWebサむトに衚瀺する

スマヌト コントラクトからのデヌタを䟿利な方法で衚瀺するための簡単な Web サむトを Python で䜜成したした。 ここでは詳しくは述べず、サむトを公開したす XNUMX ぀のコミットで.

TONぞのリク゚ストは以䞋から行われたす。 Python 経由 lite-client。 䟿宜䞊、サむトは Docker でパッケヌゞ化され、Google Cloud で公開されおいたす。 リンク.

やっおみよう

ここで、補充のためにそこにグラムを送っおみたしょう 財垃。 40グラムをお送りいたしたす。 わかりやすくするために、いく぀かの賭けをしおみたしょう。 このサむトには、賭けの履歎、珟圚の勝率、その他の圹立぀情報が衚瀺されおいるこずがわかりたす。

私たちは芋るXNUMX回目は勝ったけど、XNUMX回目は負けた。

埌曞き

この蚘事は私が予想しおいたよりもずっず長くなっおしたいたした。もしかしたらもっず短くおもよかったかもしれたせん。あるいは単に TON に぀いお䜕も知らず、TON ず察話する機胜を備えたそれほど単玔ではないスマヌト コントラクトを䜜成しお公開したいず考えおいる人向けかもしれたせん。それ。 おそらく、いく぀かのこずはもっず簡単に説明できたかもしれたせん。

おそらく、実装のいく぀かの偎面はもっず効率的か぀゚レガントに実行できたはずですが、その堎合は蚘事の準備にさらに時間がかかったでしょう。 どこかで間違いを犯したり、䜕かを理解しおいなかった可胜性もあるため、深刻な䜜業を行う堎合は、公匏ドキュメントたたは TON コヌドが蚘茉された公匏リポゞトリに䟝存する必芁がありたす。

TON 自䜓はただ開発の掻発な段階にあるため、この蚘事のステップのいずれかを䞭断する倉曎が発生する可胜性があるこずに泚意しおください (これは私が執筆䞭に発生したしたが、すでに修正されおいたす) が、䞀般的なアプロヌチは次のずおりです。倉わる可胜性は䜎いです。

TONの将来に぀いおは話したせん。 おそらく、このプラットフォヌムは倧きなものになるでしょう。私たちは時間をかけお研究し、今すぐニッチ垂堎を圓瀟の補品で埋める必芁がありたす。

Facebook の Libra もあり、TON よりも倚くのナヌザヌを朜圚的に抱えおいたす。 私はLibraに぀いおほずんど䜕も知りたせんが、フォヌラムから刀断するず、TONコミュニティよりもはるかに倚くの掻動が行われおいたす。 TON の開発者ずコミュニティはアンダヌグラりンドに近いですが、それもクヌルです。

リファレンス

  1. TON の公匏ドキュメント: https://test.ton.org
  2. 公匏 TON リポゞトリ: https://github.com/ton-blockchain/ton
  3. さたざたなプラットフォヌム甚の公匏りォレット: https://wallet.ton.org
  4. この蚘事のスマヌト コントラクト リポゞトリ: https://github.com/raiym/astonished
  5. スマヌト コントラクト Web サむトぞのリンク: https://ton-lottery.appspot.com
  6. Visual Studio Code for FunC の拡匵機胜のリポゞトリ: https://github.com/raiym/func-visual-studio-plugin
  7. Telegram で TON に぀いおチャットしおください。これは、初期段階でそれを理解するのに非垞に圹立ちたした。 TONで䜕かを曞いた人はみんないるず蚀っおも間違いではないず思いたす。 そこでテストグラムを求めるこずもできたす。 https://t.me/tondev_ru
  8. TON に関する別のチャットで有益な情報を芋぀けたした。 https://t.me/TONgramDev
  9. コンテストの最初のステヌゞ: https://contest.com/blockchain
  10. コンテストの第 XNUMX ステヌゞ: https://contest.com/blockchain-2

出所 habr.com

コメントを远加したす