Autor original: @Web3 Mario (https://x.com/web3_mario)
În urma articolului anterior despre introducerea tehnologiei TON, am studiat în profunzime documentele oficiale de dezvoltare TON în această perioadă, simt că există încă unele bariere în calea învățării. care este potrivit pentru dezvoltatorii noi. Nu este foarte prietenos, așa că am încercat să rezolv o serie de articole despre dezvoltarea proiectului TON Chain pe baza propriei mele traiectorii de învățare . Dacă există erori în scriere, sunteți bineveniți să mă corectați și să învățați împreună.
Care sunt diferențele dintre dezvoltarea NFT-urilor în EVM și dezvoltarea NFT-urilor pe TON Chain?
Emiterea unui FT sau NFT este adesea o nevoie de bază pentru dezvoltatorii DApp. Așa că îl folosesc și ca punct de intrare pentru învățare. În primul rând, să înțelegem următoarele diferențe între dezvoltarea unui NFT în stiva de tehnologie EVM și TON Chain. NFT-urile bazate pe EVM aleg adesea să moștenească standardul ERC-721. Așa-numitul NFT se referă la un tip indivizibil de activ criptat, iar fiecare activ este unic, adică are anumite caracteristici exclusive. ERC-721 este o paradigmă comună de dezvoltare pentru acest tip de active. Să ne uităm la ce funcții trebuie să implementeze un contract comun ERC 721 și ce informații trebuie înregistrate. Imaginea de mai jos este o interfață ERC 721. Se poate observa că, spre deosebire de FT, ceea ce trebuie introdus în interfața de transfer este tokenIdul care trebuie transferat, mai degrabă decât suma. Acest tokenId este, de asemenea, cea mai de bază manifestare a unicității activelor NFT. Desigur, pentru a transporta mai multe atribute, se înregistrează de obicei o metadate pentru fiecare tokenId ca Link-uri către imagini PFP, nume ale anumitor proprietăți etc.
Pentru dezvoltatorii care sunt familiarizați cu Solidity sau sunt familiarizați cu orientarea obiectelor, este ușor să implementeze un astfel de contract inteligent. Trebuie doar să definiți tipurile de date necesare în contract, cum ar fi unele relații de cartografiere cheie și să dezvoltați cele corespunzătoare în funcție de cerințele Logica de modificare a acestor date poate realiza un NFT.
Cu toate acestea, acest lucru nu este același în TON Chain. Există două motive principale pentru diferență:
Stocarea datelor în TON este implementată pe baza celulelor, iar celulele aceluiași cont sunt implementate prin grafice aciclice direcționate. Aceasta înseamnă că datele care trebuie stocate nu pot crește fără limite, deoarece pentru un grafic aciclic direcționat, costul interogării este determinat de adâncimea datelor. Când adâncimea se extinde la infinit, costul interogării poate fi prea mare, ceea ce duce la Contractul este blocat într-o problemă de blocaj.
Pentru a urmări performanțe de concurență ridicate, TON a abandonat arhitectura de execuție în serie și a adoptat în schimb o paradigmă de dezvoltare special concepută pentru paralelism, modelul Actor, pentru a reconstrui mediul de execuție. Acest lucru are un impact. Contractele inteligente pot fi apelate doar în mod asincron prin trimiterea de așa-numite mesaje interne trebuie luate în considerare cu atenție Cum să gestionați retragerea datelor dacă un apel asincron eșuează.
Desigur, alte diferențe tehnice au fost discutate în detaliu în articolul precedent. Acest articol speră să se concentreze pe dezvoltarea de contracte inteligente, așa că nu va fi discutat. Cele două principii de proiectare de mai sus fac o mare diferență între dezvoltarea de contracte inteligente în TON și EVM. În discuția inițială, știm că un contract NFT trebuie să definească unele relații de mapare, adică mapare, pentru a salva datele legate de NFT. Cea mai importantă este proprietarii. Această mapare stochează relația de mapare a adresei de proprietar NFT corespunzătoare unui anumit tokenID, care determină proprietatea NFT. Deoarece aceasta este o structură de date care poate fi nelimitată în teorie, trebuie evitată pe cât posibil. Prin urmare, se recomandă oficial să folosiți existența unor structuri de date nelimitate ca standard pentru sharding. Adică, atunci când există cerințe similare de stocare a datelor, se folosește în schimb paradigma contractului master-slave, iar datele corespunzătoare fiecărei chei sunt gestionate prin crearea de subcontracte. Și gestionați parametrii globali prin contractul principal sau ajutați la gestionarea interacțiunii informațiilor interne dintre subcontracte.
Aceasta înseamnă că NFT-urile din TON trebuie, de asemenea, să fie proiectate folosind o arhitectură similară. Fiecare NFT este un subcontract independent, care salvează date exclusive, cum ar fi adresa proprietarului, metadatele etc. și gestionează situația generală printr-un contract principal cum ar fi numele NFT, simbolul, oferta totală etc.
După clarificarea arhitecturii, următorul pas este rezolvarea cerințelor funcționale de bază Deoarece este adoptată această metodă de contract master-slave, este necesar să se clarifice care funcții sunt îndeplinite de contractul principal și care funcții sunt îndeplinite de subcontract. iar cele două sunt trecute prin Ce informații interne sunt comunicate și cum se derulează înapoi datele anterioare atunci când apare o eroare de execuție. De obicei, înainte de a dezvolta un proiect complex la scară largă, este necesar să treceți o diagramă de clasă și să clarificați fluxul de informații între ele și să vă gândiți cu atenție la logica de rollback după ce apelul intern eșuează. Desigur, dezvoltarea NFT de mai sus este simplă , dar poate face și o verificare similară.
Învață să dezvolți contracte inteligente TON din codul sursă
TON a ales să creeze un limbaj tip C, denumit Func, ca limbaj de dezvoltare a contractelor inteligente. Apoi, să învățăm cum să dezvoltăm contractele inteligente TON din codul sursă. Am ales exemplul NFT în documentul oficial TON Prietenii interesați îl pot verifica singuri. În acest caz, este implementat un exemplu simplu TON NFT. Să aruncăm o privire asupra structurii contractului, care este împărțită în două contracte funcționale și trei biblioteci necesare.
Aceste două contracte funcționale principale sunt concepute conform principiilor de mai sus. În primul rând, să ne uităm la codul contractului principal nft-collection:
Acest lucru introduce primul punct de cunoaștere, cum să stocați în mod persistent datele în contractele inteligente TON. Știm că stocarea persistentă a datelor în Solidity este gestionată automat de EVM, în funcție de tipul de parametri va fi persistat și stocat automat pe baza ultimei valori după execuție, iar dezvoltatorii nu trebuie să ia în considerare acest proces. Dar acest lucru nu este cazul în Func. Dezvoltatorii trebuie să implementeze ei înșiși logica de procesare. . Să aruncăm o privire la cod. În primul rând, introducem câteva biblioteci necesare, apoi vedem că prima funcție load_data este utilizată pentru a citi datele stocate în mod persistent este realizat de standardul Implementat de biblioteca stdlib.fc, unele dintre aceste funcții pot fi utilizate de obicei ca funcții de sistem.
Tipul de valoare returnată al acestei funcții este celulă, care este tipul de celulă din TVM. În introducerea anterioară, știm deja că toate datele persistente din blockchain-ul TON sunt stocate în arborele de celule. Fiecare celulă are până la 1023 de biți de date arbitrare și până la patru referințe la alte celule. Celulele sunt folosite ca memorie în TVM bazat pe stivă. Ceea ce este stocat în celulă sunt date codificate compact. Pentru a obține date specifice text simplu, celula trebuie convertită într-un tip numit slice. Celula poate fi convertită la tipul slice prin funcția begin_parse, iar apoi datele din celulă pot fi obținute prin încărcarea biților de date și referințe la alte celule din slice. Rețineți că metoda de apelare din linia 15 este zahăr sintactic într-o funcție care apelează direct a doua funcție pe valoarea de returnare a primei funcție. Și în cele din urmă încărcați datele corespunzătoare în ordine în funcție de ordinea de persistență a datelor. Rețineți că acest proces este diferit de soliditate și nu este apelat pe baza hashmap, astfel încât ordinea apelurilor nu poate fi greșită.
În funcția save_data, logica este similară, cu excepția faptului că acesta este un proces invers, care introduce următorul punct de cunoaștere, un nou tip de constructor, care este tipul de generator de celule. Biții de date și referințele la alte celule pot fi stocați în constructori, care pot fi apoi finalizați în celule noi. Mai întâi creați un builder prin funcția standard begin_cell și stocați funcțiile asociate prin intermediul funcțiilor legate de magazin, la rândul său. Rețineți că ordinea de apelare de mai sus trebuie să fie în concordanță cu ordinea de stocare de aici. În cele din urmă, end_cell este folosit pentru a finaliza construcția noii celule. În acest moment, celula este gestionată în memorie.
În continuare, să aruncăm o privire asupra funcțiilor legate de afaceri. În primul rând, trebuie să introducem următorul punct de cunoaștere, cum să creăm un nou contract printr-un contract, care va fi folosit frecvent în arhitectura master-slave recent introdusă. Știm că în TON, apelurile între contractele inteligente sunt implementate prin trimiterea de mesaje interne. Acest lucru se realizează printr-un mesaj numit send_raw_message. Rețineți că primul parametru este celula codificată în mesaj, iar al doilea parametru este bitul de identificare, care este utilizat pentru a indica diferența în metoda de execuție a tranzacției în TON Există în prezent 3 moduri de mesaje și 3 steaguri de mesaje pentru modul de execuție al trimiterii mesajului. Un singur mod poate fi combinat cu mai multe steaguri (poate niciunul) pentru a obține modul dorit. Combinarea înseamnă doar completarea sumei valorilor lor. Un tabel de descriere a modurilor și steagurii este prezentat mai jos:
Deci, să ne uităm la prima funcție principală, deploy_nft_item După cum sugerează și numele, aceasta este o funcție folosită pentru a crea sau a arunca o nouă instanță NFT. După codificarea unui mesaj, contractul intern este trimis prin send_raw_message bitul flag de 1 folosește doar taxa specificată în codificare ca taxă de gaz pentru această execuție. După introducerea de mai sus, ne putem da seama cu ușurință că această regulă de codificare ar trebui să corespundă modului de a crea un nou contract inteligent. Deci, să aruncăm o privire la modul în care este implementat.
Să ne uităm direct la linia 51. Cele două funcții de mai sus sunt funcții auxiliare utilizate pentru a genera informațiile necesare pentru mesaj, așa că îl vom analiza mai târziu. Acesta este un proces de codificare pentru crearea de mesaje interne ale contractelor inteligente mijloc sunt de fapt Unii biți de identificare sunt utilizați pentru a descrie cerințele mesajului intern. Următorul punct de cunoaștere este introdus aici TON a ales un limbaj binar numit TL-B pentru a descrie metoda de execuție a mesajului și îl implementează prin stabilirea unui flag diferit. biți Pentru informații interne despre anumite funcții specifice, cele mai ușoare două scenarii de utilizare la care să vă gândiți sunt crearea de noi contracte și apelurile de funcții de contract. Metoda de pe linia 51 corespunde primei, creând un nou contract de articol nft, care este specificat în principal de rândurile 55, 56 și 57. În primul rând, seria mare de numere din linia 55 este o serie de biți de identificare. Rețineți că primul parametru de intrare al store_uint este valoarea, iar al doilea este lungimea biților, care determină dacă mesajul intern este creat de contract. , ultimii trei biți de marcare și valoarea binară corespunzătoare este 111 (zecimalul este 4+ 2+ 1), primii doi indică faptul că mesajul va fi însoțit de datele StateInit. Aceste date sunt codul sursă al noului contractul și datele necesare pentru inițializare. Ultimul bit de flag indică atașarea mesajului intern, adică se așteaptă ca logica relevantă și parametrii necesari să fie executați. Prin urmare, veți vedea că datele din trei cifre nu sunt setate în rândul 66 al codului, ceea ce indică un apel de funcție la contractul implementat. Regulile detaliate de codificare pot fi găsite aici.
Apoi, regulile de codificare ale StateInit corespund la 49 de linii de cod, calculate prin calculate_nft_item_state_init. Rețineți că codarea datelor stateinit urmează, de asemenea, o regulă de codificare TL-B stabilită, implică în principal două părți ale noului contract cod și Și inițializați datele. Ordinea de codificare a datelor trebuie să fie în concordanță cu ordinea de stocare a celulelor de persistență specificată de noul contract. După cum puteți vedea pe linia 36, datele de inițializare includ item_index, care este similar cu tokenId-ul din ERC 721 și adresa contractului curent returnată de funcția standard my_address, care este collection_address. Ordinea acestor date este în concordanță cu declarația în nft-item.
Următorul punct de cunoaștere este că în TON, toate contractele inteligente negenerate își pot precalcula adresele generate. Aceasta este similară cu funcția de creare 2 din Solidity. Generarea de noi adrese în TON constă din două părți, bitul de identificare cu valoarea hash a stateinit Așa cum am văzut în introducerea anterioară, primul trebuie să fie specificat pentru a corespunde arhitecturii TON infinite sharding. Obținut din lanțul de lucru al funcției standard. Acesta din urmă este obținut prin funcția standard cell_hash. Deci, revenind la acest exemplu, calculate_nft_item_address este o funcție care precalculează noua adresă de contract. Și codificați valoarea generată în mesaj pe linia 53 ca adresa de primire a mesajului intern. nft_content corespunde apelului de inițializare a contractului creat. Implementarea specifică va fi introdusă în articolul următor.
În ceea ce privește send_royalty_params, trebuie să fie un răspuns la mesajul intern al unei solicitări doar în citire. În introducerea anterioară, am subliniat în mod special că mesajul intern din TON nu conține doar operațiuni care pot modifica datele, ci și citirea. numai operațiunea trebuie făcută în acest mod, deci acest contract este o astfel de operațiune vor fi datele returnate, care sunt indexul articolului solicitat și datele corespunzătoare.
În continuare, să introducem următorul punct de cunoaștere. Există doar două intrări unificate la contractele inteligente în TON, numite recv_internal și recv_external. Dezvoltarea mesajelor Utilizatorul trebuie să utilizeze o metodă asemănătoare comutatorului pentru a răspunde la diferite solicitări în funcție de diferiții biți de semnalizare specificati de mesaj. Înapoi la acest exemplu, efectuați mai întâi o verificare a mesajului și apoi analizați informațiile din mesaj. Mai întâi, analizați pe linia 83 pentru a obține adresa de expeditor aici aparține unei alte sintaxe. Nu voi extinde aici. În continuare, biții de semnalizare a operațiunii operaționale sunt analizați, iar apoi cererile corespunzătoare sunt procesate în funcție de diferiți biți de semnalizare. Printre acestea, funcțiile de mai sus sunt numite, respectiv, după o anumită logică. De exemplu, răspundeți la o solicitare pentru parametrul redevență sau creați un nou nft și creșteți indexul global.
Următorul punct de cunoaștere corespunde liniei 108. Cred că puteți cunoaște și logica de procesare a acestei funcții, denumind-o. Similar cu funcția require din Solidity, excepțiile sunt aruncate în Func prin funcția standard throw_unless codul de eroare, al doilea este de a verifica valoarea booleană a bitului, dacă bitul este fals, va fi aruncată o excepție cu codul de eroare. În această linie, equal_slices este folosit pentru a determina dacă sender_address analizat mai sus este egal cu owner_address al stocării persistente a contractului și se face judecata de permisiune.
În cele din urmă, pentru a clarifica structura codului, au fost dezvoltate o serie de funcții auxiliare pentru a ajuta la obținerea informațiilor de persistență, care nu vor fi introduse aici. Dezvoltatorii se pot referi la această structură pentru a-și dezvolta propriile contracte inteligente.
Dezvoltarea DApp în ecosistemul TON este cu adevărat interesantă și este foarte diferită de paradigma de dezvoltare a EVM, așa că voi prezenta cum să dezvoltați DApp în TON Chain printr-o serie de articole. Învață împreună cu toată lumea și profită de acest val de oportunități. De asemenea, sunteți binevenit să interacționați cu mine pe Twitter pentru a vă ciocni cu câteva idei noi și interesante de dapp și pentru a le dezvolta împreună.