라이브러리 셀
소개
TON이 셀에 데이터를 저장하는 방식의 기본 기능 중 하나는 중복 제거입니다. 스토리지에서 메시지, 블록, 트랜잭션 등의 중복 셀은 한 번만 저장됩니다. 이를 통해 직렬화된 데이터의 크기가 크게 줄어들고 단계적으로 업데이트되는 데이터를 효율적으로 저장할 수 있습니다.
블록 구조는 메시지 큐, 트랜잭션 목록, 머클 업데이트 등 여러 곳에 각 메시지의 동일한 사본을 포함하고 있기 때문에 중복으로 인한 오버헤드가 없어 효율성에 대한 걱정 없이 필요한 곳에 데이터를 여러 번 저장할 수 있습니다.
라이브러리 셀은 온체인 중복 제거 메커니즘을 사용하여 이 기술을 맞춤형 스마트 컨트랙트에 통합할 수 있습니다.
:::정보
예를 들어 제튼월렛 코드를 라이브러리 셀(~20 셀, 6000 비트 대신 1 셀, 256+8 비트)로 저장하면 init_code
가 포함된 메시지의 전달 수수료가 0.011에서 0.003 TON으로 감소합니다.
:::
일반 정보
블록 1'000'000에서 블록 1'000'001까지의 베이스체인 단계를 살펴봅시다. 각 블록에는 소량의 데이터(일반적으로 1000개 미만의 트랜잭션)가 포함되어 있지만 전체 베이스체인 상태에는 수백만 개의 계정이 포함되어 있으며 블록체인은 데이터의 무결성을 유지해야 하므로(특히 전체 상태의 머클 루트 해시를 블록에 커밋하려면) 상태의 전체 트리를 업데이트해야 합니다.
이전 세대의 블록체인의 경우 각 블록마다 별도의 체인 상태를 저장하면 너무 많은 공간이 필요하기 때문에 일반적으로 최근 상태만 추적합니다. 그러나 중복 제거로 인해 TON 블록체인에서는 각 블록마다 새로운 셀만 스토리지에 추가합니다. 이렇게 하면 처리 속도가 빨라질 뿐만 아니라 잔액, 상태를 확인하고 기록의 모든 지점에 대해 많은 오버헤드 없이 getmethod를 실행하는 등 효율적으로 히스토리 작업을 할 수 있습니다!
유사한 컨트랙트(예: 제튼월렛)가 여러 개 있는 경우, 노드는 중복 데이터(각 제튼월렛의 동일한 코드)를 한 번만 저장합니다. 라이브러리 셀을 사용하면 이러한 컨트랙트에 대해 중복 제거 메커니즘을 활용하여 스토리지 및 전달 수수료를 줄일 수 있습니다.
라이브러리 셀은 (아마도) 많은 참조가 있는 큰 셀을 가리키는 하나의 작은 셀을 C++ 포인터로 간주할 수 있습니다. 참조된 셀(라이브러리 셀이 가리키는 셀)은 존재해야 하며 공개 컨텍스트에 등록("게시")되어 있어야 합니다.
라이브러리 셀의 구조
라이브러리 셀은 다른 정적 셀에 대한 참조를 포함하는 이색 셀입니다. 특히 여기에는 참조된 셀의 256비트 해시가 포함되어 있습니다.
TVM의 경우 라이브러리 셀은 다음과 같이 작동합니다. TVM은 셀을 슬라이스로 열라는 명령을 받을 때마다(TVM 명령: CTOS
, funC 메서드: .begin_parse()
) 마스터체인 라이브러리 컨텍스트에서 해당 해시를 가진 셀을 라이브러리 셀에서 검색합니다. 이를 찾으면 참조된 셀을 열고 해당 슬라이스를 반환합니다.
라이브러리 셀을 여는 비용은 일반 셀을 여는 것과 동일하므로 공간을 훨씬 적게 차지하지만(따라서 저장 및 전송 비용이 적게 드는) 정적 셀을 투명하게 대체하는 용도로 사용할 수 있습니다.
다른 라이브러리 셀을 참조하는 라이브러리 셀을 만들고, 이 라이브러리 셀이 다시 다른 라이브러리 셀을 참조하는 식으로 만들 수 있다는 점에 유의하세요. 이러한 경우 .begin_parse()
는 예외를 발생시킵니다. 그러나 이러한 라이브러리는 XLOAD
옵코드를 사용하여 단계적으로 래핑을 해제할 수 있습니다.
라이브러리 셀의 또 다른 중요한 특징은 참조된 셀의 해시를 포함하고 있기 때문에 궁극적으로 일부 사틱 데이터를 참조한다는 점입니다. 이 라이브러리 셀이 참조되는 데이터는 변경할 수 없습니다.
마스터체인 라이브러리 컨텍스트에서 발견되어 라이브러리 셀에서 참조하려면 소스 셀이 마스터체인에 게시되어야 합니다. 즉, 마스터체인에 존재하는 스마트 콘트랙트는 이 셀을 public=true
플래그를 사용하여 자신의 상태에 추가해야 합니다. 이는 SETLIBCODE
연산 코드를 사용하여 수행할 수 있습니다.
스마트 컨트랙트에서 사용
라이브러리 셀은 수수료 계산을 제외한 모든 상황에서 참조하는 일반 셀과 동일한 방식으로 작동하므로 정적 데이터가 있는 셀 대신 라이브러리 셀을 사용할 수 있습니다. 예를 들어 제튼월렛 코드를 라이브러리 셀로 저장하면(일반적으로 최대 20셀, 6000비트 대신 1셀, 256+8비트) 스토리지 및 전달 수수료가 훨씬 적게 듭니다. 특히, init_code
가 포함된 internal_transfer
메시지의 전달 수수료는 0.011톤에서 0.003톤으로 감소합니다.
라이브러리 셀에 데이터 저장
제튼월렛 코드를 라이브러리 셀로 저장하여 수수료를 절감하는 예를 살펴봅시다. 먼저 젯튼월렛의 코드가 포함된 일반 셀로 컴파일해야 합니다.
일반 셀을 참조하여 라이브러리 셀을 생성해야 합니다. 라이브러리 셀에는 8비트 태그의 라이브러리 0x02
와 256비트 참조 셀 해시가 포함됩니다.
Fift에서 사용
기본적으로 빌더에 태그와 해시를 넣은 다음 "빌더를 이국적인 셀로 닫기"를 해야 합니다.
이](https://github.com/ton-blockchain/multisig-contract-v2/blob/master/contracts/auto/order_code.func), 라이브러리 셀에 직접 컴파일하는 예제 여기와 같이 파이브아즘 구조로 할 수 있습니다.
;; https://docs.ton.org/tvm.pdf, page 30
;; Library reference cell — Always has level 0, and contains 8+256 data bits, including its 8-bit type integer 2
;; and the representation hash Hash(c) of the library cell being referred to. When loaded, a library
;; reference cell may be transparently replaced by the cell it refers to, if found in the current library context.
cell order_code() asm "<b 2 8 u, 0x6305a8061c856c2ccf05dcb0df5815c71475870567cab5f049e340bcf59251f3 256 u, b>spec PUSHREF";
톤/톤에서 사용
또는 블루프린트에서 @톤/톤
라이브러리를 사용하여 라이브러리 셀을 ts 레벨로만 구성할 수도 있습니다:
import { Cell, beginCell } from '@ton/core';
let lib_prep = beginCell().storeUint(2,8).storeBuffer(jwallet_code_raw.hash()).endCell();
jwallet_code = new Cell({ exotic:true, bits: lib_prep.bits, refs:lib_prep.refs});
- 학습 소스 여기.
마스터체인 라이브러리 컨텍스트에서 일반 셀 게시
실제 예제는 여기에서 확인할 수 있습니다. 이 컨트랙트의 핵심은 set_lib_code(lib_to_publish, 2);
로, 게시해야 하는 일반 셀과 flag=2(모든 사람이 사용할 수 있음을 의미)를 입력으로 받습니다.
참고로, 셀을 게시하는 컨트랙트는 베이스체인보다 마스터체인에서 1000배 높은 스토리지와 저장 비용을 지불합니다. 따라서 라이브러리 셀 사용은 수천 명의 사용자가 사용하는 컨트랙트에 대해서만 효율적입니다.
블루프린트에서 테스트
라이브러리 셀을 사용하는 컨트랙트가 블루프린트에서 어떻게 작동하는지 테스트하려면 블루프린트 에뮬레이터의 라이브러리 컨텍스트에 참조된 셀을 수동으로 추가해야 합니다. 이렇게 하면 됩니다:
- 라이브러리 컨텍스트 사전(해시맵)
uint256->Cell
을 생성해야 하며, 여기서uint256
은 해당 셀의 해시입니다. - 에뮬레이터 설정에 라이브러리 컨텍스트를 설치합니다.
방법은 여기에 예시가 나와 있습니다.
현재 블루프린트 버전(@ton/blueprint:0.19.0
)은 에뮬레이션 중 일부 컨트랙트가 새 라이브러리를 게시하는 경우 라이브러리 컨텍스트를 자동으로 업데이트하지 않으므로 수동으로 수행해야 합니다.
04.2024에 실제 적용되었으며 가까운 시일 내에 개선될 예정입니다.
라이브러리 셀 기반 계약에 대한 메서드 가져오기
라이브러리 셀에 코드가 저장된 제튼월렛이 있고 잔액을 확인하려고 합니다.
잔액을 확인하려면 코드에서 get 메서드를 실행해야 합니다. 여기에는 다음이 포함됩니다:
- 라이브러리 셀에 액세스하기
- 참조된 셀의 해시 가져오기
- 마스터체인의 라이브러리 컬렉션에서 해당 해시가 있는 셀을 찾습니다.
- 에서 코드를 실행합니다.
레이어드 솔루션(LS)에서는 이러한 모든 프로세스가 사용자가 특정 코드 저장 방법에 대해 알 필요 없이 백그라운드에서 이루어집니다.
하지만 로컬에서 작업할 때는 상황이 달라집니다. 예를 들어 탐색기나 지갑을 사용하는 경우 계정 상태를 보고 NFT인지, 지갑인지, 토큰인지, 경매인지 등 유형을 파악하려고 할 수 있습니다.
일반 컨트랙트의 경우 사용 가능한 가져오기 메서드, 즉 인터페이스를 살펴보고 이해할 수 있습니다. 또는 계정 상태를 내 로컬 의사넷으로 '훔쳐서' 그곳에서 메서드를 실행할 수도 있습니다.
라이브러리 셀의 경우 자체적으로 데이터를 포함하지 않기 때문에 이 작업이 불가능합니다. 컨텍스트에서 필요한 셀을 수동으로 감지하고 검색해야 합니다. 이 작업은 LS(아직 바인딩이 이를 지원하지 않음)나 DTon을 통해 수행할 수 있습니다.
라이트서버로 라이브러리 셀 검색하기
get 메서드를 실행할 때 Liteserver는 자동으로 올바른 라이브러리 컨텍스트를 설정합니다. get 메서드로 컨트랙트 유형을 감지하거나 로컬에서 getmethod를 실행하려면 LS 메서드 liteServer.getLibraries를 통해 해당 셀을 다운로드해야 합니다.
DTon으로 라이브러리 셀 검색하기
dton.io/graphql](https://dton.io/graphql)에서도 라이브러리를 받을 수 있습니다:
{
get_lib(
lib_hash: "<HASH>"
)
}
특정 마스터체인 블록의 라이브러리 목록도 확인할 수 있습니다:
{
blocks{
libs_publishers
libs_hash
}
}
참고 항목
- [이색 셀](/개발/데이터 형식/이색 셀)
- TVM 지침