TON의 사전
스마트 콘트랙트는 정렬된 키-값 매핑인 딕셔너리를 사용할 수 있습니다. 이는 내부적으로 셀의 트리로 표현됩니다.
Working with potentially large trees of cells creates a couple of considerations:
- 모든 업데이트 작업은 상당한 양의 셀을 생성하므로(생성된 각 셀에는 500개의 가스가 소모되며, [TVM 지침](/학습/tvm-instruction/지침#가스 가격) 페이지에서 확인할 수 있음) 주의 없이 사용할 경우 가스가 부족해질 수 있습니다.
- 특히 월렛 봇은 하이로드-v2 지갑을 사용할 때 이러한 문제가 한 번 발생했습니다. 반복할 때마다 값비싼 사전 업데이트와 결합된 무한 루프 때문에 가스가 부족해졌고 결국 fd78228f352f582a544ab7ad7eb716610668b23b88dae48e4f4dbd4404b5d7f6 같은 거래가 반복되면서 잔액이 소모되었습니다.
- N개의 키-값 쌍에 대한 이진 트리에는 N-1개의 포크가 있으므로 총 2N-1개 이상의 셀이 포함됩니다. 스마트 컨트랙트 저장소는 65536개의 고유 셀로 제한되므로 사전의 최대 항목 수는 32768개 또는 반복되는 셀이 있는 경우 약간 더 많습니다. :::
사전 종류
"해시"지도
TON에서 가장 많이 알려져 있고 사용되는 사전은 해시맵입니다. 여기에는 전체 섹션에 해당하는 TVM 옵코드(TVM 지침 - 사전 조작)가 있으며, 스마트 컨트랙트에서 일반적으로 사용됩니다.
이러한 사전은 길이가 같은 키(모든 함수에 인자로 제공됨)를 값 조각에 매핑한 것입니다. 이름에서 '해시'와는 달리, 항목은 정렬되어 있으며 키, 이전 또는 다음 키-값 쌍별로 요소를 저렴하게 추출할 수 있습니다. 값은 내부 노드 태그 및 키 부분과 같은 셀에 배치되므로 1023비트를 모두 사용할 수 없으며, 이러한 상황에서는 ~udict_set_ref
가 일반적으로 사용됩니다.
빈 해시맵은 TVM에 의해 'null'로 표시되므로 셀이 아닙니다. 셀에 딕셔너리를 저장하려면 먼저 1비트(비어 있으면 0, 그렇지 않으면 1)를 저장한 다음 해시맵이 비어 있지 않으면 참조를 추가합니다. 따라서 store_maybe_ref
와 store_dict
는 상호 교환 가능하며, 일부 스마트 컨트랙트 작성자는 load_dict
를 사용하여 수신 메시지나 스토리지에서 Maybe ^Cell
을 로드합니다.
해시맵에 가능한 연산:
- 슬라이스, 스토어에서 빌더로 로드
- 키별 값 가져오기/설정/삭제
- 값 바꾸기(키가 이미 있는 경우 새 값 설정) / 키 추가(키가 없는 경우)
- 키 순서대로 다음/이전 키-값 쌍으로 이동합니다(가스 제한이 문제가 되지 않는 경우 사전 반복에 사용할 수 있습니다).
- 해당 값으로 최소/최대 키를 검색합니다.
- 키로 함수(연속)를 가져와 즉시 실행합니다.
가스 한도 초과로 컨트랙트가 깨지지 않으려면 하나의 트랜잭션을 처리하는 동안 제한된 수의 사전 업데이트만 수행해야 합니다. 개발자의 조건에 따라 컨트랙트의 잔액이 지도를 유지하는 데 사용되는 경우, 컨트랙트는 스스로 메시지를 보내 정리를 계속할 수 있습니다.
주어진 키 범위 내의 항목의 하위 집합인 하위 사전을 검색하는 방법이 있습니다. 아직 테스트되지 않았으므로 TVM 어셈블리 형태로만 확인할 수 있습니다: 서브딕트겟`과 유사합니다. :::
해시맵 예제
257비트 정수 키를 빈 값 조각에 매핑하는 것을 구체적으로 살펴보면서 해시맵이 어떻게 생겼는지 살펴보겠습니다(이러한 맵은 요소의 존재 여부만 표시합니다).
이를 빠르게 확인하는 방법은 파이썬에서 다음 스크립트를 실행하는 것입니다(pytoniq
를 다른 SDK로 적절히 대체할 수 있음):
import pytoniq
k = pytoniq.HashMap(257)
em = pytoniq.begin_cell().to_slice()
k.set(5, em)
k.set(7, em)
k.set(5 - 2**256, em)
k.set(6 - 2**256, em)
print(str(pytoniq.begin_cell().store_maybe_ref(k.serialize()).end_cell()))
구조는 이진 트리이며, 루트 셀을 간과하면 균형 잡힌 트리가 되기도 합니다.
1[80] -> {
2[00] -> {
265[9FC00000000000000000000000000000000000000000000000000000000000000080] -> {
4[50],
4[50]
},
266[9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40] -> {
2[00],
2[00]
}
}
}
문서에 [해시맵 구문 분석에 대한 추가 예제](/개발/데이터 형식/tl-b-types#해시맵 구문 분석 예제)가 있습니다.
증강 지도(각 노드에 추가 데이터 포함)
이러한 맵은 샤드에 있는 모든 컨트랙트의 총 잔액을 계산하기 위해 TON 검증자가 내부적으로 사용합니다(각 노드의 총 하위 트리 잔액이 있는 맵을 사용하면 업데이트를 매우 빠르게 검증할 수 있습니다). 이러한 작업을 위한 TVM 프리미티브는 없습니다.
접두사 사전
테스트 결과 접두사 사전을 만들기 위한 문서가 충분하지 않은 것으로 나타났습니다. 관련 옵코드인 PFXDICTSET
등의 작동 방식에 대한 완전한 지식이 없다면 제작 계약에 사용해서는 안 됩니다.