測試客戶端 TON(Telegram Open Network)和新的智慧合約 Fift 語言

一年多前,人們得知 Telegram Messenger 計畫發布自己的去中心化網絡 電報開放網絡。 隨後出現了一份大量的技術文件,據稱是尼古拉·杜羅夫撰寫的,描述了未來網路的結構。 對於那些錯過的人,我建議您閱讀我對這份文件的重述(第1部分, 第2部分; 唉,第三部分仍在草稿中積滿灰塵)。

從那時起,就沒有關於 TON 開發狀況的重大新聞,直到幾天前(在其中一篇文章中) 非官方管道) 頁面連結未出現 https://test.ton.org/download.html,位於哪裡:
ton-test-liteclient-full.tar.xz — TON 測試網路的輕客戶端來源;
ton-lite-client-test1.config.json — 連接測試網路的設定檔;
自述 — 有關建置和啟動客戶端的資訊;
如何 — 使用客戶端建立智慧合約的逐步說明;
噸.pdf — 更新了文件(日期為 2 年 2019 月 XNUMX 日),其中包含 TON 網路的技術概述;
電視節目.pdf ——TVM(TON Virtual Machine,TON虛擬機器)的技術說明;
tblkch.pdf — TON 區塊鏈的技術描述;
第五基地.pdf — 新 Fift 語言的描述,旨在在 TON 中創建智能合約。

我再說一遍,該頁面和來自 Telegram 的所有這些文件都沒有得到官方確認,但這些材料的數量使它們非常可信。 啟動已發布的客戶端 風險自擔.

建立測試客戶端

首先,讓我們嘗試建置並運行一個測試客戶端 - 幸運的是, 自述 詳細描述了這個簡單的過程。 我將使用 macOS 10.14.5 作為範例來執行此操作;我不能保證在其他系統上建置成功。

  1. 下載並解壓縮 來源檔案。 下載最新版本非常重要,因為現階段無法保證向後相容性。

  2. 確保系統上安裝了最新版本的 make、cmake(版本 3.0.2 或更高版本)、OpenSSL(包括 C 頭檔)、g++ 或 clang。 我不需要安裝任何東西,一切都立即組合在一起。

  3. 我們假設原始碼被解壓縮到一個資料夾中 ~/lite-client。 除此之外,為組裝的專案建立一個空資料夾(例如, ~/liteclient-build),並從中得出(cd ~/liteclient-build)調用命令:

    cmake ~/lite-client
    cmake --build . --target test-lite-client

    測試客戶端 TON(Telegram Open Network)和新的智慧合約 Fift 語言

    為了建立智能合約的 Fiveft 語言解釋器(更多相關資訊請見下文),我們也調用

    cmake --build . --target fift

  4. 下載目前版​​本 設定檔 連接到測試網路並將其與組裝好的客戶端放在資料夾中。

  5. 完成,您可以啟動客戶端:

    ./test-lite-client -C ton-lite-client-test1.config.json

如果一切都正確完成,您應該看到如下內容:

測試客戶端 TON(Telegram Open Network)和新的智慧合約 Fift 語言

正如我們所看到的,可用的命令很少:
help — 顯示指令清單;
quit - 出去;
time — 顯示伺服器上的目前時間;
status — 顯示連線和本機資料庫狀態;
last — 更新區塊鏈的狀態(下載最後一個區塊)。 在發出任何請求之前執行此命令非常重要,以確保您看到網路的當前狀態。
sendfile <filename> — 將本機檔案上傳至 TON 網路。 這就是與網路互動的發生方式 - 例如,包括創建新的智慧合約和請求在帳戶之間轉移資金;
getaccount <address> — 顯示目前(執行指令時) last) 指定地址的帳戶狀態;
privkey <filename> — 從本機檔案載入私鑰。

如果在啟動用戶端時,您使用選項將資料夾傳輸到用戶端 -D,然後他會將主鏈的最後一個區塊添加到其中:

./test-lite-client -C ton-lite-client-test1.config.json -D ~/ton-db-dir

現在我們可以繼續做更有趣的事情 - 學習 Fift 語言,嘗試編譯智能合約(例如,創建測試錢包),將其上傳到網路並嘗試在帳戶之間轉移資金。

語言五

來自文件 第五基地.pdf 你可以發現Telegram團隊創建了一種新的堆疊語言來創建智能合約 菲夫特 (顯然從數字 第五,與 Forth 類似,Fifth 與 Forth 語言有許多共同點)。

該文件相當龐大,有87頁,我不會在本文的框架內詳細複述其內容(至少因為我自己還沒讀完:)。 我將重點關注要點並給出一些這種語言的程式碼範例。

從根本上來說,Fift 的語法非常簡單:它的程式碼包括 ,通常用空格或換行符號分隔(特殊情況:某些單字後面不需要分隔符號)。 任何 слово 是一個區分大小寫的字元序列,對應於某個特定的 決心 (粗略地說,解釋器遇到這個詞時應該做什麼)。 如果沒有單字的定義,解釋器會嘗試將其解析為數字並將其放入堆疊中。 順便說一句,這裡的數字突然變成了 257 位元整數,而且根本沒有分數,更準確地說,它們立即變成一對整數,形成有理分數的分子和分母。

單字往往與堆疊頂部的值互動。 一個單獨的詞類型 - 字首 — 不使用堆疊,而是使用來源檔案中的後續字元。 例如,這就是字串文字的實現方式 - 引號字元 (") 是一個前綴詞,用於尋找下一個(結束)引號,並將它們之間的字串壓入堆疊。 單行程式碼的行為方式相同(//) 和多行 (/*) 評論。

這幾乎是該語言的整個內部結構的終點。 其他一切(包括控制結構)都被定義為單字(或者是內部的,例如算術運算和新單字的定義;或者是在「標準庫」中定義的) Fift.fif,位於資料夾中 crypto/fift 在來源中)。

Five 中的一個簡單範例程式:

{ dup =: x dup * =: y } : setxy
3 setxy x . y . x y + .
7 setxy x . y . x y + .

第一行定義一個新詞 setxy (注意前綴 {,它在結束區塊之前創建一個區塊 } 和前綴 :,它實際上定義了這個詞)。 setxy 從堆疊頂部取得一個數字,將其定義(或重新定義)為全域的 持續的 x,並將該數字的平方作為常數 y (鑑於常數的值可以重新定義,我寧願將它們稱為變量,但我遵循語言中的命名約定)。

接下來的兩行將一個數字放入堆疊並調用 setxy,然後顯示常數的值 x, y (該字用於輸出 .),兩個常數都放入堆疊中,求和,並列印結果。 結果我們會看到:

3 9 12 ok
7 49 56 ok

(解釋器在交互輸入模式下處理完當前行後會列印“ok”行)

好吧,完整的程式碼範例:

"Asm.fif" include

-1 constant wc  // create a wallet in workchain -1 (masterchain)

// Create new simple wallet
<{  SETCP0 DUP IFNOTRET INC 32 THROWIF  // return if recv_internal, fail unless recv_external
    512 INT LDSLICEX DUP 32 PLDU   // sign cs cnt
    c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS  // sign cs cnt cnt' pubk
    s1 s2 XCPU            // sign cs cnt pubk cnt' cnt
    EQUAL 33 THROWIFNOT   // ( seqno mismatch? )
    s2 PUSH HASHSU        // sign cs cnt pubk hash
    s0 s4 s4 XC2PU        // pubk cs cnt hash sign pubk
    CHKSIGNU              // pubk cs cnt ?
    34 THROWIFNOT         // signature mismatch
    ACCEPT
    SWAP 32 LDU NIP 
    DUP SREFS IF:<{
      8 LDU LDREF         // pubk cnt mode msg cs
      s0 s2 XCHG SENDRAWMSG  // pubk cnt cs ; ( message sent )
    }>
    ENDS
    INC NEWC 32 STU 256 STU ENDC c4 POPCTR
}>c
// code
<b 0 32 u, 
   newkeypair swap dup constant wallet_pk 
   "new-wallet.pk" B>file
   B, 
b> // data
// no libraries
<b b{00110} s, rot ref, swap ref, b>  // create StateInit
dup ."StateInit: " <s csr. cr
dup hash dup constant wallet_addr
."new wallet address = " wc . .": " dup x. cr
wc over 7 smca>$ type cr
256 u>B "new-wallet.addr" B>file
<b 0 32 u, b>
dup ."signing message: " <s csr. cr
dup hash wallet_pk ed25519_sign_uint rot
<b b{1000100} s, wc 8 i, wallet_addr 256 u, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
dup ."External message for initialization is " <s csr. cr
2 boc+>B dup Bx. cr
"new-wallet-query.boc" tuck B>file
."(Saved to file " type .")" cr

這個看起來嚇人的檔案用於創建智能合約 - 它將被放置在一個檔案中 new-wallet-query.boc 執行後。 請注意,TON 虛擬機器這裡使用的是另一種彙編語言(我不會詳細介紹它),其指令將放在區塊鏈上。

因此,TVM 的彙編程式是用 Fift 編寫的 - 該彙編程式的原始程式碼位於檔案中 crypto/fift/Asm.fif 和 連接在上述程式碼的開頭。

我能說什麼,顯然 Nikolai Durov 只是喜歡創建新的程式語言:)

創建智能合約並與 TON 交互

因此,假設我們已經如上所述組裝了 TON 客戶端和 Fift 解釋器,並熟悉了該語言。 現在如何創建智能合約? 文件中對此進行了描述 如何,附在來源中。

TON 帳戶

正如我在 TON 評論,這個網路包含多個區塊鏈——有一個共同的區塊鏈,即所謂的區塊鏈。 “主鏈”,以及任意數量的附加“工作鏈”,由 32 位數字標識。 主鏈的標識符為-1;除此之外,還可以使用標識符為0的「基礎」工作鏈,每個工作鏈可以有自己的配置。 在內部,每個工作鏈都分為分片鏈,但這是一個不需要記住的實作細節。

在一個工作鏈中,儲存了許多具有自己的 account_id 識別碼的帳戶。 對於主鍊和零工作鏈,它們的長度是256位元。 因此,帳戶標識符的寫法例如如下:

-1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d

這是「原始」格式:首先是工作鏈 ID,然後是冒號,以及十六進位表示法的帳戶 ID。

此外,還有一種縮短的格式——工作鏈號和帳戶地址以二進位形式編碼,並添加校驗和,所有這些都以 Base64 編碼:

Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb

知道了這種記錄格式,我們可以使用以下命令透過測試客戶端請求帳戶的當前狀態

getaccount -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d

我們會得到這樣的結果:

[ 3][t 2][1558746708.815218925][test-lite-client.cpp:631][!testnode]    requesting account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D
[ 3][t 2][1558746708.858564138][test-lite-client.cpp:652][!testnode]    got account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D with respect to blocks (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F and (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F
account state is (account
  addr:(addr_std
    anycast:nothing workchain_id:-1 address:x8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D)
  storage_stat:(storage_info
    used:(storage_used
      cells:(var_uint len:1 value:3)
      bits:(var_uint len:2 value:539)
      public_cells:(var_uint len:0 value:0)) last_paid:0
    due_payment:nothing)
  storage:(account_storage last_trans_lt:74208000003
    balance:(currencies
      grams:(nanograms
        amount:(var_uint len:7 value:999928362430000))
      other:(extra_currencies
        dict:hme_empty))
    state:(account_active
      (
        split_depth:nothing
        special:nothing
        code:(just
          value:(raw@^Cell 
            x{}
             x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54}
            ))
        data:(just
          value:(raw@^Cell 
            x{}
             x{0000000D}
            ))
        library:hme_empty))))
x{CFF8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D2068086C000000000000000451C90E00DC0E35B7DB5FB8C134_}
 x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54}
 x{0000000D}

我們看到儲存在指定工作鏈的 DHT 中的結構。 例如,在該領域 storage.balance 是經常帳餘額,單位為 storage.state.code - 智能合約程式碼,以及 storage.state.data - 其當前數據。 請注意,TON 資料儲存 - Cell、cells - 是樹狀的,每個儲存格都可以有自己的資料和子儲存格。 這在最後幾行顯示為縮排。

建構智能合約

現在讓我們自己創建一個這樣的結構(它被稱為 BOC - 細胞袋)使用第五語言。 幸運的是,您不必自己編寫智能合約 - 在資料夾中 crypto/block 來源存檔中有一個文件 new-wallet.fif,這將幫助我們創建一個新的錢包。 讓我們將其複製到包含已組裝客戶端的資料夾中(~/liteclient-build,如果您按照上面的說明進行操作)。 我在上面引用了它的內容作為 Fift 上的程式碼範例。

如下執行該文件:

./crypto/fift -I"<source-directory>/crypto/fift" new-wallet.fif

這裡 <source-directory> 必須替換為解壓縮源的路徑(遺憾的是,此處不能使用“~”符號,需要完整路徑)。 而不是使用鑰匙 -I 你可以定義一個環境變數 FIFTPATH 並將這條路徑放入其中。

由於我們使用檔案名稱啟動 Fift new-wallet.fif,它將執行並退出。 如果省略檔案名,則可以與解譯器互動播放。

執行後,控制台中應該會顯示如下內容:

StateInit: x{34_}
 x{FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54}
 x{0000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B}

new wallet address = -1 : 4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 
0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ
signing message: x{00000000}

External message for initialization is x{89FEE120E20C7E953E31546F64C23CD654002C1AA919ADD24DB12DDF85C6F3B58AE41198A28AD8DAF3B9588E7A629252BA3DB88F030D00BC1016110B2073359EAC3C13823C53245B65D056F2C070B940CDA09789585935C7ABA4D2AD4BED139281CFA1200000001_}
 x{FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54}
 x{0000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B}

B5EE9C724104030100000000D60002CF89FEE120E20C7E953E31546F64C23CD654002C1AA919ADD24DB12DDF85C6F3B58AE41198A28AD8DAF3B9588E7A629252BA3DB88F030D00BC1016110B2073359EAC3C13823C53245B65D056F2C070B940CDA09789585935C7ABA4D2AD4BED139281CFA1200000001001020084FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED5400480000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B6290698B
(Saved to file new-wallet-query.boc)

這意味著帶有ID的錢包 -1:4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 (或者,什麼是相同的, 0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ)創建成功。 對應的程式碼將在文件中 new-wallet-query.boc,他的地址是在 new-wallet.addr,私鑰位於 new-wallet.pk (小心 - 再次運行腳本將覆蓋這些文件)。

當然,TON 網路還不知道這個錢包;它僅以這些文件的形式儲存。 現在需要將其上傳到網路。 然而問題是,創建智能合約需要支付佣金,而你的帳戶餘額仍然為零。

在工作模式下,這個問題將透過在交易所購買克(或從另一個錢包轉移)來解決。 嗯,在目前的測試模式下,已經創建了一個特殊的智能合約,您可以像這樣索取最多 20 克的智能合約。

產生對其他人智能合約的請求

我們向智能合約發出請求,該合約像這樣左右分配克。 在同一個資料夾中 crypto/block 查找文件 testgiver.fif:

// "testgiver.addr" file>B 256 B>u@ 
0x8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d
dup constant wallet_addr ."Test giver address = " x. cr

0x4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2
constant dest_addr

-1 constant wc
0x00000011 constant seqno

1000000000 constant Gram
{ Gram swap */ } : Gram*/

6.666 Gram*/ constant amount

// b x --> b'  ( serializes a Gram amount )
{ -1 { 1+ 2dup 8 * ufits } until
  rot over 4 u, -rot 8 * u, } : Gram, 

// create a message (NB: 01b00.., b = bounce)
<b b{010000100} s, wc 8 i, dest_addr 256 u, amount Gram, 0 9 64 32 + + 1+ 1+ u, "GIFT" $, b>
<b seqno 32 u, 1 8 u, swap ref, b>
dup ."enveloping message: " <s csr. cr
<b b{1000100} s, wc 8 i, wallet_addr 256 u, 0 Gram, b{00} s,
   swap <s s, b>
dup ."resulting external message: " <s csr. cr
2 boc+>B dup Bx. cr
"wallet-query.boc" B>file

我們還將其保存在已組裝客戶端的資料夾中,但我們將更正第五行 - 在「行」之前constant dest_addr」。 讓我們將其替換為您之前創建的錢包地址(完整,非縮寫)。 開頭不需要寫“-1:”,而是在開頭寫“0x”。

您也可以更改線路 6.666 Gram*/ constant amount — 這是您要求的克數(不超過 20)。 即使指定整數,也要保留小數點。

最後,您需要更正該行 0x00000011 constant seqno。 這裡的第一個數字是目前的序號,儲存在發行克的帳戶中。 我可以從哪裡得到它? 如上所述,啟動客戶端並運行:

last
getaccount -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d

最後,智能合約資料將包含

...
x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54}
 x{0000000D}

數字 0000000D(你的會更大)是必須替換的序號 testgiver.fif.

就這樣,儲存檔案並運行(./crypto/fift testgiver.fif)。 輸出將是一個文件 wallet-query.boc。 這就是形成的樣子 сообщение 到其他人的智能合約 - 請求“將這麼多克轉移到某個帳戶”。

使用客戶端,我們將其上傳到網路:

> sendfile wallet-query.boc
[ 1][t 1][1558747399.456575155][test-lite-client.cpp:577][!testnode]    sending query from file wallet-query.boc
[ 3][t 2][1558747399.500236034][test-lite-client.cpp:587][!query]   external message status is 1

如果你現在打電話 last,然後再次請求我們請求克的帳戶的狀態,然後我們應該看到它的序號增加了 XNUMX - 這意味著它向我們的帳戶發送了錢。

最後一步仍然是 - 下載我們錢包的代碼(其餘額已被補充,但如果沒有智能合約代碼,我們將無法管理它)。 我們開展 sendfile new-wallet-query.boc — 就是這樣,您在 TON 網路上擁有了自己的錢包(即使目前只是測試錢包)。

創建傳出交易

要從已建立的帳戶餘額中轉賬,有一個文件 crypto/block/wallet.fif,也需要和組裝好的客戶端放在資料夾中。

與前面的步驟類似,您需要調整您要轉帳的金額、接收者位址(dest_addr)和錢包的 seqno(初始化錢包後等於 1,每次發出交易後增加 1 - 您可以透過要求您的帳戶狀態來查看)。 對於測試,您可以使用我的錢包 - 0x4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2.

啟動時(./crypto/fift wallet.fif)該腳本將從文件中獲取您的錢包地址(從您轉帳的位置)及其私鑰 new-wallet.addr и new-wallet.pk,收到的訊息將會寫入 new-wallet-query.boc.

和以前一樣,要直接執行交易,請調用 sendfile new-wallet-query.boc 在客戶端中。 之後,不要忘記更新區塊鏈的狀態(last)並檢查我們錢包的餘額和序號是否已更改(getaccount <account_id>).

測試客戶端 TON(Telegram Open Network)和新的智慧合約 Fift 語言

就這樣,現在我們可以在 TON 中建立智慧合約並向它們發送請求。 正如您所看到的,當前的功能已經足夠,例如,製作一個帶有圖形介面的更友好的錢包(但是,預計它將已經作為信使的一部分提供)。

只有註冊用戶才能參與調查。 登入, 請。

您有興趣繼續分析 TON、TVM、Fift 的文章嗎?

  • 是的,我正在等待 TON 概述系列文章的完成

  • 是的,閱讀有關第五語言的更多內容很有趣

  • 是的,我想了解有關 TON 虛擬機及其彙編器的更多信息

  • 不,這些都不有趣

39 位用戶投票。 12 名用戶棄權。

您對 Telegram 推出 TON 的計劃有何看法?

  • 我對這個計畫寄予厚望

  • 我只是饒有興趣地關注著它的發展。

  • 我對此表示懷疑並懷疑它的成功。

  • 我傾向於認為這項舉措是失敗的,對於廣大群眾來說是不必要的

47 位用戶投票。 12 名用戶棄權。

來源: www.habr.com

添加評論