증명 검증 (저수준)
개요
이 섹션은 TON과의 저수준 상호작용 지침을 설명합니다. 특수 셀, TL-B 언어를 숙지하고 간단한 증명 검증 예제를 이해하고 있어야 합니다.
이 문서는 Liteserver의 증명 검증을 위한 고급 예제를 설명합니다.
블록체인과의 신뢰할 수 있는 상호작용을 위해서는 노드로부터 받는 모든 데이터를 검증하는 것이 중요합니다. 하지만 이 문서는 Liteserver 와의 신뢰할 수 있는 통신의 일부만 다룹니다. Liteserver(또는 다른 곳)로부터 받은 블록 해시를 검증했다고 가정하기 때문입니다. 블록 해시 검증은 키 블록을 동기화하고 (또는) 블록 서명을 확인해야 하기 때문에 더 고급 주제이며, 향후 다른 문서에서 설명될 예정입니다. 하지만 이 예제들만 사용하더라도 Liteserver가 잘못된 데이터를 보내고 우리가 그것을 믿을 확률을 줄일 수 있습니다.
블록 헤더
블록 ID를 알고 있다고 가정해봅시다:
<TL BlockIdExt [wc=-1, shard=-9223372036854775808, seqno=31220993, root_hash=51ed3b9e728e7c548b15a5e5ce988b4a74984c3f8374f3f1a52c7b1f46c26406, file_hash=d4fcdc692de1a252deb379cd25774842b733e6a96525adf82b8ffc41da667bf5] >
그리고 Liteserver에 이 블록의 헤더를 요청합니다. Liteserver 응답에는
header_proof
boc이 포함됩니다.
Show boc
b5ee9c72010207010001470009460351ed3b9e728e7c548b15a5e5ce988b4a74984c3f8374f3f1a52c7b1f46c26406001601241011ef55aaffffff110204050601a09bc7a98700000000040101dc65010000000100ffffffff000000000000000064b6c356000023d38ba64000000023d38ba64004886d00960007028101dc64fd01dc42bec400000003000000000000002e030098000023d38b96fdc401dc650048a3971c46472b85c8d761060a6e7ae9f13a90cdda815915a89597cfecb393a6b568807adfb3c1c5efc920907225175db61ca384e4f8b313799e3cbb8b7b4085284801018c6053c1185700c0fe4311d5cf8fa533ea0382e361a7b76d0cf299b75ac0356c000328480101741100d622b0d5264bcdb86a14e36fc8c349b82ae49e037002eb07079ead8b060015284801015720b6aefcbf406209522895faa6c0d10cc3315d90bcaf09791b19f595e86f8f0007
boc 역직렬화 후, 다음과 같은 Cell을 얻습니다:
280[0351ED3B9E728E7C548B15A5E5CE988B4A74984C3F8374F3F1A52C7B1F46C264060016] -> {
64[11EF55AAFFFFFF11] -> {
640[9BC7A98700000000040101DC65010000000100FFFFFFFF000000000000000064B6C356000023D38BA64000000023D38BA64004886D00960007028101DC64FD01DC42BEC400000003000000000000002E] -> {
608[000023D38B96FDC401DC650048A3971C46472B85C8D761060A6E7AE9F13A90CDDA815915A89597CFECB393A6B568807ADFB3C1C5EFC920907225175DB61CA384E4F8B313799E3CBB8B7B4085]
},
288[01018C6053C1185700C0FE4311D5CF8FA533EA0382E361A7B76D0CF299B75AC0356C0003],
288[0101741100D622B0D5264BCDB86A14E36FC8C349B82AE49E037002EB07079EAD8B060015],
288[01015720B6AEFCBF406209522895FAA6C0D10CC3315D90BCAF09791B19F595E86F8F0007]
}
}
이를 Block TLB 스키마에 따라 역직렬화해야 합니다:
{
'global_id': -239,
'info':
{
'version': 0,
'not_master': 0,
'after_merge': 0,
'before_split': 0,
'after_split': 0,
'want_split': False,
'want_merge': True,
'key_block': False,
'vert_seqno_incr': 0,
'flags': 1,
'seqno': 31220993,
'vert_seqno': 1,
'shard': {'shard_pfx_bits': 0, 'workchain_id': -1, 'shard_prefix': 0},
'gen_utime': 1689699158,
'start_lt': 39391488000000,
'end_lt': 39391488000004,
'gen_validator_list_hash_short': 2288844950,
'gen_catchain_seqno': 459393,
'min_ref_mc_seqno': 31220989,
'prev_key_block_seqno': 31212222,
'gen_software': {'version': 3, 'capabilities': 46},
'master_ref': None,
'prev_ref': {'type_': 'prev_blk_info', 'prev': {'end_lt': 39391487000004, 'seqno': 31220992, 'root_hash': b'H\xa3\x97\x1cFG+\x85\xc8\xd7a\x06\nnz\xe9\xf1:\x90\xcd\xda\x81Y\x15\xa8\x95\x97\xcf\xec\xb3\x93\xa6', 'file_hash': b'\xb5h\x80z\xdf\xb3\xc1\xc5\xef\xc9 \x90r%\x17]\xb6\x1c\xa3\x84\xe4\xf8\xb3\x13y\x9e<\xbb\x8b{@\x85'}},
'prev_vert_ref': None
},
'value_flow': None,
'state_update': None,
'extra': None
}
이제 역직렬화된 블록의 seqno
가 우리가 알고 있는 블록 seqno
와 일치하는지 확인하고, 유일한 Merkle Proof 참조의 hash_1을 계산하여 우리가 알고 있는 블록 해시와 비교합니다:
assert h_proof.refs[0].get_hash(0) == block_id.root_hash
이제 이 Cell에 포함된 다른 모든 데이터를 신뢰할 수 있습니다.
전체 블록
liteserver.getBlock
메서드의 경우 증명 검증은 위에서 설명한 것과 같지만, Value Flow, State Update, Block Extra 스키마에 대해 가지치기된 브랜치 대신 전체 셀을 포함합니다.
샤드 블록
샤드 증명은 샤드 참조가 실제로 우리가 Liteserver에 제공한 마스터체인 블록에 저장되어 있다는 증명입니다. liteServer.getShardInfo
, liteServer.getAccountState
, liteServer.runSmcMethod
메서드를 호출할 때 이러한 증명을 확인해야 합니다.
위에서 언급한 마스터체인 블록에 대한 샤드 정보를 Liteserver에 요청해봅시다:
await client.raw_get_shard_info(master, wc=0)
Liteserver 응답은 샤드 블록의 BlockIdExt를 포함합니다:
<TL BlockIdExt [wc=0, shard=-9223372036854775808, seqno=36908135, root_hash=39e5cbca5bf69750b5d9897872c3a0d7a3e614e521c53e4de728fafed38dce27, file_hash=f1f0e5cdc4b8a12cf2438dcab60f4712d1dc04f3792b1d72f2500cbf640948b7] >
샤드 증명 boc:
Show boc
b5ee9c72010219020004b9010009460332bf3592969931ca4fbc7715494b50597f1884c0d847456029d8cf0e526e6046016f0209460351ed3b9e728e7c548b15a5e5ce988b4a74984c3f8374f3f1a52c7b1f46c26406001611245b9023afe2ffffff1100ffffffff000000000000000001dc65010000000164b6c356000023d38ba6400401dc64fd600304050628480101affe84cdd73951bce07eeaad120d00400295220d6f66f1163b5fa8668202d72b000128480101faed0dd3ca110ada3d22980e3795d2bdf15450e9159892bbf330cdfd13a3b880016e22330000000000000000ffffffffffffffff820ce9d9c3929379c82807082455cc26aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac23519b11eddc69b7e090a0b0c28480101a5a7d24057d8643b2527709d986cda3846adcb3eddc32d28ec21f69e17dbaaef000128480101deab5a5aaf79c5e24f8dcbbe51747d6804104f75f58ed5bed4702c353545c6ac00110103d0400d284801015394592e3a3f1e3bc2d4249e993d0ec1e33ca18f49533991274ebc65276cd9a5001122bf0001aaa0161d000702816000047a7172dfb88800011e8b625908200ee215f71061846393a08c682e87bc3a12aff2d246eb97a09164f5657f96f9a252ef71580fe5309a823f73f3c4c3f8ab73f5a85bbf204bfd22e68d36d0efab1818e7b428be0f1028480101b20e36a3b36a4cdee601106c642e90718b0a58daf200753dbb3189f956b494b6000101db50119963380ee3280800011e9c5cb7ee0000011e9c5cb7ee29cf2e5e52dfb4ba85aecc4bc3961d06bd1f30a7290e29f26f3947d7f69c6e713f8f872e6e25c50967921c6e55b07a38968ee0279bc958eb97928065fb204a45b88000381abc00000000000000000ee327eb25b61a8a0e001343c9b67a721dcd6500202848010150fcc05bd9723571b83316a5f650be31edb131d05fdc78d271486e5d4ef077e1001928480101e5be728200b172cf7e2356cba2ae1c6e2c790be7c03cd7814c6e6fe3080b944b0011241011ef55aaffffff111213141501a09bc7a98700000000040101dc65010000000100ffffffff000000000000000064b6c356000023d38ba64000000023d38ba64004886d00960007028101dc64fd01dc42bec400000003000000000000002e16284801018c6053c1185700c0fe4311d5cf8fa533ea0382e361a7b76d0cf299b75ac0356c00032a8a0478e0f0e601ba1161ecc1395e9a0475c4f80aadbd6c483f210e96e29cf36789e432bf3592969931ca4fbc7715494b50597f1884c0d847456029d8cf0e526e6046016f016f1718284801015720b6aefcbf406209522895faa6c0d10cc3315d90bcaf09791b19f595e86f8f00070098000023d38b96fdc401dc650048a3971c46472b85c8d761060a6e7ae9f13a90cdda815915a89597cfecb393a6b568807adfb3c1c5efc920907225175db61ca384e4f8b313799e3cbb8b7b4085688c010378e0f0e601ba1161ecc1395e9a0475c4f80aadbd6c483f210e96e29cf36789e46492304dfb6ef9149781871464af686056a9627f882f60e3b24f8c944a75ebaf016f0014688c010332bf3592969931ca4fbc7715494b50597f1884c0d847456029d8cf0e526e6046da58493ccb5da3876129b0190f3c375e69e59c3ad9ff550be708999dad1f6f39016f0014
그리고 만약 Liteserver를 신뢰한다면 결과로 사용할 수 있는 shard_descr
boc:
Show boc
b5ee9c7201010201007d0001db50119963380ee3280800011e9c5cb7ee0000011e9c5cb7ee29cf2e5e52dfb4ba85aecc4bc3961d06bd1f30a7290e29f26f3947d7f69c6e713f8f872e6e25c50967921c6e55b07a38968ee0279bc958eb97928065fb204a45b88000381abc00000000000000000ee327eb25b61a8a01001343c9b67a721dcd650020
샤드 증명 boc 역직렬화 후 2개의 루트를 얻었습니다:
[<Cell 280[0351ED3B9E728E7C548B15A5E5CE988B4A74984C3F8374F3F1A52C7B1F46C264060016] -> 1 refs>, <Cell 280[0332BF3592969931CA4FBC7715494B50597F1884C0D847456029D8CF0E526E6046016F] -> 1 refs>]
첫 번째는 확인해야 할 마스터체인 블록 Merkle 증명입니다(check_block_header
함수 사용):
280[0351ED3B9E728E7C548B15A5E5CE988B4A74984C3F8374F3F1A52C7B1F46C264060016] -> {
64[11EF55AAFFFFFF11] -> {
640[9BC7A98700000000040101DC65010000000100FFFFFFFF000000000000000064B6C356000023D38BA64000000023D38BA64004886D00960007028101DC64FD01DC42BEC400000003000000000000002E] -> {
608[000023D38B96FDC401DC650048A3971C46472B85C8D761060A6E7AE9F13A90CDDA815915A89597CFECB393A6B568807ADFB3C1C5EFC920907225175DB61CA384E4F8B313799E3CBB8B7B4085]
},
288[01018C6053C1185700C0FE4311D5CF8FA533EA0382E361A7B76D0CF299B75AC0356C0003],
552[0478E0F0E601BA1161ECC1395E9A0475C4F80AADBD6C483F210E96E29CF36789E432BF3592969931CA4FBC7715494B50597F1884C0D847456029D8CF0E526E6046016F016F] -> {
560[010378E0F0E601BA1161ECC1395E9A0475C4F80AADBD6C483F210E96E29CF36789E46492304DFB6EF9149781871464AF686056A9627F882F60E3B24F8C944A75EBAF016F0014],
560[010332BF3592969931CA4FBC7715494B50597F1884C0D847456029D8CF0E526E6046DA58493CCB5DA3876129B0190F3C375E69E59C3AD9FF550BE708999DAD1F6F39016F0014]
},
288[01015720B6AEFCBF406209522895FAA6C0D10CC3315D90BCAF09791B19F595E86F8F0007]
}
}
셀
552[0478E0F0E601BA1161ECC1395E9A0475C4F80AADBD6C483F210E96E29CF36789E432BF3592969931CA4FBC7715494B50597F1884C0D847456029D8CF0E526E6046016F016F] -> {
560[010378E0F0E601BA1161ECC1395E9A0475C4F80AADBD6C483F210E96E29CF36789E46492304DFB6EF9149781871464AF686056A9627F882F60E3B24F8C944A75EBAF016F0014],
560[010332BF3592969931CA4FBC7715494B50597F1884C0D847456029D8CF0E526E6046DA58493CCB5DA3876129B0190F3C375E69E59C3AD9FF550BE708999DAD1F6F39016F0014]
}
이것은 ShardState TLB 스키마의 Merkle 업데이트이므로 새 해시를 기억해야 합니다.
우리가 알고 있는 블록 해시와 일치하는 유일한 Merkle Proof Cell 참조 Hash_1을 확인하고, 새로운 ShardState 해시를 기억한 후 두 번째 shard proof
Cell을 확인합니다:
280[0332BF3592969931CA4FBC7715494B50597F1884C0D847456029D8CF0E526E6046016F] -> {
362[9023AFE2FFFFFF1100FFFFFFFF000000000000000001DC65010000000164B6C356000023D38BA6400401DC64FD40] -> {
288[0101AFFE84CDD73951BCE07EEAAD120D00400295220D6F66F1163B5FA8668202D72B0001],
288[0101FAED0DD3CA110ADA3D22980E3795D2BDF15450E9159892BBF330CDFD13A3B880016E],
204[0000000000000000FFFFFFFFFFFFFFFF820CE9D9C3929379C820] -> {
288[0101A5A7D24057D8643B2527709D986CDA3846ADCB3EDDC32D28EC21F69E17DBAAEF0001],
288[0101DEAB5A5AAF79C5E24F8DCBBE51747D6804104F75F58ED5BED4702C353545C6AC0011]
},
342[CC26AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC23519B11EDDC69B7C] -> {
9[D000] -> {
878[50119963380EE3280800011E9C5CB7EE0000011E9C5CB7EE29CF2E5E52DFB4BA85AECC4BC3961D06BD1F30A7290E29F26F3947D7F69C6E713F8F872E6E25C50967921C6E55B07A38968EE0279BC958EB97928065FB204A45B88000381ABC00000000000000000EE327EB25B61A88] -> {
74[43C9B67A721DCD650000]
}
},
288[01015394592E3A3F1E3BC2D4249E993D0EC1E33CA18F49533991274EBC65276CD9A50011],
766[0001AAA0161D000702816000047A7172DFB88800011E8B625908200EE215F71061846393A08C682E87BC3A12AFF2D246EB97A09164F5657F96F9A252EF71580FE5309A823F73F3C4C3F8AB73F5A85BBF204BFD22E68D36D0EFAB1818E7B428BC] -> {
288[010150FCC05BD9723571B83316A5F650BE31EDB131D05FDC78D271486E5D4EF077E10019],
288[0101E5BE728200B172CF7E2356CBA2AE1C6E2C790BE7C03CD7814C6E6FE3080B944B0011]
},
288[0101B20E36A3B36A4CDEE601106C642E90718B0A58DAF200753DBB3189F956B494B60001]
}
}
}
보시다시피 유일한 Merkle Proof 참조는 9023AFE2
접두사를 가지고 있는데, 이는 ShardStateUnsplit TLB 스키마 접두사입니다. 따라서 이 참조의 Hash_1을 이전 단계에서 기억한 것과 비교해야 합니다:
"""
Here mc_block_cell is a first shard proof root and mc_state_root is the second one.
The check_block_header_proof function returns new hash of the ShardState Merkle Update.
"""
mc_state_hash = mc_state_root[0].get_hash(0)
state_hash = check_block_header_proof(mc_block_cell[0], blk.root_hash, True)
if mc_state_hash != state_hash:
raise ProofError('mc state hashes mismatch')
- 왜? - 블록 헤더 증명을 확인했기 때문에 다른 Cell 데이터를 신뢰할 수 있습니다. 따라서 이제 ShardState Merkle 업데이트의 새 해시를 신뢰하며, 두 번째 Cell 데이터를 신뢰하기 위해서는 해시가 일치하는지 확인해야 합니다.
이제 두 번째 Cell을 역직렬화해보겠습니다:
{
'global_id': -239,
'shard_id': {'shard_pfx_bits': 0, 'workchain_id': -1, 'shard_prefix': 0},
'seq_no': 31220993,
'vert_seq_no': 1,
'gen_utime': 1689699158,
'gen_lt': 39391488000004,
'min_ref_mc_seqno': 31220989,
'out_msg_queue_info': <Cell 288[0101AFFE84CDD73951BCE07EEAAD120D00400295220D6F66F1163B5FA8668202D72B0001] -> 0 refs>,
'before_split': 0,
'accounts': <Cell 288[0101FAED0DD3CA110ADA3D22980E3795D2BDF15450E9159892BBF330CDFD13A3B880016E] -> 0 refs>,
'overload_history': 0,
'underload_history': 18446744073709551615,
'total_balance': {'grams': 2364000148715550620, 'other': None},
'total_validator_fees': {'grams': 0, 'other': None},
'libraries': None,
'master_ref': None,
'custom': {
'shard_hashes': {
0: {'list': [{
'seq_no': 36908135,
'reg_mc_seqno': 31220993,
'start_lt': 39391487000000,
'end_lt': 39391487000005,
'root_hash': b"9\xe5\xcb\xca[\xf6\x97P\xb5\xd9\x89xr\xc3\xa0\xd7\xa3\xe6\x14\xe5!\xc5>M\xe7(\xfa\xfe\xd3\x8d\xce'",
'file_hash': b'\xf1\xf0\xe5\xcd\xc4\xb8\xa1,\xf2C\x8d\xca\xb6\x0fG\x12\xd1\xdc\x04\xf3y+\x1dr\xf2P\x0c\xbfd\tH\xb7',
'before_split': False,
'before_merge': False,
'want_split': False,
'want_merge': True,
'nx_cc_updated': False,
'flags': 0,
'next_catchain_seqno': 459607,
'next_validator_shard': 9223372036854775808,
'min_ref_mc_seqno': 31220989,
'gen_utime': 1689699153,
'split_merge_at': None,
'fees_collected': {'grams': 1016817575, 'other': None}, 'funds_created': {'grams': 1000000000, 'other': None}
}]
}
},
'config': {'config_addr': '5555555555555555555555555555555555555555555555555555555555555555', 'config': None},
'flags': 1,
'validator_info': {'validator_list_hash_short': 2862618141, 'catchain_seqno': 459393, 'nx_cc_updated': False},
'prev_blocks': None,
'after_key_block': True,
'last_key_block': {'end_lt': 39382372000004, 'seqno': 31212222, 'root_hash': b'\xe2\x0c0\x8crt\x11\x8d\x05\xd0\xf7\x87BU\xfeZH\xddr\xf4\x12,\x9e\xac\xaf\xf2\xdf4J]\xee+', 'file_hash': b'\x01\xfc\xa6\x13PG\xee~x\x98\x7f\x15n~\xb5\x0bw\xe4\t\x7f\xa4\\\xd1\xa6\xda\x1d\xf5c\x03\x1c\xf6\x85'},
'block_create_stats': {'type_': 'block_create_stats', 'counters': None},
'global_balance': {'grams': 5089971531496870767, 'other': None}
}
}
이 Cell을 신뢰할 수 있으므로 샤드 블록 데이터도 신뢰할 수 있습니다(ShardStateUnsplit
-> custom
-> shard_hashes
-> 0 (shrdblk wc)
-> leaf
).
계정 상태
문서 시작 부분에서 언급한 동일한 마스터체인 블록에 대해 계정 EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG
의 상태를 증명해보겠습니다.
Liteserver 응답은 마스터체인 블 록 id (ls에 보낸 것과 동일해야 함), 샤드 블록 id와 위에서 설명한 대로 확인해야 할 shard_proof
boc,
proof
boc, 그리고 state
boc을 포함합니다.
Show bocs
Proof boc:
b5ee9c7201023d020008480100094603f93fe5eda41a6ce9ecb353fd589842bd3f5d5e73b846cb898525293fc742fd6902190209460339e5cbca5bf69750b5d9897872c3a0d7a3e614e521c53e4de728fafed38dce27001d34235b9023afe2ffffff110000000000000000000000000002332c670000000164b6c351000023d38b96fdc501dc64fd200304052848010138f8d1c6e9f798a477d13aa26cb4d6cfe1a17949ac276b2f1e0ce037a521b9bc0001221382097522af06ffaff1f0063321d90000000000000000ffffffffffffffff825d48abc1bfebfc7bc2df8993c189361000023d38b69370401dc64fd2fa78ec529bcf9931e14f9d8b27ec1469290c0baef8256d657ce573b9679c5997431fcda6bf2d0be39344a9336cfe0ae9c844a88d2bd8022102e4012a760d4db83323130104ba9157837fd7f8f8070833231301032030fdc45f2d3838090a0b284801013e38e2548c5236a9652c45e553ced677f76550097b94138a4576f122443944d400692848010159e1a18ee4e5670306b5203912c87dffc17898f0999bd128a6965027d53b6fa40215231301013fa38088aaea2b780c0d10284801016f315f25b4a39ac12c85fea4ecfe7a83e5e59d1f059783fa0c3ef2797308806100002848010188d5f8a73382aea73dede03fc3bcda2634a717ef50e7428d5a4a44c771b014b90066231301005ecd9e51e5d22a380e0f1023130100303b3b607d7ffc781112132848010182eb0e24c842092ec2705486cbbe98de8016d55f5cff4ea910471a4c3a7a1cf1003b28480101ed7e26bd36efa6d5d9b4f6aaab9813af0742a84244977f74fd4074c9c98908be000028480101ca85960e3fc3dfb6d26e83ae87a837ae5c2faf7c8d43ea177393c602fadaa0300039221100e0f41ada252e2f08141528480101d7acbb602338c86d610f35cfb362fd76fc18b1812476b6fca99a0678e665fcf50000284801014fae109c41f3d5e2be0a3ff00a007f2e50a796797700d18a7aa663e531c37180002d221100e05c33225b78bce8161728480101545b5925b3ab2a8df2470fe22a5a3c9cc64e3cb24407c26167e0fbb476e05309002c221100e03480847f372168181928480101844a14c99695506e920635d18e76d9e685adee74e5fba6f6d3b371ca77e348130029220f00d0b1cce62aecc81a1b220f00c625c7e90dfc681c1d284801019ca2157c92d49b9d051388de45d07072c78a3aa65a5b05547d94e0369aa6bdee002a284801010326812b62712345473070d679bc38cdbbce58b7a2bf6c5c6f091fc8d36e81cd001f220f00c279d628dbf2081e1f220f00c0b8f29f9d04e82021284801019143abf2a72662054eda4f4949d010c897aff4383b514b387cff790408231c6c001a28480101de5072f46a0e0ecab2bbfc2cfc62a3fe200f12d5d457df833a46eb747fa004e30059220f00c03fa2ec9ad848222328480101baee90fd11a130d6d2e2ded21ae4a7b86553116015b7e7ebfc52369534d298b20017220f00c02e722bded7282425220d00ab138e7f18482627284801017f1df311101e472b1d443334d2426fd339539f558694c60e3428221dcb1a5478001628480101e1fc242c29e519f9740ca2570d85779aed0c593cc36b59119852945988e186960015220d00a21324d3ff2828292848010199fe288fdce2606d39f9b6af72f9c2643ef06e6bacc15dd72cfa84d63c9e44a40013220d00a1e877ec8ba82a2b284801019e019e92be76a5ae7aee239299f561682afbe445dc42ee57ccc31ecb427fdf42000e220d00a1db848431a82c2d284801012345b80e66c025fb62c41261b5d230616303ec47f3bb7a255872fada62a1e8bf0010220d00a1d633bc10682e2f220d00a02ca3ddc468303128480101654781e5d466ec4ca50cb2983b20170bb5d90e2e6ab83ed7d42a829651a5eec1000a219abb19e61b8190c2587677c010ce49a93364b965f7762a9810d916b082f45e080a02bc35ebaa649b46ac72e6e4d4c1293b66d58d9ed7a54902beefd97f5bff7977dd85998b3d000023c5643934413228480101edced2278013ea497dd2e286f495b4f7f8df6ea73e08e85414fc43a611c17797000b284801018282d13bf66b9ace1fbf5d3abd1c59cc46d61af1d47af1665d3013d8f9e47488000828480101b3e9649d10ccb379368e81a3a7e8e49c8eb53f6acc69b0ba2ffa80082f70ee390001241011ef55aaffffff113536373802a09bc7a98700000000840102332c67000000010000000000000000000000000064b6c351000023d38b96fdc0000023d38b96fdc5d41c6e3c0007035701dc64fd01dc42bec400000003000000000000002e393a28480101cb54530ac857df730e82ee239b2150528c6e5f6ed3678eab6e1e789f0e3c7a5300032a8a04f2ad1ede336a68623ddabf36cb8fa405dbe70a38c453f711000f9a9f92592db0f93fe5eda41a6ce9ecb353fd589842bd3f5d5e73b846cb898525293fc742fd69021902193b3c28480101d0cf03a1058c2fd6029288951051a0d82733953c1e9181a67c502ce59b180200000b0098000023d38b69370401dc64fd2fa78ec529bcf9931e14f9d8b27ec1469290c0baef8256d657ce573b9679c5997431fcda6bf2d0be39344a9336cfe0ae9c844a88d2bd8022102e4012a760d4db0098000023d38b87bb8402332c662b4e96320f9d0afb02e5d55b6b42c3349e33540620ecc07b399211fd56e4de3e2555617cdde457cd65a0ad033aafc0c6c25df716b04e455f49179668a46300db688c0103f2ad1ede336a68623ddabf36cb8fa405dbe70a38c453f711000f9a9f92592db04a4ff9713b206e420baaee4dd21febbeb426fcd9ce158db2a56dce9188fc313e0219001b688c0103f93fe5eda41a6ce9ecb353fd589842bd3f5d5e73b846cb898525293fc742fd6987d796744ca386906016c56921370d01f72cb004a1d7c294752afe4446da07bb0219001b
State boc:
b5ee9c720102160100033c000271c006f5bc67986e06430961d9df00433926a4cd92e597ddd8aa6043645ac20bd178222c859043259e0d9000008f1590e4d10d405786bd75534001020114ff00f4a413f4bcf2c80b030051000000e929a9a317c1b3226ce226d6d818bafe82d3633aa0f06a6c677272d1f9b760ff0d0dcf56d8400201200405020148060704f8f28308d71820d31fd31fd31f02f823bbf264ed44d0d31fd31fd3fff404d15143baf2a15151baf2a205f901541064f910f2a3f80024a4c8cb1f5240cb1f5230cbff5210f400c9ed54f80f01d30721c0009f6c519320d74a96d307d402fb00e830e021c001e30021c002e30001c0039130e30d03a4c8cb1f12cb1fcbff1213141502e6d001d0d3032171b0925f04e022d749c120925f04e002d31f218210706c7567bd22821064737472bdb0925f05e003fa403020fa4401c8ca07cbffc9d0ed44d0810140d721f404305c810108f40a6fa131b3925f07e005d33fc8258210706c7567ba923830e30d03821064737472ba925f06e30d08090201200a0b007801fa00f40430f8276f2230500aa121bef2e0508210706c7567831eb17080185004cb0526cf1658fa0219f400cb6917cb1f5260cb3f20c98040fb0006008a5004810108f45930ed44d0810140d720c801cf16f400c9ed540172b08e23821064737472831eb17080185005cb055003cf1623fa0213cb6acb1fcb3fc98040fb00925f03e20201200c0d0059bd242b6f6a2684080a06b90fa0218470d4080847a4937d29910ce6903e9ff9837812801b7810148987159f31840201580e0f0011b8c97ed44d0d70b1f8003db29dfb513420405035c87d010c00b23281f2fff274006040423d029be84c6002012010110019adce76a26840206b90eb85ffc00019af1df6a26840106b90eb858fc0006ed207fa00d4d422f90005c8ca0715cbffc9d077748018c8cb05cb0222cf165005fa0214cb6b12ccccc973fb00c84014810108f451f2a7020070810108d718fa00d33fc8542047810108f451f2a782106e6f746570748018c8cb05cb025006cf165004fa0214cb6a12cb1fcb3fc973fb0002006c810108d718fa00d33f305224810108f459f2a782106473747270748018c8cb05cb025005cf165003fa0213cb6acb1f12cb3fc973fb00000af400c9ed54
샤드 증명
을 확인한 후, proof
와 state
셀을 모두 역직렬화해야 합니다. 먼저 증명 셀은 정확히 2개의 루트를 가져야 합니다:
[<Cell 280[0339E5CBCA5BF69750B5D9897872C3A0D7A3E614E521C53E4DE728FAFED38DCE27001D] -> 1 refs>, <Cell 280[03F93FE5EDA41A6CE9ECB353FD589842BD3F5D5E73B846CB898525293FC742FD690219] -> 1 refs>]
첫 번째 루트는 샤드 블록에 대한 Merkle 증명입니다(이미 해시를 증명하고 신뢰함):
280[0339E5CBCA5BF69750B5D9897872C3A0D7A3E614E521C53E4DE728FAFED38DCE27001D] -> {
64[11EF55AAFFFFFF11] -> {
640[9BC7A98700000000840102332C67000000010000000000000000000000000064B6C351000023D38B96FDC0000023D38B96FDC5D41C6E3C0007035701DC64FD01DC42BEC400000003000000000000002E] -> {
608[000023D38B69370401DC64FD2FA78EC529BCF9931E14F9D8B27EC1469290C0BAEF8256D657CE573B9679C5997431FCDA6BF2D0BE39344A9336CFE0AE9C844A88D2BD8022102E4012A760D4DB],
608[000023D38B87BB8402332C662B4E96320F9D0AFB02E5D55B6B42C3349E33540620ECC07B399211FD56E4DE3E2555617CDDE457CD65A0AD033AAFC0C6C25DF716B04E455F49179668A46300DB]
},
288[0101CB54530AC857DF730E82EE239B2150528C6E5F6ED3678EAB6E1E789F0E3C7A530003],
552[04F2AD1EDE336A68623DDABF36CB8FA405DBE70A38C453F711000F9A9F92592DB0F93FE5EDA41A6CE9ECB353FD589842BD3F5D5E73B846CB898525293FC742FD6902190219] -> {
560[0103F2AD1EDE336A68623DDABF36CB8FA405DBE70A38C453F711000F9A9F92592DB04A4FF9713B206E420BAAEE4DD21FEBBEB426FCD9CE158DB2A56DCE9188FC313E0219001B],
560[0103F93FE5EDA41A6CE9ECB353FD589842BD3F5D5E73B846CB898525293FC742FD6987D796744CA386906016C56921370D01F72CB004A1D7C294752AFE4446DA07BB0219001B]
},
288[0101D0CF03A1058C2FD6029288951051A0D82733953C1E9181A67C502CE59B180200000B]
}
}
샤드 증명
검증에서 했던 것처럼 check_block_header
함수를 사용해야 합니다: Block Cell이 유효한지 확인하고 새로운 StateUpdate
해시를 기억합니다.
그런 다음 두 번째 루트(state_cell이라고 하자)를 역직렬화하고 Hash_1이 기억한 해시와 일치하는지 확인합니다:
proof_cells = Cell.from_boc(proof)
if len(proof_cells) != 2:
raise ProofError('expected 2 root cells in account state proof')
state_cell = proof_cells[1]
state_hash = check_block_header_proof(proof_cells[0][0], shrd_blk.root_hash, True)
if state_cell[0].get_hash(0) != state_hash:
raise ProofError('state hashes mismatch')
이제 다음과 같이 생긴 state_cell
을 신뢰할 수 있습니다:
Show Cell
280[03F93FE5EDA41A6CE9ECB353FD589842BD3F5D5E73B846CB898525293FC742FD690219] -> {
362[9023AFE2FFFFFF110000000000000000000000000002332C670000000164B6C351000023D38B96FDC501DC64FD00] -> {
288[010138F8D1C6E9F798A477D13AA26CB4D6CFE1A17949AC276B2F1E0CE037A521B9BC0001],
75[82097522AF06FFAFF1E0] -> {
76[0104BA9157837FD7F8F0] -> {
76[01032030FDC45F2D3830] -> {
288[010159E1A18EE4E5670306B5203912C87DFFC17898F0999BD128A6965027D53B6FA40215],
76[01013FA38088AAEA2B70] -> {
288[010188D5F8A73382AEA73DEDE03FC3BCDA2634A717EF50E7428D5A4A44C771B014B90066],
76[01005ECD9E51E5D22A30] -> {
76[0100303B3B607D7FFC70] -> {
288[0101CA85960E3FC3DFB6D26E83AE87A837AE5C2FAF7C8D43EA177393C602FADAA0300039],
68[00E0F41ADA252E2F00] -> {
288[01014FAE109C41F3D5E2BE0A3FF00A007F2E50A796797700D18A7AA663E531C37180002D],
68[00E05C33225B78BCE0] -> {
288[0101545B5925B3AB2A8DF2470FE22A5A3C9CC64E3CB24407C26167E0FBB476E05309002C],
68[00E03480847F372160] -> {
288[0101844A14C99695506E920635D18E76D9E685ADEE74E5FBA6F6D3B371CA77E348130029],
60[00D0B1CCE62AECC0] -> {
60[00C625C7E90DFC60] -> {
288[01010326812B62712345473070D679BC38CDBBCE58B7A2BF6C5C6F091FC8D36E81CD001F],
60[00C279D628DBF200] -> {
60[00C0B8F29F9D04E0] -> {
288[0101DE5072F46A0E0ECAB2BBFC2CFC62A3FE200F12D5D457DF833A46EB747FA004E30059],
60[00C03FA2EC9AD840] -> {
288[0101BAEE90FD11A130D6D2E2DED21AE4A7B86553116015B7E7EBFC52369534D298B20017],
60[00C02E722BDED720] -> {
52[00AB138E7F1840] -> {
288[0101E1FC242C29E519F9740CA2570D85779AED0C593CC36B59119852945988E186960015],
52[00A21324D3FF20] -> {
288[010199FE288FDCE2606D39F9B6AF72F9C2643EF06E6BACC15DD72CFA84D63C9E44A40013],
52[00A1E877EC8BA0] -> {
288[01019E019E92BE76A5AE7AEE239299F561682AFBE445DC42EE57CCC31ECB427FDF42000E],
52[00A1DB848431A0] -> {
288[01012345B80E66C025FB62C41261B5D230616303EC47F3BB7A255872FADA62A1E8BF0010],
52[00A1D633BC1060] -> {
52[00A02CA3DDC460] -> {
616[BB19E61B8190C2587677C010CE49A93364B965F7762A9810D916B082F45E080A02BC35EBAA649B46AC72E6E4D4C1293B66D58D9ED7A54902BEEFD97F5BFF7977DD85998B3D000023C564393441] -> {
288[01018282D13BF66B9ACE1FBF5D3ABD1C59CC46D61AF1D47AF1665D3013D8F9E474880008]
},
288[0101EDCED2278013EA497DD2E286F495B4F7F8DF6EA73E08E85414FC43A611C17797000B]
},
288[0101654781E5D466EC4CA50CB2983B20170BB5D90E2E6AB83ED7D42A829651A5EEC1000A]
}
}
}
}
},
288[01017F1DF311101E472B1D443334D2426FD339539F558694C60E3428221DCB1A54780016]
}
}
},
288[01019143ABF2A72662054EDA4F4949D010C897AFF4383B514B387CFF790408231C6C001A]
}
},
288[01019CA2157C92D49B9D051388DE45D07072C78A3AA65A5B05547D94E0369AA6BDEE002A]
}
}
}
},
288[0101D7ACBB602338C86D610F35CFB362FD76FC18B1812476B6FCA99A0678E665FCF50000]
},
288[010182EB0E24C842092EC2705486CBBE98DE8016D55F5CFF4EA910471A4C3A7A1CF1003B],
288[0101ED7E26BD36EFA6D5D9B4F6AAAB9813AF0742A84244977F74FD4074C9C98908BE0000]
},
288[0101ED7E26BD36EFA6D5D9B4F6AAAB9813AF0742A84244977F74FD4074C9C98908BE0000]
},
288[01016F315F25B4A39AC12C85FEA4ECFE7A83E5E59D1F059783FA0C3EF279730880610000]
},
288[01013E38E2548C5236A9652C45E553CED677F76550097B94138A4576F122443944D40069],
288[0101B3E9649D10CCB379368E81A3A7E8E49C8EB53F6ACC69B0BA2FFA80082F70EE390001]
},
288[0101B3E9649D10CCB379368E81A3A7E8E49C8EB53F6ACC69B0BA2FFA80082F70EE390001]
},
868[0000000000000000FFFFFFFFFFFFFFFF825D48ABC1BFEBFC7BC2DF8993C189361000023D38B69370401DC64FD2FA78EC529BCF9931E14F9D8B27EC1469290C0BAEF8256D657CE573B9679C5997431FCDA6BF2D0BE39344A9336CFE0AE9C844A88D2BD8022102E4012A760D4DB0] -> {
288[0101B3E9649D10CCB379368E81A3A7E8E49C8EB53F6ACC69B0BA2FFA80082F70EE390001]
}
}
}
다시 말하지만 유일한 Merkle Proof 참조는 ShardStateUnsplit TLB 스키마 접두사인 9023AFE2
를 가지고 있으므로, TLB 스키마에 따라 역직렬화하겠습니다:
{
'global_id': -239,
'shard_id': {'shard_pfx_bits': 0, 'workchain_id': 0, 'shard_prefix': 0},
'seq_no': 36908135,
'vert_seq_no': 1,
'gen_utime': 1689699153,
'gen_lt': 39391487000005,
'min_ref_mc_seqno': 31220989,
'out_msg_queue_info': <Cell 288[010138F8D1C6E9F798A477D13AA26CB4D6CFE1A17949AC276B2F1E0CE037A521B9BC0001] -> 0 refs>,
'before_split': 0,
'accounts': (
{
50368879097771769677871174881221998657607998794347754829932074327482686052226: {
'account': None,
'last_trans_hash': b'd\x9bF\xacr\xe6\xe4\xd4\xc1);f\xd5\x8d\x9e\xd7\xa5I\x02\xbe\xef\xd9\x7f[\xffyw\xdd\x85\x99\x8b=',
'last_trans_lt': 39330697000001,
'cell': <Cell 320[649B46AC72E6E4D4C1293B66D58D9ED7A54902BEEFD97F5BFF7977DD85998B3D000023C564393441] -> 1 refs>
}
},
[
{'split_depth': 0, 'balance': {'grams': 5873792469, 'other': None}},
{'split_depth': 0, 'balance': {'grams': 5991493155, 'other': None}},
{'split_depth': 0, 'balance': {'grams': 63109456003, 'other': None}},
{'split_depth': 0, 'balance': {'grams': 63822897549, 'other': None}},
...
{'split_depth': 0, 'balance': {'grams': 21778458402704, 'other': None}},
{'split_depth': 0, 'balance': {'grams': 54074699968483, 'other': None}},
{'split_depth': 0, 'balance': {'grams': 2725956214994157511, 'other': None}}
]
),
'overload_history': 0,
'underload_history': 18446744073709551615,
'total_balance': {'grams': 2725956214994157511, 'other': None},
'total_validator_fees': {'grams': 37646260890702444, 'other': None},
'libraries': None,
'master_ref': {'master': {'end_lt': 39391484000004, 'seqno': 31220989, 'root_hash': b'/\xa7\x8e\xc5)\xbc\xf9\x93\x1e\x14\xf9\xd8\xb2~\xc1F\x92\x90\xc0\xba\xef\x82V\xd6W\xceW;\x96y\xc5\x99', 'file_hash': b't1\xfc\xdak\xf2\xd0\xbe94J\x936\xcf\xe0\xae\x9c\x84J\x88\xd2\xbd\x80"\x10.@\x12\xa7`\xd4\xdb'}},
'custom': None
}
여기서는 ShardAccounts 타입을 가진 account
필드가 필요합니다.
ShardAccounts
는 키가 주소 hash_part이고, 값이 ShardAccount
타입이며 extra가 DeepBalanceInfo
타입인 HashmapAugE입니다.
주소 EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG
를 파싱하면 hash_part가 50368879097771769677871174881221998657607998794347754829932074327482686052226
과 같으므로, 이 키의 값을 해시맵에서 가져와야 합니다:
{
50368879097771769677871174881221998657607998794347754829932074327482686052226: {
'account': None,
'last_trans_hash': b'd\x9bF\xacr\xe6\xe4\xd4\xc1);f\xd5\x8d\x9e\xd7\xa5I\x02\xbe\xef\xd9\x7f[\xffyw\xdd\x85\x99\x8b=',
'last_trans_lt': 39330697000001,
'cell': <Cell 320[649B46AC72E6E4D4C1293B66D58D9ED7A54902BEEFD97F5BFF7977DD85998B3D000023C564393441] -> 1 refs>
}
}
계정 트랜잭션을 가져오는 데 사용할 수 있으므로 last_trans_hash
와 last_trans_lt
를 기억해야 하고 이 데이터의 전체 Cell을 확인해보겠습니다:
320[649B46AC72E6E4D4C1293B66D58D9ED7A54902BEEFD97F5BFF7977DD85998B3D000023C564393441] -> {
288[01018282D13BF66B9ACE1FBF5D3ABD1C59CC46D61AF1D47AF1665D3013D8F9E474880008]
}
보시다시피 Cell은 레벨 1의 일반 Cell이며 가지치기된 계정 데이터인 참조를 하나만 가지고 있으므로, 이 가지치기된 브랜치의 Hash_1을 계산해보겠습니다 -
이것이 우리가 신뢰할 수 있는 계정 상태 해시입니다: 8282d13bf66b9ace1fbf5d3abd1c59cc46d61af1d47af1665d3013d8f9e47488
.
이제 마지막 단계를 시작하면 state
boc을 역직렬화합니다:
449[C006F5BC67986E06430961D9DF00433926A4CD92E597DDD8AA6043645AC20BD178222C859043259E0D9000008F1590E4D10D405786BD755300] -> {
80[FF00F4A413F4BCF2C80B] -> {
2[00] -> {
4[40] -> {
920[D001D0D3032171B0925F04E022D749C120925F04E002D31F218210706C7567BD22821064737472BDB0925F05E003FA403020FA4401C8CA07CBFFC9D0ED44D0810140D721F404305C810108F40A6FA131B3925F07E005D33FC8258210706C7567BA923830E30D03821064737472BA925F06E30D] -> {
480[01FA00F40430F8276F2230500AA121BEF2E0508210706C7567831EB17080185004CB0526CF1658FA0219F400CB6917CB1F5260CB3F20C98040FB0006],
552[5004810108F45930ED44D0810140D720C801CF16F400C9ED540172B08E23821064737472831EB17080185005CB055003CF1623FA0213CB6ACB1FCB3FC98040FB00925F03E2]
},
2[00] -> {
2[00] -> {
4[50] -> {
242[B29DFB513420405035C87D010C00B23281F2FFF274006040423D029BE84C40],
2[00] -> {
97[ADCE76A26840206B90EB85FF80],
97[AF1DF6A26840106B90EB858F80]
}
},
68[B8C97ED44D0D70B1F0]
},
357[BD242B6F6A2684080A06B90FA0218470D4080847A4937D29910CE6903E9FF9837812801B7810148987159F3180]
}
},
992[F28308D71820D31FD31FD31F02F823BBF264ED44D0D31FD31FD3FFF404D15143BAF2A15151BAF2A205F901541064F910F2A3F80024A4C8CB1F5240CB1F5230CBFF5210F400C9ED54F80F01D30721C0009F6C519320D74A96D307D402FB00E830E021C001E30021C002E30001C0039130E30D03A4C8CB1F12CB1FCBFF] -> {
440[D207FA00D4D422F90005C8CA0715CBFFC9D077748018C8CB05CB0222CF165005FA0214CB6B12CCCCC973FB00C84014810108F451F2A702],
448[810108D718FA00D33FC8542047810108F451F2A782106E6F746570748018C8CB05CB025006CF165004FA0214CB6A12CB1FCB3FC973FB0002],
432[810108D718FA00D33F305224810108F459F2A782106473747270748018C8CB05CB025005CF165003FA0213CB6ACB1F12CB3FC973FB00],
40[F400C9ED54]
}
}
},
321[000000E929A9A317C1B3226CE226D6D818BAFE82D3633AA0F06A6C677272D1F9B760FF0D0DCF56D800]
}
그 표현 해시를 계산하고 가지치기에서 얻은 것과 일치하는지 확인합니다: 8282d13bf66b9ace1fbf5d3abd1c59cc46d61af1d47af1665d3013d8f9e47488
.
그리고 Account TLB 스키마에 따라 역직렬화합니다:
{
'addr': Address<EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG>,
'storage_stat': {'used': {'cells': 22, 'bits': 5697, 'public_cells': None}, 'last_paid': 1689502130, 'due_payment': None},
'storage': {
'last_trans_lt': 39330697000003,
'balance': {'grams': 5873792469, 'other': None},
'state': {
'type_': 'account_active',
'state_init': {'split_depth': None, 'special': None, 'code': <Cell 80[FF00F4A413F4BCF2C80B] -> 1 refs>, 'data': <Cell 321[000000E929A9A317C1B3226CE226D6D818BAFE82D3633AA0F06A6C677272D1F9B760FF0D0DCF56D800] -> 0 refs>, 'library': None}
}
}
}
이제 이 계정 상태 데이터를 신뢰할 수 있습니다.
계정 트랜잭션
liteServer.getTransactions 요청을 위해서는 시작할 트랜잭션의 lt
와 hash
를 제공해야 합니다.
마지막 계정 트랜잭션을 가져오려면 ShardAccount
(위에서 설명)에서 가져올 수 있으며 이러한 lt
와 hash
를 신뢰할 수 있습니다.
Liteserver로부터 트랜잭션을 받을 때 요청한 트랜잭션 수만큼의 루트를 가진 boc을 받습니다. 각 루트는 Transaction TLB 스키마에 따라 역직렬화해야 하는 Cell입니다.
첫 번째 트랜잭션 셀의 경우 해시가 계정 상태에서 얻은 last_trans_hash
와 일치하는지 확인해야 합니다. 그런 다음 prev_trans_hash
필드의 값을 기억하고 두 번째 루트의 해시와 비교하는 식으로 진행합니다.