TON Raw Tx Breakdown

Table of Contents

1. TON 交易

在 TON 区块链中,通过 RPC sendBocReturnHash(或者 sendBoc)可以把签名后的 Tx 提交到链上。

1.1. Tx 解析实例 1(V4R2 钱包原生币转帐)

下面以 TON 测试网上的 Tx _6N7CAGyVt9UO_c10dgJHsS6x6SYey7kRJtU32DXGsg= 为例介绍一下这个 Tx 的细节。

这个交易的功能是测试网上 V4R2 钱包进行原生币 TON 的转帐:

0QCM8Tds9jQwLbxt-nASe4v7PRwOirxczwE1Yni1TdMYNHij (V4R2 wallet)      --- 0.123456 TON -->      0QCc6ls--YZh8WpSr6m1B9kX4EsNfmE3xDGJ93xxaRdOxAhM

这个 Tx 是通过 RPC sendBocReturnHash 提交上链的(注:这个 RPC 返回的是 Message Hash V8Y4wRJOdKphKnSjkBcWYTbIMTTcPrOq/1VA0zH1o4c=,不是 Tx Hash),提交 Tx 时的具体参数如下:

$ curl https://testnet.toncenter.com/api/v2/sendBocReturnHash -X POST -H "Content-Type: application/json" -d '{
  "boc": "te6cckEBAgEAswAB4YgBGeJu2exoYFt42/TgJPcX9no4HRV4uZ4CasTxapumMGgC7o4rP3HdzxLAj0eioBQ5O3hk4wCk884JPnEN2UBWdILxynlD6bzD7EctVOl8OqSn9oa3tqtRlpJpS7itpE54CU1NGLsyjn4gAAAAGAAcAQB6QgBOdS2ffMMw+LUpV9Tag+yL8CWGvzCb4hjE+744tIunYiA63lAAAAAAAAAAAAAAAAAAAAAAAABIZWxsb86+YLo="
}'
{"ok":true,"result":{"@type":"raw.extMessageInfo","hash":"V8Y4wRJOdKphKnSjkBcWYTbIMTTcPrOq/1VA0zH1o4c=","@extra":"1716637630.853718:6:0.03332699648976334"}}

上面命令中提到的 Base64 编码的 Tx 数据可以分解为下面这种更清晰的表达方式:

 magic prefix                            b5ee9c72                                                                                                                     魔法数字,参考 https://docs.ton.org/tblkch.pdf 5.3.9 节   
 flags and size                          41                                                                                                                           后面会介绍                                                
 off bytes                               01                                                                                                                           number of bytes to store the size of the serialized cells 
 number of cells                         02                                                                                                                           这个例子是 2 个 cell                                      
 number of root cells                    01                                                                                                                           只有 1 个 root cell                                       
 absent                                  00                                                                                                                           always 0 in current implementations                       
 size of serialized cells                b3                                                                                                                           size of the serialized cells,这里是 179 字节             
 root cell list                          00                                                                                                                           root cell should have index 0 in case of 1 root cell      
            
            
            
            
            
            
            
            
 serialized 
 cells      
            
            
            
            
            
        
        
        
        
 cell 0 
        
        
        
        
 refs descriptor   01                                                                                                                           当前 cell 有一个引用,当前 cell 是 ordinary cell          
 bits descriptor   e1                                                                                                                           floor(901 / 8) + ceil (901 / 8) = 225 = 0xe1              
 cell data       
                 
                 
 880119e26ed9ec68605b78dbf4e024f717f67a381d1578b99e026ac4f16a9ba6306802ee8e2b3f71ddcf12c08f47a2a01439                       
 3b7864e300a4f3ce093e710dd940567482f1ca7943e9bcc3ec472d54e97c3aa4a7f686b7b6ab519692694bb8ada44e78094d                       
 4d18bb328e7e2000000018001c                                                                                                 
 cell data。cell 中有 901 bits 数据                        
 序列化时按 8 bits 倍数补齐为了 113 字节(904 bits)       
                                                           
 cell refs         01                                                                                                                           所引用的 cell index 为 1                                  
        
        
 cell 1 
        
        
 refs descriptor   00                                                                                                                           当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   7a                                                                                                                           floor(488 / 8) + ceil (488 / 8) = 122 = 0x7a              
 cell data         42004e752d9f7cc330f8b52957d4da83ec8bf02586bf309be218c4fbbe38b48ba762203ade5000000000000000000000000000000000000048656c6c6f   cell data。cell 中有 488 bits 数据,不需要补齐            
 crc32c                                  cebe60ba                                                                                                                     crc32c 校验码                                             

注 1:flags and size(在上面例子中就是二进制 01000001)的前 3 bits 表示 has_idx/has_crc32c/has_cache_bits(如果 has_idx 为 1,则在 root cell list 后面会在额外的 index 数据。has_cache_bits 仅当 has_idx 为 1 时才有意义);中间 2 bits 均为 0;最后 3 bits 表示编码 Cell 的数量所需的最小字节数(上面例子中为 1)。
注 2:refs descriptor 的计算公式为: r+8s+32l ,其中 r 表示当前 Cell 的引用的个数,所以 0r4s 的可选值为 0/1,分别表示 Ordinary Cell/Exotic Cell; llevel of Cell。
注 2:bits descriptor 的计算公式为: floor(b/8)+ceil(b/8) ,其中 b 是 Cell data 的二进制位数,由于一个 Cell 最多有 1023 位数据,所以 0b1023

1.1.1. Cell 0

前面介绍中提到了 Cell 0 由下面数据组成(下面十六进制数据共有 904 bits,需要根据 Cell 的 bits descriptor 信息才知道 padding 的比特位数是 3,才能知道 Cell 0 真正比特位数是 901:

0x880119e26ed9ec68605b78dbf4e024f717f67a381d1578b99e026ac4f16a9ba6306802ee8e2b3f71ddcf12c08f47a2a014393b7864e300a4f3ce093e710dd940567482f1ca7943e9bcc3ec472d54e97c3aa4a7f686b7b6ab519692694bb8ada44e78094d4d18bb328e7e2000000018001c

Cell 0 数据可分解为下面更易读的形式:

            
            
            
            
 external   
 message    
 header     
 (275 bits) 
            
            
            
            
            
 magic bits          0b10                                                                 10 表示 ext_in_msg_info,https://ton.org/tblkch.pdf                             
 src addr            0b00                                                                 00 表示 none addr                                                               
      
      
 dest 
 addr 
      
      
      
 addr flag    0b10                                                                 10 表示 std addr                                                                
 anycast      0b0                                                                                                                                                  
 workchain    0b00000000                                                           workchain                                                                       
 addr hash    0x8cf1376cf634302dbc6dfa70127b8bfb3d1c0e8abc5ccf01356278b54dd31834   发送者的 raw 地址                                                               
 import fee          0b0000                                                                                                                                               
 stateInit present flag (1 bit)   0b0                                                                  0 没有 stateInit;1 有 stateInit。首次提交 Tx 创建钱包合约时,它才是 1          
 body ref flag (1 bit)            0b0                                                                  0 表示 Cell 剩下空间可放下整个 body;1 表示 Cell 空间不够,body 需要放在 ref 中 
       
       
       
       
 body  
 (624  
 bits) 
       
       
       
       
       
 signature              
 (512 bits)             
 0x5dd1c567ee3bb9e25811e8f4540287276f0c9c60149e79c127ce21bb280ace90 
 0x5e394f287d37987d88e5aa9d2f875494fed0d6f6d56a32d24d297715b489cf01 
 Ed25519 签名数据,后文会介绍它是如何计算的                                      
                                                                                 
         
         
         
         
 signing 
 message 
         
         
         
 wallet id      0x29a9a317                                                                                                                                           
 valid until    0x6651cfc4                                                           交易过期时间                                                                    
 seqno          0x00000003                                                           类似于 Ethereum 的 nonce 值                                                     
 op             0x00                                                                 对于 V4R2 版本的钱包来说,op 为 0 表示原生币发送                                
 send mode      0x03                                                                 参考 https://docs.ton.org/develop/func/stdlib#send_raw_message                  
 cell padding                     0b100                                                                按字节补齐。如果 Cell 的 bits descriptor 为奇数,表示有 padding                 

注 1:TON 的钱包合约是在用户自己首次提交 Tx 时才会被部署(别人给你转币的场景,并不会帮你部署合约),上面例子中,由于 seqno 为 3,所以不是首次提交 Tx 了,钱包合约早就已经部署了。
注 2:对于 V4R2 版本的钱包来说,op 为 0 表示原生币发送,参考:https://github.com/ton-blockchain/wallet-contract/blob/4111fd9e3313ec17d99ca9b5b1656445b5b49d8f/func/wallet-v4-code.fc#L94
注 3:对于 V4R2 版本的钱包来说,body 中的 signature 在 signing message 的前面(V5R1 钱包恰恰相反,signature 在 signing message 的后面)。这是由 V4R2/V5R1 合约中的代码决定的,参考:https://github.com/ton-blockchain/wallet-contract/blob/4111fd9e3313ec17d99ca9b5b1656445b5b49d8f/func/wallet-v4-code.fc#L73https://github.com/ton-blockchain/wallet-contract-v5/blob/88557ebc33047a95207f6e47ac8aadb102dff744/contracts/wallet_v5.fc#L165
注 4:上面数据中既有二进制表示,又有十六进制表示。并且这些数据没有按字节(或半字节)对齐,所以如果直接在 Tx 的十六进制表达中搜索签名数据,会找不到(因为没有按半字节对齐,它们错位了)。

1.1.2. Cell 1

Cell 0 有且只有一个引用,就是 Cell 1。前面介绍中提到了 Cell 1 由下面 488 bits 数据组成:

0x42004e752d9f7cc330f8b52957d4da83ec8bf02586bf309be218c4fbbe38b48ba762203ade5000000000000000000000000000000000000048656c6c6f

Cell 1 数据可分解为下面更易读的形式:

            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
 internal   
 message    
 header     
 (414 bits) 
            
            
            
            
            
            
            
            
            
            
            
            
 magic bits             0b0                                                                  0 表示 int_msg_info,https://ton.org/tblkch.pdf                                    
 ihrDisabled            0b1                                                                  目前总是 1。因为 Instant Hypercube Routing 还没有被完全实现                        
 isBounceable           0b0                                                                  0,因为接收地址 0QCc6ls--YZh8WpSr6m1B9kX4EsNfmE3xDGJ93xxaRdOxAhM 为 Non-bounceable 
 bounced                0b0                                                                  0 表示没有被弹回                                                                   
 src addr               0b00                                                                 00 表示 none addr                                                                  
          
          
 dest     
 addr     
          
          
          
 addr flag   0b10                                                                 10 表示 std addr                                                                   
 anycast     0b0                                                                                                                                                     
 workchain   0b00000000                                                           workchain                                                                          
 addr hash   0x9cea5b3ef98661f16a52afa9b507d917e04b0d7e6137c43189f77c7169174ec4   接收者的 raw 地址                                                                  
          
 currency 
 collect- 
 tion     
          
 size        0b0100                                                               转帐数量占 4 字节                                                                  
 value       0x075bca00                                                           转帐数量 123456000                                                                 
 other       0b0                                                                  0 means no other (i.e. ExtraCurrencyCollection) in CurrencyCollection              
 ihr fee (4 bits)       0b0000                                                                                                                                                  
 forward fee (4 bits)   0b0000                                                                                                                                                  
 created lt (64 bits)   0x0000000000000000                                                                                                                                      
 created at (32 bits)   0x00000000                                                                                                                                              
 message init present flag (1 bit)   0b0                                                                  0 表示 message 没有 init 数据                                                      
 message body ref flag (1 bit)       0b0                                                                  0 表示 Cell 剩下空间可放下整个 body;1 表示 Cell 空间不够,body 需要放在 ref 中    
            
 body       
 (72 bits)  
 type of payload        0x00000000                                                           32 bits 0 表示 string                                                              
 payload                0x48656c6c6f                                                         交易备注 Hello                                                                     

注:Cell 1 一共有 414+1+1+72 = 488 bits 数据。

1.2. Tx 解析实例 2(V5R1 钱包部署及原生币转帐)

下面介绍测试网上另一个 Tx b35192b5d7c975d3c86903059964e38775aa6cf271cd6923d0c9ef21e79e2413 的细节。

这个交易的功能是测试网上 V5R1 钱包进行原生币 TON 的转帐(注:由于这是帐户 0QBu6dyecFJBVzjtTEUTTPcZpdJhCDnIMQ3To4PZS0DrVqp_ 的首个 Tx,所以这个 Tx 中还会部署钱包合约):

0QBu6dyecFJBVzjtTEUTTPcZpdJhCDnIMQ3To4PZS0DrVqp_ (V5R1 wallet)      --- 0.1234 TON -->      0QASPuJu9dYvKyQuV-vQL4YKOEa9uXNkslh0qRbU5quI7TTU

这个 Tx 是通过 RPC sendBoc 提交上链的,提交 Tx 时的具体参数如下:

$ curl 'https://testnet.toncenter.com/api/v2/jsonRPC' \
-X POST \
-H 'Content-Type: application/json' \
--data-raw '{"id":"1","jsonrpc":"2.0","method":"sendBoc","params":{"boc":"te6cckECGQEAA3UAA+eIAN3TuTzgpIKucdqYiiaZ7jNLpMIQc5BiG6dHB7KWgdasEY5tLO3P////v////+AAAAAW8m9QlO0hQ8Io17rpq2NooiJiF5nEC4ADFcikdU2QvJ/x6LwsurKdCxkgJdhRsQbnbQY7ERPoMFSpNLGeXLsoPAEVFgEU/wD0pBP0vPLICwICASADDgIBSAQFAtzQINdJwSCRW49jINcLHyCCEGV4dG69IYIQc2ludL2wkl8D4IIQZXh0brqOtIAg1yEB0HTXIfpAMPpE+Cj6RDBYvZFb4O1E0IEBQdch9AWDB/QOb6ExkTDhgEDXIXB/2zzgMSDXSYECgLmRMOBw4hEQAgEgBg0CASAHCgIBbggJABmtznaiaEAg65Drhf/AABmvHfaiaEAQ65DrhY/AAgFICwwAF7Ml+1E0HHXIdcLH4AARsmL7UTQ1woAgABm+Xw9qJoQICg65D6AsAQLyDwEeINcLH4IQc2lnbrry4Ip/EAHmjvDtou37IYMI1yICgwjXIyCAINch0x/TH9Mf7UTQ0gDTHyDTH9P/1woACvkBQMz5EJoolF8K2zHh8sCH3wKzUAew8tCEUSW68uCFUDa68uCG+CO78tCIIpL4AN4BpH/IygDLHwHPFsntVCCS+A/ecNs82BED9u2i7fsC9AQhbpJsIY5MAiHXOTBwlCHHALOOLQHXKCB2HkNsINdJwAjy4JMg10rAAvLgkyDXHQbHEsIAUjCw8tCJ10zXOTABpOhsEoQHu/Lgk9dKwADy4JPtVeLSAAHAAJFb4OvXLAgUIJFwlgHXLAgcEuJSELHjDyDXShITFACWAfpAAfpE+Cj6RDBYuvLgke1E0IEBQdcY9AUEnX/IygBABIMH9FPy4IuOFAODB/Rb8uCMItcKACFuAbOw8tCQ4shQA88WEvQAye1UAHIw1ywIJI4tIfLgktIA7UTQ0gBRE7ry0I9UUDCRMZwBgQFA1yHXCgDy4I7iyMoAWM8Wye1Uk/LAjeIAEJNb2zHh10zQAFGAAAAAP////tlBsCnz1yWP/sjO5CFA7bkxE/CSaZC7YJQuMiwpiYnQoAIKDsPIbQIXGAAAAIZCAAkfcTd66xeVkhcr9egXwwUcI17cubJZLDpUi2pzVcR2okxqxAAAAAAAAAAAAAAAAAAAAAAAAEhlbGxvIHdvcmxkv4KlZg=="}}'
{
  "ok": true,
  "result": {
    "@type": "ok",
    "@extra": "1722675676.5674324:1:0.5131636309140121"
  },
  "id": "1",
  "jsonrpc": "2.0"
}

上面命令中提到的 Base64 编码的 Tx 数据可以分解为下面这种更清晰的表达方式:

 magic prefix                            b5ee9c72                                                                                               魔法数字,参考 https://docs.ton.org/tblkch.pdf 5.3.9 节   
 flags and size                          41                                                                                                     后面会介绍                                                
 off bytes                               02                                                                                                     number of bytes to store the size of the serialized cells 
 number of cells                         19                                                                                                     这个例子是 25 个 cell                                     
 number of root cells                    01                                                                                                     只有 1 个 root cell                                       
 absent                                  00                                                                                                     always 0 in current implementations                       
 size of serialized cells                0375                                                                                                   size of the serialized cells,这里是 885 字节             
 root cell list                          00                                                                                                     root cell should have index 0 in case of 1 root cell      
            
            
            
            
            
            
            
            
 serialized 
 cells      
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
        
        
        
        
 cell 0 
        
        
        
        
 refs descriptor   03                                                                                                     当前 cell 有 3 个引用,当前 cell 是 ordinary cell         
 bits descriptor   e7                                                                                                     序列化后的 cell data 占用 ceil(231/2) = 116 字节          
 cell data       
                 
                 
 8800ddd3b93ce0a482ae71da988a2699ee334ba4c2107390621ba74707b29681d6ac118e6d2cedcfffffffbfffffffe00000 
 0016f26f5094ed2143c228d7bae9ab6368a222621799c40b800315c8a4754d90bc9ff1e8bc2cbab29d0b192025d851b106e7 
 6d063b1113e83054a934b19e5cbb283c                                                                     
 cell data。由于 0xe7 为奇数,有补齐                       
                                                           
                                                           
 cell refs         011516                                                                                                 所引用的 cell index 为 0x01/0x15/0x16                     
        
        
        
 cell 1 
        
        
        
 refs descriptor   01                                                                                                     当前 cell 有 1 个引用,当前 cell 是 ordinary cell         
 bits descriptor   14                                                                                                     序列化后的 cell data 占用 ceil(20/2) = 10 字节            
 cell data         ff00f4a413f4bcf2c80b                                                                                   cell data。由于 0xe7 为偶数,没有补齐                     
 cell refs         02                                                                                                     所引用的 cell index 为 0x02                               
        
        
        
 cell 2 
        
        
        
 refs descriptor   02                                                                                                     当前 cell 有 2 个引用,当前 cell 是 ordinary cell         
 bits descriptor   01                                                                                                     序列化后的 cell data 占用 ceil(1/2) = 1 字节              
 cell data         20                                                                                                     cell data。由于 0x01 为奇数,有补齐                       
 cell refs         030e                                                                                                   所引用的 cell index 为 0x03/0x0e                          
        
        
        
 cell 3 
        
        
        
 refs descriptor   02                                                                                                     当前 cell 有 2 个引用,当前 cell 是 ordinary cell         
 bits descriptor   01                                                                                                     序列化后的 cell data 占用 ceil(1/2) = 1 字节              
 cell data         48                                                                                                     cell data。由于 0x01 为奇数,有补齐                       
 cell refs         0405                                                                                                   所引用的 cell index 为 0x04/0x05                          
        
        
        
 cell 4 
        
        
        
        
        
 refs descriptor   02                                                                                                     当前 cell 有 2 个引用,当前 cell 是 ordinary cell         
 bits descriptor   dc                                                                                                     序列化后的 cell data 占用 ceil(220/2) = 110 字节          
 cell data       
                 
                 
 d020d749c120915b8f6320d70b1f2082106578746ebd21821073696e74bdb0925f03e082106578746eba8eb48020d72101d0 
 74d721fa4030fa44f828fa443058bd915be0ed44d0810141d721f4058307f40e6fa1319130e18040d721707fdb3ce03120d7 
 49810280b99130e070e2                                                                                 
 cell data。由于 0xdc 为偶数,没有补齐                     
                                                           
                                                           
 cell refs         1110                                                                                                   所引用的 cell index 为 0x11/0x10                          
        
        
        
 cell 5 
        
        
        
 refs descriptor   02                                                                                                     当前 cell 有 2 个引用,当前 cell 是 ordinary cell         
 bits descriptor   01                                                                                                     序列化后的 cell data 占用 ceil(1/2) = 1 字节              
 cell data         20                                                                                                     cell data。由于 0x01 为奇数,有补齐                       
 cell refs         060d                                                                                                   所引用的 cell index 为 0x06/0x0d                          
        
        
        
 cell 6 
        
        
        
 refs descriptor   02                                                                                                     当前 cell 有 2 个引用,当前 cell 是 ordinary cell         
 bits descriptor   01                                                                                                     序列化后的 cell data 占用 ceil(1/2) = 1 字节              
 cell data         20                                                                                                     cell data。由于 0x01 为奇数,有补齐                       
 cell refs         070a                                                                                                   所引用的 cell index 为 0x07/0x0a                          
        
        
        
 cell 7 
        
        
        
 refs descriptor   02                                                                                                     当前 cell 有 2 个引用,当前 cell 是 ordinary cell         
 bits descriptor   01                                                                                                     序列化后的 cell data 占用 ceil(1/2) = 1 字节              
 cell data         6e                                                                                                     cell data。由于 0x01 为奇数,有补齐                       
 cell refs         0809                                                                                                   所引用的 cell index 为 0x08/0x09                          
        
        
        
 cell 8 
        
 refs descriptor   00                                                                                                     当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   19                                                                                                     序列化后的 cell data 占用 ceil(25/2) = 13 字节            
 cell data         adce76a2684020eb90eb85ffc0                                                                             cell data。由于 0x19 为奇数,有补齐                       
        
        
        
 cell 9 
        
 refs descriptor   00                                                                                                     当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   19                                                                                                     序列化后的 cell data 占用 ceil(25/2) = 13 字节            
 cell data         af1df6a2684010eb90eb858fc0                                                                             cell data。由于 0x19 为奇数,有补齐                       
        
        
        
 cell   
 10     
        
        
 refs descriptor   02                                                                                                     当前 cell 有 2 个引用,当前 cell 是 ordinary cell         
 bits descriptor   01                                                                                                     序列化后的 cell data 占用 ceil(1/2) = 1 字节              
 cell data         48                                                                                                     cell data。由于 0x01 为奇数,有补齐                       
 cell refs         0b0c                                                                                                   所引用的 cell index 为 0x0b/0x0c                          
        
 cell   
 11     
        
        
 refs descriptor   00                                                                                                     当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   17                                                                                                     序列化后的 cell data 占用 ceil(23/2) = 12 字节            
 cell data         b325fb51341c75c875c2c7e0                                                                               cell data。由于 0x17 为奇数,有补齐                       
        
 cell   
 12     
        
        
 refs descriptor   00                                                                                                     当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   11                                                                                                     序列化后的 cell data 占用 ceil(17/2) = 9 字节             
 cell data         b262fb513435c28020                                                                                     cell data。由于 0x11 为奇数,有补齐                       
        
 cell   
 13     
        
        
 refs descriptor   00                                                                                                     当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   19                                                                                                     序列化后的 cell data 占用 ceil(25/2) = 13 字节            
 cell data         be5f0f6a2684080a0eb90fa02c                                                                             cell data。由于 0x19 为奇数,有补齐                       
        
        
        
 cell   
 14     
        
        
 refs descriptor   01                                                                                                     当前 cell 有 1 个引用,当前 cell 是 ordinary cell         
 bits descriptor   02                                                                                                     序列化后的 cell data 占用 ceil(2/2) = 1 字节              
 cell data         f2                                                                                                     cell data。由于 0x02 为偶数,没有补齐                     
 cell refs         0f                                                                                                     所引用的 cell index 为 0x0f                               
        
        
        
 cell   
 15     
        
        
 refs descriptor   01                                                                                                     当前 cell 有 1 个引用,当前 cell 是 ordinary cell         
 bits descriptor   1e                                                                                                     序列化后的 cell data 占用 ceil(30/2) = 15 字节            
 cell data         20d70b1f82107369676ebaf2e08a7f                                                                         cell data。由于 0x1e 为偶数,没有补齐                     
 cell refs         10                                                                                                     所引用的 cell index 为 0x10                               
        
        
        
 cell   
 16     
        
        
        
        
 refs descriptor   01                                                                                                     当前 cell 有 1 个引用,当前 cell 是 ordinary cell         
 bits descriptor   e6                                                                                                     序列化后的 cell data 占用 ceil(230/2) = 115 字节          
 cell data       
                 
                 
 8ef0eda2edfb218308d722028308d723208020d721d31fd31fd31fed44d0d200d31f20d31fd3ffd70a000af90140ccf9109a 
 28945f0adb31e1f2c087df02b35007b0f2d0845125baf2e0855036baf2e086f823bbf2d0882292f800de01a47fc8ca00cb1f 
 01cf16c9ed542092f80fde70db3cd8                                                                       
 cell data。由于 0xe6 为偶数,没有补齐                     
                                                           
                                                           
 cell refs         11                                                                                                     所引用的 cell index 为 0x11                               
        
        
        
 cell   
 17     
        
        
        
        
 refs descriptor   03                                                                                                     当前 cell 有 3 个引用,当前 cell 是 ordinary cell         
 bits descriptor   f6                                                                                                     序列化后的 cell data 占用 ceil(246/2) = 123 字节          
 cell data       
                 
                 
 eda2edfb02f404216e926c218e4c0221d73930709421c700b38e2d01d72820761e436c20d749c008f2e09320d74ac002f2e0 
 9320d71d06c712c2005230b0f2d089d74cd7393001a4e86c128407bbf2e093d74ac000f2e093ed55e2d20001c000915be0eb 
 d72c08142091709601d72c081c12e25210b1e30f20d74a                                                       
 cell data。由于 0xf6 为偶数,没有补齐                     
                                                           
                                                           
 cell refs         121314                                                                                                 所引用的 cell index 为 0x12/0x13/0x14                     
        
        
        
 cell   
 18     
        
 refs descriptor   00                                                                                                     当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   96                                                                                                     序列化后的 cell data 占用 ceil(150/2) = 75 字节           
 cell data       
                 
 01fa4001fa44f828fa443058baf2e091ed44d0810141d718f405049d7fc8ca0040048307f453f2e08b8e14038307f45bf2e0 
 8c22d70a00216e01b3b0f2d090e2c85003cf1612f400c9ed54                                                   
 cell data。由于 0x96 为偶数,没有补齐                     
                                                           
        
        
        
 cell   
 19     
        
 refs descriptor   00                                                                                                     当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   72                                                                                                     序列化后的 cell data 占用 ceil(114/2) = 57 字节           
 cell data       
                 
 30d72c08248e2d21f2e092d200ed44d0d2005113baf2d08f54503091319c01810140d721d70a00f2e08ee2c8ca0058cf16c9 
 ed5493f2c08de2                                                                                       
 cell data。由于 0x72 为偶数,没有补齐                     
                                                           
        
 cell   
 20     
        
        
 refs descriptor   00                                                                                                     当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   10                                                                                                     序列化后的 cell data 占用 ceil(16/2) = 8 字节             
 cell data         935bdb31e1d74cd0                                                                                       cell data。由于 0x10 为偶数,没有补齐                     
        
 cell   
 21     
        
        
 refs descriptor   00                                                                                                     当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   51                                                                                                     序列化后的 cell data 占用 ceil(81/2) = 41 字节            
 cell data         800000003ffffffed941b029f3d7258ffec8cee42140edb93113f0926990bb60942e322c298989d0a0                     cell data。由于 0x51 为奇数,有补齐                       
        
        
        
 cell   
 22     
        
        
 refs descriptor   02                                                                                                     当前 cell 有 2 个引用,当前 cell 是 ordinary cell         
 bits descriptor   0a                                                                                                     序列化后的 cell data 占用 ceil(10/2) = 5 字节             
 cell data         0ec3c86d02                                                                                             cell data。由于 0x0a 为偶数,没有补齐                     
 cell refs         1718                                                                                                   所引用的 cell index 为 0x17/0x18                          
 cell   
 23     
        
 refs descriptor   00                                                                                                     当前 cell 没个引用,当前 cell 是 ordinary cell            
 bits descriptor   00                                                                                                     序列化后的 cell data 占用 ceil(0/2) = 0 字节              
        
 cell   
 24     
        
        
        
 refs descriptor   00                                                                                                     当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   86                                                                                                     序列化后的 cell data 占用 ceil(134/2) = 67 字节           
 cell data       
                 
 4200091f71377aeb179592172bf5e817c3051c235edcb9b2592c3a548b6a7355c476a24c6ac4000000000000000000000000 
 00000000000048656c6c6f20776f726c64                                                                   
 cell data。由于 0x86 为偶数,没有补齐                     
                                                           
 crc32c                                  bf82a566                                                                                               crc32c 校验码                                             

可见,这个 Tx 中一共编码了 25 个 Cell,为什么这么多呢?这是由于这个 Tx 是帐户 0QBu6dyecFJBVzjtTEUTTPcZpdJhCDnIMQ3To4PZS0DrVqp_ 的首个 Tx,所以这个 Tx 中还包含了钱包合约的 Init Code 和 Init Data,所以导致 Cell 会比较多。

1.2.1. Cell 0

前面介绍中提到了 Cell 0 由下面数据组成:

8800ddd3b93ce0a482ae71da988a2699ee334ba4c2107390621ba74707b29681d6ac118e6d2cedcfffffffbfffffffe00000
0016f26f5094ed2143c228d7bae9ab6368a222621799c40b800315c8a4754d90bc9ff1e8bc2cbab29d0b192025d851b106e7
6d063b1113e83054a934b19e5cbb283c

下面把 Cell 0 数据分解为更易读的形式:

            
            
            
            
 external   
 message    
 header     
 (275 bits) 
            
            
            
            
            
 magic bits             0b10                                                                 10 表示 ext_in_msg_info,https://ton.org/tblkch.pdf                                              
 src addr               0b00                                                                 00 表示 none addr                                                                                
      
      
 dest 
 addr 
      
      
      
 addr flag       0b10                                                                 10 表示 std addr                                                                                 
 anycast         0b0                                                                                                                                                                   
 workchain       0b00000000                                                           workchain                                                                                        
 addr hash       0x6ee9dc9e7052415738ed4c45134cf719a5d2610839c8310dd3a383d94b40eb56   发送者的 raw 地址                                                                                
 import fee             0b0000                                                                                                                                                                
 stateInit present flag (1 bit)      0b1                                                                  0 没有 stateInit;1 有 stateInit。这里是首次提交 Tx 会创建钱包合约,所以它是 1                   
 stateInit ref flag (1 bit)          0b0                                                                  0 表示 Cell 剩下空间可放下 stateInit;1 表示 Cell 空间不够(需要放在 ref 中)                    
            
            
            
            
 stateInit  
            
            
            
            
 split depth            0b0                                                                  0 表示 no splitDepth in StateInit                                                                
 sepcial                0b0                                                                  0 表示 no special in StateInit                                                                   
 init code ref flag     0b1                                                                  1 表示 init code 保存在当前 Cell 的 ref 中。第 1 个 ref                                          
 init data ref flag     0b1                                                                  1 表示 init data 保存在当前 Cell 的 ref 中。第 2 个 ref                                          
 libraries              0b0                                                                  0 表示 no libraries in StateInit                                                                 
 body ref flag (1 bit)               0b0                                                                  0 表示 Cell 剩下空间可放下整个 body;1 表示 Cell 空间不够,body 需要放在 ref 中                  
      
      
      
      
      
 body 
      
      
      
      
      
      
      
      
         
         
         
         
         
 signing 
 message 
         
         
         
         
 V5R1 opcode        0x7369676e                                                           0x7369676e/0x73696e74/0x6578746e 分别为 auth_signed_external/auth_signed_internal/auth_extension 
 wallet id          0x7ffffffd                                                           0x7ffffffd(2147483645) 测试网,0x7fffff11(2147483409) 主网                                       
 valid until        0xffffffff                                                           交易过期时间,这里设置了全 1 的值(几乎不会过期)                                                
 seqno              0x00000000                                                           类似于 Ethereum 的 nonce 值                                                                      
 basic actions      0b1                                                                  1 表示 basic actions(send message) 保存在当前 Cell 的 ref 中。第 3 个 ref                        
 extended actions   0b0                                                                  0 表示没有 extended actions(add extension/remove extension/set signature allowed)                
 signature                  
 (512 bits)                 
 0xde4dea129da42878451af75d356c6d14444c42f33881700062b9148ea9b21793 
 0xfe3d1785975653a1632404bb0a3620dceda0c762227d060a95269633cb976507 
 Ed25519 签名数据                                                                                 
                                                                                                  
 cell padding                        0b100                                                                按字节补齐。如果 Cell 的 bits descriptor 为奇数,表示有 padding                                  

从上面的分析中可知 Cell 0 共有 3 个 refs(Cell 0 的 cell refs 数据为 0x011516):

  1. Init Code,对应的 Cell Index 是 0x01,即 Cell 1
  2. Init Data,对应的 Cell Index 是 0x15,即 Cell 21
  3. Basic Actions,对应的 Cell Index 是 0x16,即 Cell 22

下面我们重点分析一下 Cell 22。

1.2.2. Cell 22/23/24

通过前面的介绍可知 Cell 22 保存着 Wallet V5R1 钱包的 Basic Actions,这节将分析它。

Basic Actions 是 Out List 结构,它在 @ton/core 中是这样序列化的:

/*
out_list_empty$_ = OutList 0;
out_list$_ {n:#} prev:^(OutList n) action:OutAction
  = OutList (n + 1);
 */
export function storeOutList(actions: OutAction[]) {
    const cell = actions.reduce((cell, action) => beginCell()
            .storeRef(cell)                    // Cell 23 保存在 Cell 22 的 refs 中。Cell 22 的第 1 个 ref
            .store(storeOutAction(action))
            .endCell(),
        beginCell().endCell()                  // Begin with empty cell,就是我们这个例子中的 Cell 23(空 Cell)
    );

    return (builder: Builder) => {
        builder.storeSlice(cell.beginParse());
    }
}

/*
action_send_msg#0ec3c86d mode:(## 8)
  out_msg:^(MessageRelaxed Any) = OutAction;
*/
const outActionSendMsgTag = 0x0ec3c86d;
function storeOutActionSendMsg(action: OutActionSendMsg) {
    return (builder: Builder) => {
        builder.storeUint(outActionSendMsgTag, 32)     // Cell 22 的数据部分 1
            .storeUint(action.mode, 8)                 // Cell 22 的数据部分 2
            .storeRef(beginCell().store(storeMessageRelaxed(action.outMsg)).endCell()); // Cell 22 的第 2 个 ref
    }
}

Cell 22 数据可分解为下面更易读的形式:

 out action tag   0ec3c86d   Tag 0ec3c86d/ad4de08e 分别表示 send msg/set code。参考 https://ton.org/tblkch.pdf 4.4.11. Serialization of output actions 
 send mode        02         可简单理解为目标帐户合约没部署也不出错。参考 https://docs.ton.org/develop/smart-contracts/messages#message-modes          

Cell 22 的两个 refs 分别为:

  1. Cell 23,这是一个空 Cell,是序列化 Out List 时的首个 Cell。
  2. Cell 24,Send Message 主要内容在这个 Cell 中。

注:Cell 22 中指定的 send mode 为 2,并没有包含 +1 flag。这会导致:尽量转账数量指定的是 1.234 TON,但目标地址真正收到的 TON 的数量会在 1.234 的基础上扣除手续费(会小于 1.234)。我们查询目标地址余额也会发现确实比 1.234 要少:

$ curl 'https://testnet.toncenter.com/api/v2/getAddressBalance?address=0QASPuJu9dYvKyQuV-vQL4YKOEa9uXNkslh0qRbU5quI7TTU'
{"ok":true,"result":"1233600000"}

Cell 24 数据可分解为下面更易读的形式:

            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
 internal   
 message    
 header     
 (414 bits) 
            
            
            
            
            
            
            
            
            
            
            
            
 magic bits             0b0                                                                  0 表示 int_msg_info,https://ton.org/tblkch.pdf                                    
 ihrDisabled            0b1                                                                  目前总是 1。因为 Instant Hypercube Routing 还没有被完全实现                        
 isBounceable           0b0                                                                  0,因为接收地址 0QASPuJu9dYvKyQuV-vQL4YKOEa9uXNkslh0qRbU5quI7TTU 为 Non-bounceable 
 bounced                0b0                                                                  0 表示没有被弹回                                                                   
 src addr               0b00                                                                 00 表示 none addr                                                                  
          
          
 dest     
 addr     
          
          
          
 addr flag   0b10                                                                 10 表示 std addr                                                                   
 anycast     0b0                                                                                                                                                     
 workchain   0b00000000                                                           workchain                                                                          
 addr hash   0x123ee26ef5d62f2b242e57ebd02f860a3846bdb97364b25874a916d4e6ab88ed   接收者的 raw 地址                                                                  
          
 currency 
 collect- 
 tion     
          
 size        0b0100                                                               转帐数量占 4 字节                                                                  
 value       0x498d5880                                                           转帐数量 1234000000(即 1.234 TON)                                                
 other       0b0                                                                  0 means no other (i.e. ExtraCurrencyCollection) in CurrencyCollection              
 ihr fee (4 bits)       0b0000                                                                                                                                                  
 forward fee (4 bits)   0b0000                                                                                                                                                  
 created lt (64 bits)   0x0000000000000000                                                                                                                                      
 created at (32 bits)   0x00000000                                                                                                                                              
 message init present flag (1 bit)   0b0                                                                  0 表示 message 没有 init 数据                                                      
 message body ref flag (1 bit)       0b0                                                                  0 表示 Cell 剩下空间可放下整个 body;1 表示 Cell 空间不够,body 需要放在 ref 中    
 message    
 body       
 (120 bits) 
 type of payload        0x00000000                                                           32 bits 0 表示 string                                                              
 payload                0x48656c6c6f20776f726c64                                             交易备注 Hello world                                                               

1.3. Tx 解析实例 3(V5R1 钱包 Jetton 转账)

下面以 TON 主网上的 Tx edc724b8b3733afc5133d62c2b65bafa3fae31df876d87b576050ce3369e15b4 为例介绍一下这个 Tx 的细节。

这个交易的功能是主网上 V5R1 钱包进行 USDT 的转帐:

UQCh41gQP1A4I0lnAn6yAfitDAIYpXG6UFIXqeSz1TVxNOJ_ (V5R1 wallet)      --- 0.11 USDT -->         UQAU3o5-Sp1MYRpw3U7b_wmARxqI49LxiFhEoVCxpUKjTYXk

提交 Tx 时的具体参数如下:

$ curl https://toncenter.com/api/v2/sendBocReturnHash -X POST -H "Content-Type: application/json" -d '{
  "boc": "te6cckECBgEAASIAAUWIAUPGsCB+oHBGks4E/WQD8VoYBDFK43SgpC9TyWeqauJoDAEBoXNpZ25///8RZro7egAAAAGYUu8+ZHZK/wWb9ojB++h5tz2ie7e4GktWZfr475zJcnpRLZADd9wbyuuV7GXr8QzKeqvQbSDVJlgv4bcdnjwDYAICCg7DyG0DAwQAAAFoYgBwcARvtYoAq2KC3PPTyFSjlwwsLVuA3hCZtiQP1p6T4yAvrwgAAAAAAAAAAAAAAAAAAQUAyA+KfqUAAAAAAAAAADAa2wgAKb0c/JU6mMI04bqdt/4TAI41Ecel4xCwiUKhY0qFRpsAKHjWBA/UDgjSWcCfrIB+K0MAhilcbpQUhep5LPVNXE0CAgAAAAB0ZXN0IGNvbW1lbnQIl4du"
}'

上面命令中提到的 Base64 编码的 Tx 数据可以分解为下面这种更清晰的表达方式:

 magic prefix                            b5ee9c72                                                                                                         魔法数字,参考 https://docs.ton.org/tblkch.pdf 5.3.9 节   
 flags and size                          41                                                                                                               后面会介绍                                                
 off bytes                               02                                                                                                               number of bytes to store the size of the serialized cells 
 number of cells                         06                                                                                                               这个例子是 6 个 cell                                      
 number of root cells                    01                                                                                                               只有 1 个 root cell                                       
 absent                                  00                                                                                                               always 0 in current implementations                       
 size of serialized cells                0122                                                                                                             size of the serialized cells,这里是 290 字节             
 root cell list                          00                                                                                                               root cell should have index 0 in case of 1 root cell      
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
 serialized 
 cells      
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
        
        
        
        
 cell 0 
        
        
 refs descriptor   01                                                                                                               当前 cell 有一个引用,当前 cell 是 ordinary cell          
 bits descriptor   45                                                                                                               bits descriptor                                           
 cell data         880143c6b0207ea0704692ce04fd6403f15a1804314ae374a0a42f53c967aa6ae2680c                                           cell data                                                 
 cell refs         01                                                                                                               所引用的 cell index 为 1                                  
        
        
 cell 1 
        
        
        
        
        
 refs descriptor   01                                                                                                               当前 cell 有一个引用,当前 cell 是 ordinary cell          
 bits descriptor   a1                                                                                                               bits descriptor                                           
 cell data       
                 
 7369676e7fffff1166ba3b7a000000019852ef3e64764aff059bf688c1fbe879b73da27bb7b81a4b5665faf8ef9cc9727a512d900377dc 
 1bcaeb95ec65ebf10cca7aabd06d20d526582fe1b71d9e3c0360                                                           
 cell data                                                 
                                                           
 cell refs         02                                                                                                               所引用的 cell index 为 2                                  
        
        
 cell 2 
        
        
        
        
 refs descriptor   02                                                                                                               当前 cell 有两个引用,当前 cell 是 ordinary cell          
 bits descriptor   0a                                                                                                               bits descriptor                                           
 cell data         0ec3c86d03                                                                                                       cell data                                                 
 cell refs         0304                                                                                                             所引用的 cell index 为 3,4                                
        
 cell 3 
        
 refs descriptor   00                                                                                                               当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   00                                                                                                               bits descriptor                                           
        
        
 cell 4 
        
        
        
        
 refs descriptor   01                                                                                                               当前 cell 有一个引用,当前 cell 是 ordinary cell          
 bits descriptor   68                                                                                                               bits descriptor                                           
 cell data         62007070046fb58a00ab6282dcf3d3c854a3970c2c2d5b80de1099b6240fd69e93e3202faf080000000000000000000000000001         cell data                                                 
 cell refs         05                                                                                                               所引用的 cell index 为 5                                  
        
        
 cell 5 
        
        
        
 refs descriptor   00                                                                                                               当前 cell 没有引用,当前 cell 是 ordinary cell            
 bits descriptor   c8                                                                                                               bits descriptor                                           
 cell data       
                 
 0f8a7ea50000000000000000301adb080029bd1cfc953a98c234e1ba9db7fe13008e3511c7a5e310b08942a1634a85469b002878d6040f 
 d40e08d259c09fac807e2b430086295c6e941485ea792cf54d5c4d0202000000007465737420636f6d6d656e74                     
 cell data                                                 
                                                           
 crc32c                                  0897876e                                                                                                         crc32c 校验码                                             

1.3.1. Cell 0

前面介绍中提到了 Cell 0 由下面数据组成:

880143c6b0207ea0704692ce04fd6403f15a1804314ae374a0a42f53c967aa6ae2680c

下面把 Cell 0 数据分解为更易读的形式:

            
            
            
            
 external   
 message    
 header     
 (275 bits) 
            
            
            
            
            
 magic bits          0b10                                                                 10 表示 ext_in_msg_info,https://ton.org/tblkch.pdf                             
 src addr            0b00                                                                 00 表示 none addr                                                               
      
      
 dest 
 addr 
      
      
      
 addr flag    0b10                                                                 10 表示 std addr                                                                
 anycast      0b0                                                                                                                                                  
 workchain    0b00000000                                                           workchain                                                                       
 addr hash    0xa1e358103f5038234967027eb201f8ad0c0218a571ba505217a9e4b3d5357134   发送者的 raw 地址                                                               
 import fee          0b0000                                                                                                                                               
 stateInit present flag (1 bit)   0b0                                                                  0 没有 stateInit;1 有 stateInit。首次提交 Tx 创建钱包合约时,它才是 1          
 body ref flag (1 bit)            0b1                                                                  0 表示 Cell 剩下空间可放下整个 body;1 表示 Cell 空间不够,body 需要放在 ref 中 
 cell padding                     0b100                                                                按字节补齐。如果 Cell 的 bits descriptor 为奇数,表示有 padding                 

1.3.2. Cell 1

上面例子中 Cell 0 的 body ref flag 为 1,表示 Body 保存在 Cell 0 的 ref 中,而 Cell 0 只有一个 ref(Cell 1),所以 Cell 1 保存的就是 Body。

下面把 Cell 1 数据分解为更易读的形式:

      
      
      
      
      
 body 
      
      
      
      
      
      
      
      
         
         
         
         
         
 signing 
 message 
         
         
         
         
 V5R1 opcode        0x7369676e                                                           0x7369676e/0x73696e74/0x6578746e 分别为 auth_signed_external/auth_signed_internal/auth_extension 
 wallet id          0x7fffff11                                                           0x7ffffffd(2147483645) 测试网,0x7fffff11(2147483409) 主网                                       
 valid until        0x66ba3b7a                                                           交易过期时间,Unix Timestamp 1723480954                                                          
 seqno              0x00000001                                                           类似于 Ethereum 的 nonce 值                                                                      
 basic actions      0b1                                                                  1 表示 basic actions(send message) 保存在当前 Cell 的 ref 中。Cell 1 的 ref 是 Cell 2            
 extended actions   0b0                                                                  0 表示没有 extended actions(add extension/remove extension/set signature allowed)                
 signature                  
 (512 bits)                 
 0x614bbcf991d92bfc166fda2307efa1e6dcf689eedee0692d5997ebe3be7325c9 
 0xe944b6400ddf706f2bae57b197afc43329eaaf41b483549960bf86dc7678f00d 
 Ed25519 签名数据,后文会介绍它是如何计算的                                                       
                                                                                                  
 cell padding                        0b100000                                                             按字节补齐。如果 Cell 的 bits descriptor 为奇数,表示有 padding                                  

1.3.3. Cell 2/3/4/5

通过前面的介绍可知 Cell 2 保存着 Wallet V5R1 钱包的 Basic Actions,这节将分析它。Basic Actions 是 Out List 结构,细节可参考节 1.2.2

Cell 2 数据可分解为下面更易读的形式:

 out action tag   0ec3c86d   Tag 0ec3c86d/ad4de08e 分别表示 send msg/set code。参考 https://ton.org/tblkch.pdf 4.4.11. Serialization of output actions 
 send mode        03         这是 +1 flag 和 +2 flag 的组合。参考 https://docs.ton.org/develop/smart-contracts/messages#message-modes                  

Cell 2 的两个 refs 分别为:

  1. Cell 3,这是一个空 Cell,是序列化 Out List 时的首个 Cell。
  2. Cell 4,Send Message 主要内容在这个 Cell 中。

Cell 4 数据(62007070046fb58a00ab6282dcf3d3c854a3970c2c2d5b80de1099b6240fd69e93e3202faf080000000000000000000000000001)可分解为下面更易读的形式:

            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
 internal   
 message    
 header     
 (414 bits) 
            
            
            
            
            
            
            
            
            
            
            
            
 magic bits             0b0                                                                  0 表示 int_msg_info,https://ton.org/tblkch.pdf                                                    
 ihrDisabled            0b1                                                                  目前总是 1。因为 Instant Hypercube Routing 还没有被完全实现                                        
 isBounceable           0b1                                                                  1,因为接收地址 EQDg4AjfaxQBVsUFueenkKlHLhhYWrcBvCEzbEgfrT0nxuGC(USDT wallet)为 bounceable       
 bounced                0b0                                                                  0 表示没有被弹回                                                                                   
 src addr               0b00                                                                 00 表示 none addr                                                                                  
          
          
 dest     
 addr     
          
          
          
 addr flag   0b10                                                                 10 表示 std addr                                                                                   
 anycast     0b0                                                                                                                                                                     
 workchain   0b00000000                                                           workchain                                                                                          
 addr hash   0xe0e008df6b140156c505b9e7a790a9472e18585ab701bc21336c481fad3d27c6   消息接收者地址(EQDg4AjfaxQBVsUFueenkKlHLhhYWrcBvCEzbEgfrT0nxuGC),即 USDT 发送者的 jetton wallet 
          
 currency 
 collect- 
 tion     
          
 size        0b0100                                                               转帐数量占 4 字节                                                                                  
 value       0x05f5e100                                                           转帐数量 100000000(即 0.1 TON)。这个值不是用户指定的,钱包 App 指定的                            
 other       0b0                                                                  0 means no other (i.e. ExtraCurrencyCollection) in CurrencyCollection                              
 ihr fee (4 bits)       0b0000                                                                                                                                                                  
 forward fee (4 bits)   0b0000                                                                                                                                                                  
 created lt (64 bits)   0x0000000000000000                                                                                                                                                      
 created at (32 bits)   0x00000000                                                                                                                                                              
 message init present flag (1 bit)   0b0                                                                  0 表示 message 没有 init 数据                                                                      
 message body ref flag (1 bit)       0b1                                                                  0 表示 Cell 剩下空间可放下整个 body;1 表示 Cell 空间不够,body 需要放在 ref 中                    

Message Body 保存在 Cell 4 的 ref(即 Cell 5)中,下面我们介绍 Cell 5 的内容。

1.3.4. Cell 5(Jetton 转帐时的 Message body)

Cell 5 数据可分解为下面更易读的形式:

            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
 message    
 body       
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
 jetton op              0x0f8a7ea5                                                           jetton transfer op. https://github.com/ton-blockchain/minter-contract/blob/main/contracts/imports/op-codes.fc 
 query id               0x0000000000000000                                                   可以用它把 Transfer/Transfer notification/Excesses 三个消息关联起来                                           
         
 amount  
         
 size         0b0011                                                               转帐数量占 3 字节                                                                                             
 value        0x01adb0                                                             转帐数量 110000,由于 USDT 精度是 6,这里就是 0.11 USDT                                                       
         
         
 dest    
 addr    
         
         
         
 addr flag    0b10                                                                 10 表示 std addr                                                                                              
 anycast      0b0                                                                                                                                                                                
 workchain    0b00000000                                                           workchain                                                                                                     
 addr hash    0x14de8e7e4a9d4c611a70dd4edbff0980471a88e3d2f1885844a150b1a542a34d   jetton 的 new owner 地址(UQAU3o5-Sp1MYRpw3U7b_wmARxqI49LxiFhEoVCxpUKjTYXk)                                  
         
 resp    
 dest    
 addr    
         
         
         
 addr flag    0b10                                                                 10 表示 std addr                                                                                              
 anycast      0b0                                                                                                                                                                                
 workchain    0b00000000                                                           workchain                                                                                                     
 addr hash    0xa1e358103f5038234967027eb201f8ad0c0218a571ba505217a9e4b3d5357134   指定多余的 TON 会通过 Excesses 消息退给哪个地址(转移 jetton 时,会往 jetton wallet 转帐 0.1 TON 作手续费)   
 custom payload flag    0b0                                                                  0 表示没有 custom payload,1 表示 custom payload 在 ref 中                                                    
 forward 
 ton     
 amount  
 size         0b0001                                                               转帐数量占 1 字节                                                                                             
 value        0x01                                                                 大于 0 时会向 new owner 地址发送 Transfer notification 消息,这里是 0.000000001 TON                           
 forward payload flag   0b0                                                                  0 表示没有 forward payload,1 表示 forward payload 在 ref 中                                                  
         
 comment 
         
 type         0x00000000                                                           32 bits 0 表示 string                                                                                         
 payload      0x7465737420636f6d6d656e74                                           交易备注。这里是 test comment 的编码                                                                          

2. 附录

2.1. Message Hash 计算

通过 RPC sendBocReturnHash 提交 Tx 时会返回 Message Hash。

Message Hash 就是 Root Cell 的“标准 Cell 表示哈希”,其具体规则可参考:Standard Cell representation hash

下面是节 1.1 中 Message Hash 为 V8Y4wRJOdKphKnSjkBcWYTbIMTTcPrOq/1VA0zH1o4c= ,下面演示一下它的计算过程:

import hashlib
import base64

# Standard Cell representation hash calculation
# https://docs.ton.org/develop/data-formats/cell-boc#standard-cell-representation-hash-calculation

cell_1_refs_descriptor = '00'
cell_1_bits_descriptor = '7a'
cell_1_data = '42004e752d9f7cc330f8b52957d4da83ec8bf02586bf309be218c4fbbe38b48ba762203ade5000000000000000000000000000000000000048656c6c6f'
# cell 1 has no refs, so skip the refs descriptor and refs hashes
cell_1_cell_hash = hashlib.sha256(
    bytes.fromhex(cell_1_refs_descriptor
                  + cell_1_bits_descriptor
                  + cell_1_data
                  )).hexdigest()

cell_0_refs_descriptor = '01'
cell_0_bits_descriptor = 'e1'
cell_0_data = '880119e26ed9ec68605b78dbf4e024f717f67a381d1578b99e026ac4f16a9ba6306802ee8e2b3f71ddcf12c08f47a2a014393b7864e300a4f3ce093e710dd940567482f1ca7943e9bcc3ec472d54e97c3aa4a7f686b7b6ab519692694bb8ada44e78094d4d18bb328e7e2000000018001c'
cell_0_refs_depth = '0000'
cell_0_refs_hashes = cell_1_cell_hash

cell_0_cell_hash = hashlib.sha256(
    bytes.fromhex(cell_0_refs_descriptor
                  + cell_0_bits_descriptor
                  + cell_0_data
                  + cell_0_refs_depth
                  + cell_0_refs_hashes
                  )).digest()

print(cell_0_cell_hash.hex())  # 57c638c1124e74aa612a74a39017166136c83134dc3eb3aaff5540d331f5a387
print(base64.b64encode(cell_0_cell_hash))  # V8Y4wRJOdKphKnSjkBcWYTbIMTTcPrOq/1VA0zH1o4c=

2.2. Tx 解析实例 1 中的签名计算(Python)

1.1 中的交易的 Ed25519 签名数据是:

0x5dd1c567ee3bb9e25811e8f4540287276f0c9c60149e79c127ce21bb280ace905e394f287d37987d88e5aa9d2f875494fed0d6f6d56a32d24d297715b489cf01

下面 Python 代码演示了它是如何计算出来的:

import hashlib
import nacl.encoding
import nacl.signing


# 生成要签名的数据,它是 signing message 的 Standard Cell representation hash
# See https://docs.ton.org/develop/data-formats/cell-boc#standard-cell-representation-hash-calculation
def get_data_to_be_signed():
    cell_1_refs_descriptor = '00'
    cell_1_bits_descriptor = '7a'
    cell_1_data = '42004e752d9f7cc330f8b52957d4da83ec8bf02586bf309be218c4fbbe38b48ba762203ade5000000000000000000000000000000000000048656c6c6f'
    cell_1_hash = hashlib.sha256(
        bytes.fromhex(cell_1_refs_descriptor + cell_1_bits_descriptor + cell_1_data)).hexdigest()

    signing_message_refs_descriptor = '01'  # signing message has one reference to cell 1
    signing_message_bits_descriptor = '1c'
    signing_message_data = ('29a9a317'  # wallet id, you can get it from the cell 0
                            + '6651cfc4'  # expire time, you can get it from the cell 0
                            + '00000003'  # seqno, you can get it from the cell 0
                            + '00'  # op, you can get it from the cell 0
                            + '03'  # send mode, you can get it from the cell 0
                            + '0000'  # max depth as array
                            + cell_1_hash)

    return hashlib.sha256(bytes.fromhex(signing_message_refs_descriptor
                                        + signing_message_bits_descriptor
                                        + signing_message_data)).digest()


# Ed25519 私钥
private_key = bytes.fromhex('e36740a50f44ae14fdc3682f14361f7a686738dd624c0e9b9bc9183b7ef6b7cb')

# 使用指定的私钥生成签名密钥
signing_key = nacl.signing.SigningKey(private_key, encoder=nacl.encoding.RawEncoder)

# 生成验证密钥
verify_key = signing_key.verify_key
print("public key:", verify_key.encode().hex())  # 6091a31d2acd5b5eb42a29888d106043796c1a438d1e000406e688f3d831056e

# 要签名的消息
data = get_data_to_be_signed()
print("data to be signed:", data.hex())  # 468e22fbaf2cf2578ecd879334eaf4bb80feb8e2f07d2c1e6f80201a50616ed9

# 对 data 进行签名
signature = signing_key.sign(data).signature
print("signature:",
      signature.hex())  # 5dd1c567ee3bb9e25811e8f4540287276f0c9c60149e79c127ce21bb280ace905e394f287d37987d88e5aa9d2f875494fed0d6f6d56a32d24d297715b489cf01

# 验证签名
try:
    verify_key.verify(data, signature)
    print("Signature verified")
except nacl.exceptions.BadSignatureError:
    print("Signature verification failed")

2.3. 帐户合约部署 VS Jetton 合约部署

往目标地址转账 Jetton 时,如果目标地址还没有部署 Jetton 合约,则会先为目标地址部署 Jetton 合约。这是因为用户的 Jetton 余额保存在用户的 Jetton 合约中, 不部署 Jetton 合约的话,就无法为目标地址用户记录 Jetton 余额。

这一点和原生币不一样!我们给某目标地址转账原生币时,如果目标帐户合约还没有部署也无需帮他部署,因为在目标合约部署之前 TON 链上有能力为这个地址记录原生币 TON 的余额(即 TON 链可以为处于 uninitialized 状态的合约记录原生币余额,也就是说原生币 TON 余额并不是保存在合约中)。其实就算你在转账 TON 时想帮目标帐户合约部署也很难实现,因为你没有目标帐户合约的 Init Code 和 Init Data,你最多只是猜测它可能是 V4R2/V5R1 等合约,如果目标合约完全是用户自已定制的,这种情况是没有办法帮忙部署的,除非他在链下发送给你。

关于钱包帐户合约和 Jetton 合约的部署时机的对比可以参考表 1

Table 1: 钱包帐户合约部署时机 VS Jetton 合约部署时机
  一般部署时机 一般谁部署
钱包帐户(如 V4R2/V5R1)合约 首次往外转账原生币 TON 时 自己部署
Jetton 合约 首次收到别人转来的 Jetton 时 别人部署

考虑场景:Address 1 往 Address 2 转账 Jetton USDT,这会涉及到几个合约的部署呢?

  1. Address 1 曾经往外发过交易(帐户合约已经部署),Address 2 以前收过 Jetton USDT。这时不会有合约被部署。
  2. Address 1 曾经往外发过交易(帐户合约已经部署),但 Address 2 以前没有收过 Jetton USDT。在这种情况下这个 Tx 会部署一个合约,即别人(即 Address 2)的 Jetton USDT 合约。
  3. Address 1 以前没有往外发过交易(Address 1 帐户合约未部署过),Address 2 以前收过 Jetton USDT。在这种情况下这个 Tx 会部署一个合约,即自己(即 Address 1)的帐户合约。
  4. Address 1 以前没有往外发过交易(Address 1 帐户合约未部署过),而且恰好 Address 2 是首次收到 Jetton USDT。在这种情况下这个 Tx 会部署两个合约:一是自己(即 Address 1)的帐户合约;二是部署别人(即 Address 2)的 Jetton USDT 合约。链上就有这样的例子,比如 Tx 00defd4857b646c31b46049c1c8f61cc17d6cf3df1d0a22f40e325126dd2296c

注意:上面讨论的是最简单的场景,没有考虑 Mintless Jetton 的情况,也没有考虑由于 Transfer Notification 触发其它合约部署的情况。

Author: cig01

Created: <2024-05-27 Mon>

Last updated: <2024-09-28 Sat>

Creator: Emacs 27.1 (Org mode 9.4)