본문으로 건너뛰기

TON의 딕셔너리

스마트 컨트랙트는 딕셔너리(순서가 있는 키-값 매핑)를 사용할 수 있습니다. 내부적으로 셀 트리로 표현됩니다.

경고

Working with potentially large trees of cells creates a couple of considerations:

  1. 모든 업데이트 작업은 상당한 양의 셀을 생성합니다(생성된 각 셀은 500 가스가 소비됨, TVM 명령어 참조). 즉, 주의 없이 사용하면 가스가 부족할 수 있습니다.
    • 특히, Wallet 봇이 highload-v2 월렛 사용 시 이러한 문제를 겪었습니다. 무한 루프와 각 반복의 비싼 딕셔너리 업데이트가 결합되어 가스가 소진되었고, 결국 fd78228f352f582a544ab7ad7eb716610668b23b88dae48e4f4dbd4404b5d7f6와 같은 반복 트랜잭션으로 잔액이 소진되었습니다.
  2. N개의 키-값 쌍을 위한 이진 트리는 N-1개의 포크를 포함하므로, 총 최소 2N-1개의 셀이 필요합니다. 스마트 컨트랙트 저장소는 65536개의 고유 셀로 제한되어 있어, 딕셔너리의 최대 항목 수는 32768개이거나 반복되는 셀이 있는 경우 약간 더 많을 수 있습니다.

딕셔너리 종류

"해시"맵

TON에서 가장 잘 알려지고 사용되는 딕셔너리 종류는 해시맵입니다. TVM 명령어에서 전체 섹션을 차지하며(TVM 명령어 - 딕셔너리 조작) 스마트 컨트랙트에서 일반적으로 사용됩니다.

이러한 딕셔너리는 동일한 길이의 키(모든 함수에 인수로 제공)를 값 슬라이스에 매핑합니다. 이름의 "해시"와 달리, 항목들은 순서가 있고 키별 요소, 이전 또는 다음 키-값 쌍의 저렴한 추출을 제공합니다. 값은 내부 노드 태그와 가능한 키 부분과 같은 셀에 위치하므로 1023비트를 모두 사용할 수 없습니다; 이런 경우 일반적으로 ~udict_set_ref를 사용합니다.

빈 해시맵은 TVM에서 null로 표현됩니다; 따라서 셀이 아닙니다. 셀에 딕셔너리를 저장하려면, 먼저 1비트(비어있으면 0, 그렇지 않으면 1)를 저장하고, 해시맵이 비어있지 않은 경우 참조를 추가합니다. 따라서 store_maybe_refstore_dict는 서로 교환 가능하며, 일부 스마트 컨트랙트 작성자는 load_dict를 사용하여 수신 메시지나 저장소에서 Maybe ^Cell을 로드합니다.

해시맵에서 가능한 작업:

  • 슬라이스에서 로드, 빌더에 저장
  • 키별 값 get/set/delete
  • 값 교체(키가 이미 있는 경우 새 값 설정) / 추가(키가 없는 경우)
  • 키 순서대로 다음/이전 키-값 쌍으로 이동(가스 제한이 문제가 되지 않는 경우 딕셔너리 반복에 사용 가능)
  • 최소/최대 키와 해당 값 검색
  • 키로 함수(continuation) 가져와서 즉시 실행

가스 제한 초과로 인한 컨트랙트 중단을 방지하기 위해, 하나의 트랜잭션을 처리하는 동안 제한된 수의 딕셔너리 업데이트만 수행해야 합니다. 개발자의 조건에 따라 컨트랙트의 잔액이 맵을 유지하는 데 사용되는 경우, 컨트랙트는 정리를 계속하기 위해 자신에게 메시지를 보낼 수 있습니다.

정보

하위 딕셔너리(주어진 키 범위 내의 항목 하위 집합)를 검색하는 명령어가 있습니다. 이들은 테스트되지 않았으므로 TVM 어셈블리 형태로만 확인할 수 있습니다: SUBDICTGET 등.

해시맵 예제

257비트 정수 키를 빈 값 슬라이스에 매핑하는 해시맵(요소의 존재 여부만 표시)을 살펴보겠습니다.

Python에서 다음 스크립트를 실행하여 빠르게 확인할 수 있습니다(필요한 경우 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]
}
}
}

문서에 해시맵 파싱 예제가 더 있습니다.

보강된 맵 (각 노드에 추가 데이터 포함)

TON 검증자들이 샤드의 모든 컨트랙트 총 잔액을 계산하기 위해 내부적으로 사용됩니다(각 노드에 서브트리 총 잔액이 있는 맵을 사용하면 업데이트를 매우 빠르게 검증할 수 있음). 이를 위한 TVM 기본 요소는 없습니다.

접두사 딕셔너리

정보

테스트 결과 접두사 딕셔너리를 만들기 위한 문서가 충분하지 않습니다. PFXDICTSET 등의 관련 명령어가 어떻게 작동하는지 완전히 알지 못하는 한 프로덕션 컨트랙트에서 사용하지 않는 것이 좋습니다.