TON测试客户端(电报开放网络)和用于智能合约的新Fift语言

一年多以前,人们已经知道Telegram Messenger计划发布自己的去中心化网络Telegram Open Network 。 然后,大量的技术文档可供使用,大概是Nikolai Durov撰写的,描述了未来网络的结构。 对于那些错过的人,我建议您阅读我对本文档的重述( 第1 部分第2部分 ;第三部分,a,仍在草稿中收集灰尘)。


从那时起,就没有关于TON的发展状况的重大新闻,直到几天前(在一个非官方渠道中 )出现了指向页面https://test.ton.org/download.html的链接,其中:


◦ton-test-liteclient-full.tar.xz- TON测试网络的轻客户端资源;
ton-lite-client-test1.config.json-用于连接到测试网络的配置文件;
自述文件 -有关构建和启动客户端的信息;
◦HOWTO-有关使用客户端创建智能合约的分步说明;
ton.pdf-更新的文件(2019年3月2日),其中包含TON网络的技术概述;
◦tvm.pdf -TVM(TON虚拟机,TON虚拟机)的技术说明;
◦tblkch.pdf -TON 区块链的技术说明;
◦fiftbase.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-buildcd ~/liteclient-build命令:


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

    成功的客户建立

    为了构建用于智能合约的Fift语言解释器(请参见下文),我们还调用


     cmake --build . --target fift 

  4. 下载当前的配置文件以连接到测试网络,并将其放入组装好的客户端的文件夹中。


  5. 完成 ,您可以启动客户端:


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


如果一切都正确完成,那么您应该会看到类似以下内容:


客户启动


如您所见,几乎没有可用的命令:


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语言,尝试编译智能合约(例如,创建测试钱包),将其上传到网络,并尝试在帐户之间转移资金。


五十种语言


从文件fiftbase.pdf中,您可以发现,要创建智能合约,Telegram团队创建了一种新的堆栈语言Fift (显然,从第五个数字开始,类似于Forth,Fift与该语言有很多共同点)。


该文档篇幅巨大,有87页,在本文的框架中,我不会详细讲述其内容(至少因为我本人还没有读完它:)。 我将重点介绍这些语言,并给出一些使用该语言的代码示例。


在基本级别上,Fift的语法非常简单:其代码由单词组成,通常由空格或换行符分隔(特殊情况:某些单词本身不需要分隔符)。 任何单词都是对应于某些定义的区分大小写的字符序列(大致来说,解释器在遇到该单词时必须执行的操作)。 如果没有该词的定义,则解释器尝试将其解析为数字并将其放入堆栈中。 顺便说一下,这里的数字-突然是257位整数,但是根本没有小数-更准确地说,它们立即变成一对整数,形成有理数的分子和分母。


单词通常与堆栈顶部的含义相互作用。 单词的另一种类型- 前缀 -不使用堆栈,而是使用源文件中的后续字符。 例如,字符串文字是通过这种方式实现的:“引号”( " )字符是一个前缀单词,它搜索下一个(结束)引号并将字符串放在它们之间的堆栈中。单行( // )和多行( /* )的行为方式相同评论。


至此,语言的几乎整个内部结构结束了。 其他所有内容(包括控制结构)都定义为单词(内部,例如算术运算和新单词的定义;或者在“标准库” Fift.fif定义,该crypto/fift位于源代码的crypto/fift中)。


一个Fift程序的简单示例:


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

第一行定义了新单词setxy (请注意前缀{ ,它在结束setxy }之前创建了块,而前缀:实际上定义了该词)。 setxy从堆栈的顶部获取一个数字,将其定义(或重新定义)为全局常量 x ,并将该数字的平方定义为常量y (假设可以重新定义常量的值,我宁愿称它们为变量,但我遵循该语言的命名方式)。


在接下来的两行中,将一个数字放在堆栈上, setxy ,然后显示常数xy的值(该单词用于输出. ),将两个常数都压入堆栈,相加并显示结果。 结果,我们将看到:


 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 <bb{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 <bb{1000100} s, wc 8 i, wallet_addr 256 u, b{000010} s, swap <ss, b{0} s, swap B, swap <ss, 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解释器放在一起,并熟悉了该语言。 现在如何创建智能合约? 在源附带的HOWTO文件中对此进行了描述。


TON帐户


正如我在TON评论所述 ,该网络包含多个区块链-有一个常见的所谓的 “主链”,以及由32位数字标识的任意数量的其他“工作链”。 主链的标识符为-1,除此之外,还可以使用标识符为0的“基本”工作链​​,每个工作链可以具有自己的配置。 在内部,每个工作组都被分成多个分链,但这已经是实现的细节,不必牢记。


许多帐户存储在一个工作链中,它们具有自己的account_id标识符。 对于主链和零工作链,它们的长度为256位。 因此,帐户标识符的编写方式如下:


 -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d 

这是一种“原始”格式:首先是工作链标识符,然后是冒号,以及以十六进制表示法的帐户标识符。


此外,还有一种缩短的格式-工作链号和帐户地址以二进制形式编码,向其添加校验和,所有这些都以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} -client.cpp: [ 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}为-1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D相对于块(-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F和 [ 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数据存储区-单元格,单元格-是一棵树,每个单元格可以拥有自己的数据以及子单元格。 这在最后几行中显示为缩进。


智能合约组装


现在,让我们使用Fift语言自己创建一个这样的结构(称为BOC- cell of bag )。 幸运的是,您不必自己编写智能合约-源归档文件中的crypto/block文件夹中有一个new-wallet.fif文件,可帮助我们创建新的钱包。 将其复制到具有组装好的客户端的文件夹中(如果~/liteclient-build说明,则为~/liteclient-build )。 我在上面引用了其内容作为Fift上的代码示例。


我们按以下方式执行此文件:


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

在这里, <source-directory>必须替换为已解压缩的源的路径(不幸的是,您需要完整的路径,此处不能使用符号“〜”)。 您可以定义FIFTPATH环境FIFTPATH并将此路径放入其中, FIFTPATH使用-I


自从我们以文件名new-wallet.fif启动Fift以来,它将执行并完成。 如果省略文件名,则可以在交互模式下使用解释器。


执行后,应在控制台中显示以下内容:


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

这意味着标识符为-1:4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2的钱包-1:4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 (或者就是0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ创建0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ 。 与之对应的代码将new-wallet-query.bocnew-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 // bx --> 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) <bb{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 <bb{1000100} s, wc 8 i, wallet_addr 256 u, 0 Gram, b{00} s, swap <ss, 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.fiftestgiver.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 ,然后再次请求我们要克的帐户的状态,那么我们应该看到其序列号增加了一个-这意味着它向我们的帐户汇了款。


最后一步仍然是-我们加载钱包的代码(其余额已被补充,但是如果没有智能合约代码,我们将无法对其进行管理)。 sendfile new-wallet-query.boc就是这样,您在TON网络中拥有自己的钱包(尽管目前只有一个测试)。


创建外向交易


要从已创建帐户的余额中转移资金,有一个crypto/block/wallet.fif ,该crypto/block/wallet.fif也需要与收集到的客户一起放在文件夹中。


与前面的步骤类似,您需要更正转账金额,收件人的地址(dest_addr)和钱包的seqno(初始化钱包后为1,在每次付款交易后增加1-您可以通过请求帐户状态来查看它) 。 对于测试,您可以使用我的钱包0x4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2


当您运行( ./crypto/fift wallet.fif )时,脚本将从文件new-wallet.addrnew-wallet.pk中获取您的钱包地址(从中进行转移)和其私钥,并将接收到的消息写入new-wallet-query.boc


和以前一样,要直接执行事务,我们在客户端中调用sendfile new-wallet-query.boc 。 之后,不要忘记更新区块链的状态( last ),并检查我们钱包的余额和seqno是否已更改( getaccount <account_id> )。


帐户说明


就是这样,现在我们可以在TON中创建智能合约并将请求发送给他们。 如您所见,当前功能已经足够,例如,通过图形界面制作一个更友好的钱包(但是,预计它将作为Messenger的一部分提供)。

Source: https://habr.com/ru/post/zh-CN453714/


All Articles