Autor: @Web3Mario

Zusammenfassung: Nach dem vorherigen Artikel über die Einführung der TON-Technologie habe ich die offiziellen TON-Entwicklungsdokumente in diesem Zeitraum eingehend studiert. Ich habe das Gefühl, dass es immer noch einige Hindernisse für das Lernen gibt. Der aktuelle Dokumentinhalt scheint eher eine interne Entwicklung zu sein Dokument für die Entwicklung neuer Einsteiger, daher versuche ich, eine Reihe von Artikeln über die Entwicklung von TON-Chain-Projekten auf der Grundlage meines eigenen Lernverlaufs zusammenzustellen begann mit der TON DApp-Entwicklung. Sollten sich beim Schreiben Fehler eingeschlichen haben, können Sie mich gerne korrigieren und gemeinsam lernen.

Was sind die Unterschiede zwischen der Entwicklung von NFT in EVM und der Entwicklung von NFT auf TON Chain?

Die Ausgabe eines FT oder NFT ist normalerweise das grundlegendste Bedürfnis für DApp-Entwickler. Deshalb nutze ich dies auch als Einstiegspunkt zum Lernen. Lassen Sie uns zunächst die folgenden Unterschiede zwischen der Entwicklung eines NFT im EVM-Technologie-Stack und in der TON-Kette verstehen. EVM-basierte NFTs entscheiden sich normalerweise dafür, den ERC-721-Standard zu erben. Das sogenannte NFT bezieht sich auf eine unteilbare Art von Kryptowährungs-Asset, und jedes Asset ist einzigartig, das heißt, es weist bestimmte exklusive Eigenschaften auf. ERC-721 ist ein gängiges Entwicklungsparadigma für diese Art von Vermögenswerten. Schauen wir uns an, welche Funktionen ein gemeinsamer ERC721-Vertrag implementieren muss und welche Informationen aufgezeichnet werden. Das Bild unten zeigt eine ERC721-Schnittstelle. Es ist ersichtlich, dass im Gegensatz zu FT in der Übertragungsschnittstelle nicht der Betrag, sondern die zu übertragende TokenId eingegeben werden muss. Diese Token-ID ist auch die grundlegendste Manifestation der Einzigartigkeit von NFT-Assets. Um mehr Attribute zu tragen, werden normalerweise Metadaten für jede Token-ID aufgezeichnet. Diese Metadaten sind ein externer Link, der andere skalierbare Daten des NFT speichert als Links zu PFP-Bildern, bestimmten Attributnamen usw.

Für Entwickler, die mit Solidity oder objektorientiert vertraut sind, ist es einfach, einen solchen intelligenten Vertrag zu implementieren. Definieren Sie einfach die im Vertrag erforderlichen Datentypen, z. B. einige wichtige Zuordnungsbeziehungen, und entwickeln Sie die entsprechenden Funktionen . Die Modifikationslogik dieser Daten kann eine NFT realisieren.

Allerdings ist bei TON Chain alles anders. Es gibt zwei Hauptgründe für den Unterschied:

l Die Datenspeicherung in TON basiert auf der Zelle, und die Zelle desselben Kontos wird durch einen gerichteten azyklischen Graphen implementiert. Dies bedeutet, dass die zu speichernden Daten nicht unbegrenzt wachsen können, da bei einem gerichteten azyklischen Diagramm die Abfragekosten durch die Tiefe der Daten bestimmt werden. Wenn sich die Tiefe ins Unendliche erstreckt, können die Abfragekosten zu hoch sein Der Vertrag steckt in einem Deadlock-Problem fest.

l Um eine hohe Parallelitätsleistung zu erzielen, hat TON die serielle Ausführungsarchitektur aufgegeben und stattdessen ein speziell für Parallelität entwickeltes Entwicklungsparadigma, das Actor-Modell, übernommen, um die Ausführungsumgebung zu rekonstruieren. Dies hat Auswirkungen. Smart Contracts können nur asynchron aufgerufen werden, indem sogenannte interne Nachrichten gesendet werden. Beachten Sie, dass dieses Prinzip auch befolgt werden muss, unabhängig davon, ob es sich um einen Statusänderungstyp oder einen schreibgeschützten Typ handelt Es muss sorgfältig überlegt werden, wie mit einem Daten-Rollback umgegangen wird, wenn ein asynchroner Aufruf fehlschlägt.

Natürlich wurden im vorherigen Artikel weitere technische Unterschiede ausführlich besprochen. Dieser Artikel konzentriert sich auf die Entwicklung intelligenter Verträge und wird daher nicht erläutert. Die beiden oben genannten Designprinzipien machen einen großen Unterschied zwischen der Entwicklung intelligenter Verträge und EVM in TON. In der ersten Diskussion wissen wir, dass ein NFT-Vertrag einige Mapping-Beziehungen, also Mapping, definieren muss, um NFT-bezogene Daten zu speichern. Die wichtigste davon ist Eigentümer. Diese Zuordnung speichert die Zuordnungsbeziehung der Eigentümeradresse des NFT, die einer bestimmten Token-ID entspricht, die den Besitz des NFT bestimmt. Die Übertragung ist eine Änderung des Besitzes. Da es sich hierbei um eine Datenstruktur handelt, die theoretisch unbegrenzt sein kann, muss sie so weit wie möglich vermieden werden. Daher wird offiziell empfohlen, die Existenz unbegrenzter Datenstrukturen als Standard für das Sharding zu verwenden. Das heißt, wenn ähnliche Anforderungen an die Datenspeicherung bestehen, wird stattdessen das Master-Slave-Vertragsparadigma verwendet und die jedem Schlüssel entsprechenden Daten werden durch die Erstellung von Unterverträgen verwaltet. Und verwalten Sie globale Parameter über den Hauptvertrag oder helfen Sie bei der Abwicklung der internen Informationsinteraktion zwischen Unterverträgen.

Dies bedeutet, dass auch NFTs in TON mit einer ähnlichen Architektur entworfen werden müssen. Jeder NFT ist ein unabhängiger Untervertrag, der exklusive Daten wie Eigentümeradresse, Metadaten usw. speichert und die Gesamtsituation über einen Hauptvertrag verwaltet wie NFT-Name, Symbol, Gesamtangebot usw.

Nach der Klärung der Architektur besteht der nächste Schritt darin, die grundlegenden Funktionsanforderungen aufgrund der Einführung dieses Master-Slave-Vertrags zu lösen.

Daher muss geklärt werden, welche Funktionen vom Hauptvertrag und welche vom Untervertrag übernommen werden und welche internen Informationen zur Kommunikation zwischen beiden verwendet werden. Gleichzeitig muss geklärt werden, wann ein Ausführungsfehler auftritt um die vorherigen Daten zurückzusetzen. Normalerweise ist es vor der Entwicklung eines komplexen Großprojekts notwendig, ein Klassendiagramm zu übergeben und den Informationsfluss untereinander zu klären und sorgfältig über die Rollback-Logik nachzudenken, nachdem der interne Aufruf fehlgeschlagen ist. Natürlich ist die oben erwähnte NFT-Entwicklung fehlgeschlagen ist einfach, kann aber auch eine ähnliche Überprüfung durchführen.

Erfahren Sie, wie Sie TON-Smart-Verträge aus dem Quellcode entwickeln

TON hat sich dafür entschieden, eine C-ähnliche, statisch typisierte Sprache namens Func als intelligente Vertragsentwicklungssprache zu entwerfen. Dann lernen wir, wie man TON-Smart-Verträge aus dem Quellcode entwickelt. Ich habe das NFT-Beispiel im offiziellen TON-Dokument ausgewählt . Interessierte Freunde können es selbst ausprobieren. In diesem Fall wird ein einfaches TON NFT-Beispiel implementiert. Werfen wir einen Blick auf die Vertragsstruktur, die in zwei funktionale Verträge und drei notwendige Bibliotheken unterteilt ist.

Diese beiden Hauptfunktionsverträge sind nach den oben genannten Grundsätzen gestaltet. Schauen wir uns zunächst den Code des Hauptvertrags nft-collection an:

Dies führt den ersten Wissenspunkt ein, wie man Daten in TON-Smart-Verträgen dauerhaft speichert. Wir wissen, dass die dauerhafte Speicherung von Daten in Solidity automatisch von EVM entsprechend der Art der Parameter von Smart Contracts erfolgt Wird nach der Ausführung automatisch basierend auf dem neuesten Wert beibehalten und gespeichert, und Entwickler müssen diesen Prozess nicht berücksichtigen. Dies ist jedoch in Func nicht der Fall. Entwickler müssen die entsprechende Verarbeitungslogik selbst implementieren. Diese Situation ähnelt in gewisser Weise der Notwendigkeit, den GC-Prozess in C und C++ zu berücksichtigen, aber andere neue Entwicklungssprachen automatisieren diesen Teil normalerweise Logik. Werfen wir einen Blick auf den Code. Zuerst stellen wir einige erforderliche Bibliotheken vor und sehen dann, dass die erste Funktion „load_data“ zum Lesen der dauerhaft gespeicherten Daten verwendet wird. Ihre Logik besteht darin, zunächst die persistente Vertragsspeicherzelle über get_data zurückzugeben Dies wird standardmäßig durch die Bibliothek stdlib.fc implementiert, einige dieser Funktionen können normalerweise als Systemfunktionen verwendet werden.

Der Rückgabewerttyp dieser Funktion ist Zelle, der Zelltyp in TVM. In der vorherigen Einführung wissen wir bereits, dass alle persistenten Daten in der TON-Blockchain im Zellbaum gespeichert werden. Jede Zelle verfügt über bis zu 1023 Bits beliebiger Daten und bis zu vier Verweise auf andere Zellen. Zellen werden im stapelbasierten TVM als Speicher verwendet. In der Zelle werden kompakt codierte Daten gespeichert. Um die spezifischen Klartextdaten zu erhalten, muss die Zelle in einen Typ namens Slice konvertiert werden. Die Zelle kann über die Funktion begin_parse in den Slice-Typ konvertiert werden. Anschließend können die Daten in der Zelle durch Laden der Datenbits aus dem Slice und Verweise auf andere Zellen abgerufen werden. Beachten Sie, dass diese Aufrufmethode in Zeile 15 syntaktischer Zucker in func ist und Sie die zweite Funktion direkt aufrufen können, die den Wert der ersten Funktion zurückgibt. Laden Sie schließlich die entsprechenden Daten in der Reihenfolge der Datenpersistenzreihenfolge. Beachten Sie, dass sich dieser Prozess von Solidity unterscheidet und nicht auf der Grundlage einer Hashmap aufgerufen wird, sodass die Reihenfolge der Aufrufe nicht durcheinander gebracht werden kann.

In der Funktion save_data ist die Logik ähnlich, mit der Ausnahme, dass es sich hierbei um einen umgekehrten Prozess handelt, der den nächsten Wissenspunkt einführt, einen neuen Typ-Builder, bei dem es sich um den Typ des Zell-Builders handelt. Datenbits und Verweise auf andere Zellen können in Buildern gespeichert werden, die dann in neue Zellen finalisiert werden können. Erstellen Sie zunächst einen Builder über die Standardfunktion begin_cell und speichern Sie nacheinander verwandte Funktionen über die speicherbezogenen Funktionen. Beachten Sie, dass die oben genannte Aufrufreihenfolge mit der Speicherreihenfolge hier übereinstimmen muss. Schließlich wird der Aufbau der neuen Zelle über end_cell abgeschlossen. Zu diesem Zeitpunkt wird die Zelle im Speicher verwaltet. Schließlich kann die dauerhafte Speicherung der Zelle über die äußersten set_data abgeschlossen werden.

Als nächstes werfen wir einen Blick auf geschäftsbezogene Funktionen. Zunächst müssen wir den nächsten Wissenspunkt vorstellen, wie man einen neuen Vertrag durch einen Vertrag erstellt, der in der gerade eingeführten Master-Slave-Architektur häufig verwendet wird. Wir wissen, dass in TON Anrufe zwischen Smart Contracts durch das Senden interner Nachrichten implementiert werden. Dies wird durch eine Nachricht namens send_raw_message erreicht. Beachten Sie, dass der erste Parameter die nachrichtencodierte Zelle ist und der zweite Parameter das Identifikationsbit ist, das verwendet wird, um den Unterschied in der Ausführungsmethode der Transaktion anzuzeigen in TON gibt es derzeit 3 ​​Nachrichtenmodi und 3 Nachrichtenflags für die Ausführungsmethode des Nachrichtenversands. Ein einzelner Modus kann mit mehreren (möglicherweise keinem) Flags kombiniert werden, um den gewünschten Modus zu erhalten. Das Kombinieren bedeutet lediglich, die Summe ihrer Werte einzutragen. Die Beschreibungstabelle der Modi und Flags ist unten aufgeführt:

Schauen wir uns also die erste Hauptfunktion an, „deploy_nft_item“, eine Funktion, die zum Erstellen oder Umwandeln einer neuen NFT-Instanz verwendet wird. Nach dem Codieren wird der interne Vertrag über send_raw_message gesendet und das Flag ausgewählt Das Flag-Bit von 1 verwendet nur die in der Codierung angegebene Gebühr als Gasgebühr für diese Ausführung. Nach der obigen Einführung können wir leicht erkennen, dass diese Codierungsregel der Art und Weise entsprechen sollte, einen neuen Smart Contract zu erstellen.

Werfen wir also einen Blick auf die Umsetzung.

Schauen wir uns direkt Zeile 51 an. Die beiden oben genannten Funktionen sind Hilfsfunktionen, die zum Generieren der für die Nachricht erforderlichen Informationen verwendet werden. Wir werden sie uns später ansehen. Dies ist ein Codierungsprozess zum Erstellen interner Nachrichten des Smart Contracts In der Mitte werden tatsächlich einige Identifikationsbits verwendet, um die Anforderungen der internen Nachricht zu beschreiben. Der nächste Wissenspunkt wird hier eingeführt. TON wählt eine Binärsprache namens TL-B, um die Ausführungsmethode der Nachricht zu beschreiben Für interne Informationen zu bestimmten spezifischen Funktionen sind die beiden einfachsten Verwendungsszenarien die Erstellung neuer Verträge und bereitgestellte Vertragsfunktionsaufrufe. Die Methode in Zeile 51 entspricht der ersteren und erstellt einen neuen NFT-Artikelvertrag, der hauptsächlich in den Zeilen 55, 56 und 57 angegeben wird. Erstens handelt es sich bei der großen Zahlenreihe in Zeile 55 um eine Reihe von Identifikationsbits. Beachten Sie, dass der erste Eingabeparameter von store_uint der Wert und der zweite die Bitlänge ist, die bestimmt, ob die interne Nachricht durch den Vertrag erstellt wird , die letzten drei Markierungsbits und das entsprechende Das Binärwertbit ist 111 (dezimal ist 4+2+1), die ersten beiden geben an, dass die Nachricht von StateInit-Daten begleitet wird. Diese Daten sind der Quellcode des neuen Vertrag und die für die Initialisierung erforderlichen Daten. Das letztgenannte Flag-Bit zeigt den internen Nachrichtenanhang an, d. h. es wird erwartet, dass die relevante Logik und die erforderlichen Parameter ausgeführt werden. Daher werden Sie feststellen, dass in Zeile 66 des Codes keine dreistelligen Daten festgelegt sind, was auf einen Funktionsaufruf für den bereitgestellten Vertrag hinweist. Detaillierte Kodierungsregeln finden Sie hier.

Dann entsprechen die Codierungsregeln von StateInit 49 Codezeilen, berechnet durch berechne_nft_item_state_init. Beachten Sie, dass die Codierung der Stateinit-Daten neben einigen Flag-Bits hauptsächlich zwei Teile des neuen Vertrags umfasst Code und Daten initialisieren. Die Codierungsreihenfolge der Daten muss mit der im neuen Vertrag festgelegten Speicherreihenfolge der Persistenzzellen übereinstimmen. Wie Sie in Zeile 36 sehen können, umfassen die Initialisierungsdaten item_index, der der tokenId in ERC721 ähnelt, und die aktuelle Vertragsadresse, die von der Standardfunktion my_address zurückgegeben wird, nämlich collection_address. Die Reihenfolge dieser Daten stimmt mit der Deklaration in überein NFT-Artikel.

Der nächste Wissenspunkt ist, dass in TON alle nicht generierten Smart Contracts ihre generierten Adressen vorab berechnen können. Dies ähnelt der Funktion create2 in Solidity. Die Generierung neuer Adressen in TON besteht aus zwei Teilen, dem Workchain-Identifier-Bit und dem Hash von Stateinit In der vorherigen Einführung wissen wir bereits, dass ersterer angegeben werden muss, um der TON-Infinite-Sharding-Architektur zu entsprechen. Erhalten aus der Standardfunktions-Workchain. Letzteres wird durch die Standardfunktion cell_hash ermittelt. Zurück zu diesem Beispiel: berechne_nft_item_address ist eine Funktion, die die neue Vertragsadresse vorab berechnet. Und kodieren Sie den generierten Wert in der Nachricht in Zeile 53 als Empfangsadresse der internen Nachricht. nft_content entspricht dem Initialisierungsaufruf des erstellten Vertrags. Die spezifische Implementierung wird im nächsten Artikel vorgestellt.

Bei send_royalty_params muss es sich um eine Antwort auf die interne Nachricht einer schreibgeschützten Anfrage handeln. In der vorherigen Einführung haben wir besonders betont, dass die interne Nachricht in TON nicht nur Vorgänge enthält, die die Daten ändern können, sondern auch die Lese-. Auf diese Weise muss nur die Operation durchgeführt werden, daher ist dieser Vertrag eine solche Operation. Zunächst ist es erwähnenswert, dass Zeile 67 die Markierung der Rückruffunktion darstellt, nachdem er auf die Anfrage geantwortet hat Die zurückgegebenen Daten sind der angeforderte Artikelindex und die entsprechenden Lizenzgebührendaten.

Als nächstes stellen wir den nächsten Wissenspunkt vor. Es gibt nur zwei einheitliche Eingänge zu Smart Contracts mit dem Namen recv_internal.

und recv_external, wobei Ersteres der einheitliche Aufrufeingang für alle internen Nachrichten und Letzteres der einheitliche Aufrufeingang für alle externen Nachrichten ist. Entwickler müssen eine schalterähnliche Methode innerhalb der Funktion entsprechend den Anforderungen verwenden, um auf verschiedene Tags zu reagieren Bits, die durch die Nachrichtenanforderung angegeben werden, ist das Markierungsbit hier die Callback-Funktionsmarkierung in Zeile 67 oben. Zurück zu diesem Beispiel: Führen Sie zunächst eine Leerstellenprüfung für die Nachricht durch und analysieren Sie dann die Informationen in Zeile 83, um die sender_address zu erhalten. Beachten Sie, dass der ~-Operator verwendet wird Hier gehört Zucker zu einer anderen Syntax. Ich werde hier nicht näher darauf eingehen. Als nächstes werden die OP-Operations-Flag-Bits analysiert und dann werden die entsprechenden Anforderungen entsprechend den verschiedenen Flag-Bits verarbeitet. Unter diesen werden die oben genannten Funktionen jeweils nach einer bestimmten Logik aufgerufen. Reagieren Sie beispielsweise auf eine Anfrage nach dem Lizenzgebührenparameter oder erstellen Sie einen neuen NFT und erhöhen Sie den globalen Index.

Der nächste Wissenspunkt entspricht Zeile 108. Ich denke, Sie können die Verarbeitungslogik dieser Funktion auch kennen, indem Sie sie benennen. Sie ähnelt der Anforderungsfunktion in Solidity. Ausnahmen werden in Func über den ersten Eingabeparameter ausgelöst ist der Fehlercode, der zweite besteht darin, den booleschen Wert des Bits zu überprüfen. Wenn das Bit falsch ist, wird eine Ausnahme mit dem Fehlercode ausgelöst. In dieser Zeile wird equal_slices verwendet, um zu bestimmen, ob die oben analysierte sender_address mit der Owner_address des dauerhaften Speichers des Vertrags übereinstimmt, und es wird eine Berechtigungsbeurteilung vorgenommen.

Um die Codestruktur klarer zu machen, wurden schließlich eine Reihe von Hilfsfunktionen entwickelt, die dabei helfen, Persistenzinformationen zu erhalten. Diese werden hier nicht vorgestellt. Entwickler können auf diese Struktur zurückgreifen, um ihre eigenen Smart Contracts zu entwickeln.

Die DApp-Entwicklung im TON-Ökosystem ist wirklich interessant und unterscheidet sich stark vom Entwicklungsparadigma von EVM. Daher werde ich in einer Reihe von Artikeln vorstellen, wie man DApp in der TON-Kette entwickelt. Lernen Sie gemeinsam mit allen und nutzen Sie diese Welle an Möglichkeiten. Sie können auch gerne mit mir auf Twitter interagieren, um neue und interessante Dapp-Ideen zu entwickeln und diese gemeinsam weiterzuentwickeln.