저자: @Web3Mario
요약: 지난번 TON 기술 소개 글에 이어서 TON 공식 개발 문서를 심도 있게 공부하고 있는데, 아직 학습의 문턱이 있고 현재 문서의 내용이 내부 개발 문서에 가깝게 되어 있어 신규 개발자에게는 그리 친절하지 않은 것 같아 저만의 학습 궤적을 정리해 보려고 합니다. 따라서 저는 저만의 학습 궤적을 바탕으로 톤체인 프로젝트 개발에 대한 일련의 글들을 정리해보고자 하며, 이를 통해 여러분이 톤 디앱 개발을 빠르게 시작하는 데 도움이 될 수 있기를 바랍니다. TON 디앱 개발을 시작하는 데 도움이 되었으면 좋겠고, 혹시 실수가 있다면 지적해주시고 함께 배워나가면 좋겠습니다.
>
EVM에서 NFT를 개발하는 것과 TON 체인에서 개발하는 것의 차이점은 무엇인가요
FT나 NFT를 출시하는 것은 일반적으로 디앱 개발자에게 가장 기본적인 요구사항입니다. 그래서 저는 이것을 학습 곡선으로 사용하고 있습니다. 우선, EVM 기술 스택에서 NFT를 개발할 때와 TON 체인에서 개발할 때의 차이점을 이해해 보겠습니다. EVM 기반 NFT는 일반적으로 ERC-721 표준을 상속받습니다. NFT는 분할할 수 없는 암호화 자산 유형이며, 각 자산은 고유한, 즉 해당 자산에만 적용되는 특정 특성이 있습니다. ERC-721은 이러한 유형의 자산에 대한 일반적인 개발 패러다임입니다. 어떤 기능을 구현해야 하고 어떤 정보를 공통 ERC721 컨트랙트에 기록해야 하는지 살펴봅시다. 아래는 ERC721 인터페이스입니다. FT와 달리 전송 인터페이스에서는 수량이 아닌 전송할 토큰의 토큰아이디를 입력해야 한다는 것을 알 수 있습니다. 이 토큰아이디는 NFT 자산의 고유성을 나타내는 가장 기본적인 표현이기도 하지만, 물론 더 많은 속성을 전달하기 위해 일반적으로 각 토큰아이디에 대해 메타데이터가 기록되며, 이는 NFT에 대한 다른 확장 가능한 데이터에 대한 외부 링크(예: PFP 이미지 링크, 일부 속성의 이름 등)입니다.
이미지 src="https://img.jinse.cn/7246813_image3.png" alt="P6yhmaC143.png">
솔리디 또는 객체 지향에 익숙한 개발자는 이와 같은 스마트 컨트랙트를 쉽게 구현할 수 있습니다. 몇 가지 주요 매핑 관계와 같이 컨트랙트에 필요한 데이터 유형을 정의하고 원하는 기능에 따라 해당 데이터를 수정하는 로직을 개발하면 NFT를 구현할 준비가 된 것입니다.
그러나 TON 체인에서는 이와 완전히 동일하지 않으며 두 가지 핵심 이유가 있습니다.
TON에서 데이터 저장은 셀을 기반으로 하며, 동일한 계정의 셀은 방향성 비순환 그래프를 통해 구현됩니다. 따라서 데이터의 저장 기간이 무한정 늘어날 수 없는데, 쿼리 비용을 결정하는 데이터의 깊이인 방향 비순환 그래프가 무한히 확장되는 경우 쿼리 비용의 깊이가 너무 높아져 교착 상태에 빠지는 문제가 발생하게 됩니다.
TON은 높은 동시성 성능을 추구하기 위해 직렬 실행 아키텍처를 포기하고 대신 병렬 실행을 위한 개발 패러다임인 액터 모델을 채택하여 실행 환경을 재구성했습니다. 이는 스마트 컨트랙트가 서로에게 소위 내부 메시지를 보내는 방식으로만 비동기적으로 호출할 수 있다는 것을 의미하며, 상태 수정 호출과 읽기 전용 호출 모두 이 원칙을 따라야 하고, 비동기 호출이 실패할 경우 데이터 롤백을 어떻게 처리할지에 대한 신중한 고려가 필요하다는 점을 지적합니다.
물론 다른 기술적 차이점은 이전 포스트에서 자세히 설명했지만, 이번 포스트에서는 스마트 콘트랙트 개발에 초점을 맞추지 않겠습니다. 위의 두 가지 설계 원칙은 TON의 스마트 컨트랙트 개발을 EVM과 매우 다르게 만듭니다. 먼저, NFT 콘트랙트는 NFT 관련 데이터를 저장하기 위해 몇 가지 매핑 관계, 즉 매핑을 정의해야 한다는 것을 알고 있습니다. 가장 중요한 것은 소유자이며, 이 매핑은 NFT의 소유권을 결정하는 토큰ID에 해당하는 NFT의 소유자 주소 매핑을 저장하며, 자금 전송은 소유권을 변경하는 것입니다. 이는 이론적으로 무한한 데이터 구조이므로 가급적 피해야 합니다. 따라서 공식적인 권장 사항은 경계가 없는 데이터 구조의 존재 여부를 샤딩의 기준으로 삼는 것입니다. 즉, 유사한 데이터 저장 요구가 있는 경우 마스터-슬레이브 계약 패러다임을 각 키에 해당하는 데이터를 관리하는 서브 계약을 생성하는 것으로 대체합니다. 그리고 마스터 컨트랙트를 통해 글로벌 파라미터를 관리하거나 하위 컨트랙트 간의 내부 정보 상호 작용을 처리할 수 있습니다.
이에 따라 TON의 NFT도 이와 유사한 아키텍처로 설계되어야 하며, 각 NFT는 소유자 주소, 메타데이터 등과 같은 고유 데이터를 보유한 별도의 서브 컨트랙트로서 마스터 컨트랙트를 통해 NFT 이름, 심볼, 총 공급량 등과 같은 글로벌 데이터를 관리하게 됩니다.
아키텍처를 정의한 다음 단계는 핵심 기능 요구사항을 해결하는 것입니다. 마스터-슬레이브 컨트랙트 방식이기 때문에 마스터 컨트랙트가 수행하는 기능과 서브 컨트랙트가 수행하는 기능, 둘 사이의 통신에 사용되는 내부 정보, 실행 오류 발생 시 이전 데이터를 롤백하는 방법 등을 정의해야 합니다. 일반적으로 크고 복잡한 프로젝트를 개발하기 전에 클래스 다이어그램을 통해 클래스 간의 정보 흐름을 정의하고 내부 호출 실패 시 롤백 로직에 대해 신중하게 생각해야 하지만, 위의 NFT 개발은 간단하지만 이와 유사하게 검증할 수 있습니다.
소스코드에서 TON 스마트 컨트랙트 개발하기
소스 코드에서 TON 스마트 컨트랙트 개발하기
TON은 스마트 컨트랙트 개발 언어로 Func라는 정적 타입의 언어인 C 클래스를 선택했기 때문에 소스코드에서 TON 스마트 컨트랙트를 개발하는 방법을 배우도록 하겠습니다, 저는 NFT 예제에서 TON 공식 문서를 소개하기로 선택했으니 관심있는 파트너들은 확인해보시면 됩니다. 이 경우 간단한 TON NFT 예제가 구현되어 있습니다. 두 개의 기능 컨트랙트와 세 개의 필수 라이브러리로 나뉘어져 있는 컨트랙트 구조를 살펴보겠습니다.
이미지 src="https://img.jinse.cn/7246815_image3.png" alt="kDAvnWDXv9.png">
두 가지 주요 기능 계약은 위에서 설명한 원칙에 따라 설계되었으며, 먼저 메인 계약인 nft-collection의 코드를 살펴봅시다. 컬렉션 코드:
이미지 src="https://img.jinse.cn/7246816_image3.png" alt="J5p9hzzlMr.png">
이것은 첫 번째 지식인 TON 스마트 컨트랙트에 데이터를 영구적으로 저장하는 방법을 소개합니다. 솔리디티에서 데이터의 영구 저장은 파라미터의 유형에 따라 EVM이 자동으로 처리한다는 것을 알고 있습니다. 일반적으로 스마트 컨트랙트의 상태 변수는 실행이 끝날 때 최신 값을 기준으로 자동으로 유지되므로 개발자는 이 과정에 대해 고민할 필요가 없습니다. 그러나 Func에서는 그렇지 않으며, 개발자가 직접 해당 처리 로직을 구현해야 하는데, 이는 C와 C++가 GC 과정을 고려해야 하는 것과 약간 비슷하지만 다른 새로운 개발 언어에서는 일반적으로 이 부분을 자동화합니다. 코드를 살펴보고 먼저 필요한 라이브러리 몇 가지를 소개한 다음, 첫 번째 함수 load_data는 퍼시스턴트되는 데이터를 읽는 데 사용되며, 로직은 먼저 get_data를 사용하여 퍼시스턴트 컨트랙트 저장 셀을 반환하는 것이며, 이는 표준 라이브러리 stdlib.fc에서 구현되며 일반적으로 이러한 함수 중 일부를 시스템 함수로 사용할 수 있다는 점에 유의하시기 바랍니다.
이 함수의 반환 값은 TVM의 셀 유형인 셀 타입입니다. 앞서 소개한 것처럼 TON 블록체인의 모든 퍼시스턴트 데이터는 셀 트리에 저장됩니다. 각 셀에는 최대 1023 비트의 임의 데이터와 다른 셀에 대한 최대 4개의 참조가 있습니다. 셀은 스택 기반 TVM에서 메모리로 사용됩니다. 셀은 엄격하게 인코딩된 데이터를 담고 있으며, 그 안의 특정 평문 데이터를 얻으려면 셀을 슬라이스라는 유형으로 변환해야 합니다. 셀은 시작_파싱 함수를 통해 슬라이스 유형으로 변환할 수 있고, 다시 시작_파싱 함수로 슬라이스 유형으로 변환할 수 있습니다. 셀은 begin_parse 함수에 의해 슬라이스로 변환된 다음, 슬라이스에서 비트를 로드하고 다른 셀에 대한 참조를 통해 셀의 데이터를 얻을 수 있습니다. 15행의 이 호출은 첫 번째 함수의 반환 값에서 직접 두 번째 함수를 호출하는 함수의 구문 설탕이라는 점에 유의하세요. 그리고 마지막에는 데이터가 유지된 순서대로 데이터가 로드됩니다. 이 프로세스는 솔리디티와 달리 해시맵을 기반으로 호출되지 않으므로 이 호출 순서가 엉망이 될 수 없습니다.
Save_data 함수에서도 로직은 비슷하지만 역방향 프로세스라는 점을 제외하면 다음 단계인 셀 빌더라는 새로운 유형의 빌더로 넘어갑니다. 데이터 비트와 다른 셀에 대한 참조를 빌더에 저장할 수 있으며, 먼저 표준 함수 start_cell을 통해 빌더를 생성한 다음 store 관련 함수를 통해 관련 함수를 저장하여 새로운 셀로 마무리할 수 있는데, 위의 호출 순서가 여기 저장 순서와 일치해야 한다는 점에 유의하세요. 마지막으로 end_cell은 메모리에서 관리되는 새 셀의 구성을 완료하고, 가장 바깥쪽의 set_data는 셀의 영구 저장을 완료합니다.
이미지 src="https://img.jinse.cn/7246817_image3.png" alt="p1926pA9lg.png">
다음으로 비즈니스 관련 기능들을 살펴보겠습니다, 먼저 컨트랙트를 통해 새로운 계약을 생성하는 방법을 먼저 소개해드리겠습니다. 는 방금 소개한 마스터-슬레이브 아키텍처에서 자주 사용됩니다. TON에서는 스마트 컨트랙트 간의 호출은 내부 메시지를 전송하는 방식으로 이루어집니다. 이는 send_raw_message라는 메서드를 통해 이루어집니다. 첫 번째 인수는 셀로 인코딩된 메시지, 두 번째 인수는 트랜잭션 실행 방식의 차이를 나타내는 식별자 비트이며, TON에서 전송되는 내부 메시지는 현재 3개의 메시지 모드와 3개의 메시지 플래그 등 다양한 실행 방식이 존재한다는 점에 유의하시기 바랍니다. 원하는 모드를 얻기 위해 하나의 모드와 여러 개의(또는 전혀 없는) 플래그를 결합할 수 있습니다. 결합은 단순히 값의 합을 채우는 것을 의미합니다. 모드와 플래그를 설명하는 표는 다음과 같습니다:
자, 이제 첫 번째 주요 함수인 deploy_. nft_item은 이름에서 알 수 있듯이 새로운 NFT 인스턴스를 생성하거나 캐스팅하는 함수이며, 메시지를 인코딩하는 약간의 조작을 거친 후 send_raw_message를 통해 내부 컨트랙트를 전송하고 플래그 1의 전송 식별자 비트와 인코딩에 지정된 수수료만을 현재 실행을 위한 가스 요금으로 사용합니다. 이 인코딩 규칙은 새로운 스마트 콘트랙트가 생성되는 방식과 일치해야 한다는 것을 쉽게 알 수 있습니다. 그럼 어떻게 하는지 살펴보겠습니다.
51줄을 직접 살펴보겠습니다. 위의 두 함수는 메시지에 필요한 정보를 생성하는 헬퍼 함수이므로 나중에 살펴보겠습니다. 스마트 컨트랙트를 생성하는 데 사용되는 내부 메시지를 인코딩하는 과정이며, 중간에 있는 숫자 중 일부는 실제로 내부 메시지가 필요하다는 것을 나타내는 식별자 비트입니다. 여기서 우리는 다음 지식을 소개해야 하는데, TON은 메시지 실행을 설명하기 위해 TL-B라는 이진 언어를 선택하고 내부 메시지의 특정 기능을 달성하기 위해 다른 마킹 비트 설정에 따라 가장 쉽게 생각할 수 있는 두 가지 시나리오, 즉 새로운 계약의 생성과 계약 함수 호출의 배포를 선택합니다. 51번째 줄의 접근 방식은 55, 56, 57번째 줄에 명시된 새 NFT 아이템 컨트랙트 생성이라는 전자에 해당합니다. 먼저, 55줄의 숫자 시퀀스는 일련의 식별자 비트입니다. store_uint에 대한 첫 번째 입력은 숫자 값이고, 두 번째는 내부 메시지가 식별자의 마지막 3비트에 의해 생성된 컨트랙트임을 결정하는 비트 길이이며, 111(또는 10진수로 4+2+1)의 해당 이진 값이며, 이 중 처음 두 개는 메시지에 새 컨트랙트의 소스 코드인 StateInit 데이터와 계약의 초기화가 동반됨을 나타냅니다. 처음 두 비트는 메시지에 새 컨트랙트의 소스 코드이자 초기화에 필요한 데이터인 StateInit 데이터가 첨부될 것임을 나타냅니다. 마지막 두 비트는 메시지가 새 컨트랙트의 소스 코드이자 초기화에 필요한 데이터인 StateInit 데이터와 함께 제공됨을 나타냅니다. 따라서 66줄의 코드는 3비트 데이터를 설정하는 것이 아니라 배포된 컨트랙트에 대한 함수 호출을 나타내는 것을 볼 수 있습니다. 구체적인 코딩 규칙은 여기에서 확인하세요.
따라서 StateInit에 대한 인코딩 규칙은 계산_nft_item_state_init에 의해 계산된 코드의 49줄에 해당하며, stateinit 데이터의 인코딩도 잘 정립된 TL-B 인코딩 규칙을 따르며, 몇 개의 태그된 비트 외에도 새 컨트랙트에 대한 코드와 데이터의 두 부분을 포함합니다. 초기화 데이터. 데이터는 새 컨트랙트에 지정된 퍼시스턴트 셀과 동일한 순서로 인코딩되어야 합니다. 36번째 줄에서 볼 수 있듯이, 초기화 데이터는 item_index로 ERC721의 tokenId와 유사하며, 표준 함수 my_address가 반환하는 현재 컨트랙트의 주소는 collection_address이며, 이 데이터의 순서는 nft-item의 선언과 일치합니다.
다음으로 알아둘 점은 TON에서 생성되지 않은 모든 스마트 콘트랙트는 생성 후 주소를 미리 계산할 수 있다는 점인데, 이는 솔리디티의 create2 함수와 유사하며, 새로운 주소의 생성은 워크체인 식별자 비트와 앞서 소개한 stateinit의 해시값 두 부분으로 구성된다는 점입니다. 전자는 앞서 소개한 것처럼 TON 무한 슬라이싱 아키텍처에서 지정해야 하며, 현재는 균일한 값입니다. 이 값은 표준 함수 워크체인에서 얻습니다. 후자는 표준 함수 cell_hash에서 얻습니다. 예시로 돌아가서, 계산_nft_item_address는 새 컨트랙트의 주소를 미리 계산하는 함수입니다. 결과 값은 내부 메시지가 전송될 주소인 53행의 메시지에 인코딩됩니다. 그리고 nft_content는 생성된 컨트랙트에 대한 초기화 호출에 해당하며, 다음 문서에서 설명합니다.
send_royalty_params는 읽기 전용 요청에 해당하는 내부 메시지여야 합니다. 이전 소개에서 TON의 내부 메시지에는 데이터를 수정할 수 있는 연산뿐만 아니라 이러한 방식으로 구현해야 하는 읽기 전용 연산도 포함된다는 점을 의도적으로 강조했는데, 컨트랙트가 바로 이러한 연산입니다. 요청은 요청자 마크의 콜백 함수 이후에 이루어져야 하며, 반환 데이터는 각각 항목 인덱스의 요청과 해당 로열티 데이터라는 점에 유의해야 합니다.
다음으로, 다음 지식의 다음 지점을 소개합시다, 톤의 스마트 계약은 모든 내부 메시지에 대한 전자는 모든 외부 메시지의 통합 호출에 대한 후자, 개발자는 항목의 통합 호출의 요구에 따라 기능에 있어야하며, 개발자는 내부의 함수를 사용해야합니다. 개발자는 위 67줄의 콜백 함수 태그인 메시지에 지정된 다양한 태그 비트를 기반으로 스위치와 같은 접근 방식을 사용하여 필요에 따라 함수 내에서 다양한 요청에 응답해야 합니다. 예제로 돌아가서 먼저 메시지에 빈 공간이 있는지 확인한 다음 메시지의 정보를 구문 분석합니다. 먼저 83행의 메시지를 구문 분석하여 후속 권한 확인에 사용될 sender_address를 가져오고, 여기서 ~ 연산자는 다른 구문 설탕에 속한다는 점에 유의합니다. 연산자는 다른 구문 설탕에 속한다는 점에 유의하세요. 다음으로 연산자 태그 비트를 파싱한 다음 다른 태그 비트에 따라 요청을 처리합니다. 즉, 위의 함수는 어떤 논리에 따라 호출됩니다. 예를 들어, 로열티 매개변수 요청에 대한 응답으로 새로운 nft를 캐스팅하거나, 자기증가형 글로벌 인덱스를 생성합니다.
다음 지식의 포인트는 108줄에 해당하며, 함수의 로직으로 이름을 알 수 있어야 하며, require 함수의 Solidity는 예외를 던지기 위한 표준 함수 throw_ unless, 예외를 던지기 위한 Func의 첫 번째 항목, 예외를 던지기 위한 Func의 첫 번째 항목을 통해 Func와 유사합니다. unless는 예외를 던지는 Func의 표준 함수이며, 첫 번째 매개 변수는 오류 코드이고, 두 번째 매개 변수는 비트 단위 부울 검사이며, 거짓이면 오류 코드와 함께 예외를 던집니다. 이 줄에서는 equal_slices를 사용하여 위에서 파싱한 sender_address가 컨트랙트 퍼시스턴트 스토어의 owner_address와 같은지 확인하고 권한 판단을 내립니다.
이미지 src="https://img.jinse.cn/7246819_image3.png" alt="Xg1dKPk83l.png">
마지막으로 코드 구조를 보다 명확하게 하기 위해 지속성 정보를 가져오는 데 도움이 되는 일련의 보조 함수가 유휴화되기 시작했지만 여기서는 소개하지 않겠습니다. 개발자는 이 구조를 참고하여 자신만의 스마트 컨트랙트를 개발할 수 있습니다.
이미지 src="https://img.jinse.cn/7246820_image3.png" alt="3DukH2og9o.png">
TON 생태계의 디앱 개발은 정말 흥미로운 일이며, EVM과는 매우 다른 패러다임이기 때문에 TON 체인에서 디앱을 개발하는 방법에 대한 연재를 진행하려고 합니다. TON 체인에서 디앱을 개발하는 방법에 대한 글들.