Sui.

Beitrag

Teile dein Wissen.

article banner.
harry phan.
Apr 13, 2025
Artikel

Objektzugriffskontrolle und Empfangsmechanik

Dies ist Teil 2 der Serie „Eltern-Kind-Objekte in Sui Move“. Teil 1 können Sie hier lesen

Übertragung der Objektzugriffskontrolle: :receive Mechanics

Sie haben also ein ObjektXin ein übergeordnetesPgesteckt (indem Sie X auf die ID von P übertragen haben) — wie holen Sie es wieder heraus oder verwenden es? 🤔 An dieser Stelle kommt Suis spezieller Empfangsmechanismus ins Spiel.

Wenn ein Objekt an ein übergeordnetes Objekt übertragen wird, springt es nicht automatisch heraus. Es befindet sich dort und gehörtP. Um dieses untergeordnete Objekt in einer Transaktion verwenden oder entfernen zu können, müssen Sie esempfangen. Sui bietet eine strukturierte Möglichkeit, dies mithilfe einesEmpfangsticketund der Funktion transfer: :receive zu tun.

##Das Empfangsticket

Stellen Sie sich Wareneingang als Anspruchsticket für ein untergeordnetes Objekt des Typs T vor. Anstatt das untergeordnete Objekt (das Sie noch nicht besitzen) direkt an eine Funktion weiterzuleiten, übergeben Sie einen Wareneingang — im Wesentlichen einen Verweis auf „das Objekt mit der ID Y, das dem übergeordneten Objekt X gehört“. Dieses Receiving ist eine spezielle Move-Struktur, die die ID, Version und den Digest des Objekts enthält, das empfangen werden soll. Sie hat nur die Fähigkeit, sie abzulegen, was bedeutet, dass sie kurzlebig existieren kann, aber nicht dauerhaft gespeichert werden kann. Mit anderen Worten, es handelt sich um ein Ticket zur einmaligen Verwendung innerhalb einer Transaktion.

Wie bekommt man eine Quittung? In der Regel, indem Sie die Übertragung durchführen. In einem programmierbaren Transaktionsblock (PTB) kann ein Schritt das ObjektCan das übergeordnete ObjektPübertragen, wodurch ein Empfangsticket entsteht, das der nächste Schritt verwenden kann. Wenn das Kind bereits in einer früheren Transaktion im übergeordneten Objekt saß, können Sie einen Empfang als Eingabe für eine neue Transaktion angeben (das Sui SDK/CLI ermöglicht es Ihnen, ein untergeordnetes Objekt anhand seiner ID und des übergeordneten Objekts anzugeben, um das Ticket zu generieren).

Wichtig: Eine Empfangsfunktion ist nicht das Objekt selbst — es überträgt Ihnen noch keine Eigentumsrechte. Es signalisiert nur, dass „ein Objekt vom Typ T mit dieser ID diesem Elternteil gehört und ich beabsichtige, es zu übernehmen“. Um das Objekt tatsächlich abzurufen, müssen Sie transfer: :receive: aufrufen:


module example::toy_box {
    use sui::transfer::{Self, Receiving};

    struct Toy has key { id: UID, name: vector<u8> }
    struct Box has key { id: UID }

    /// Remove a Toy child from a Box, returning the Toy to the caller.
    public entry fun take_toy(box: &mut Box, toy_ticket: Receiving<Toy>): Toy {
        // Use the parent's UID and the Receiving ticket to get the Toy
        let toy = transfer::receive(&mut box.id, toy_ticket);
        // Now `toy` is an owned value we can return (or transfer to someone).
        toy
    }
}

In take_toy steht toy_ticket: Receiving für ein Spielzeug, das zur Box gehört. Durch den Aufruf von transfer: :receive (&mut box.id, toy_ticket) rufen wir die native Logik von Sui auf, um das Toy-Objekt tatsächlich aus der Box abzurufen. Das macht ein paar wichtige Dinge:

  • Esüberprüftzur Laufzeit, ob das toy_ticket tatsächlich auf ein Objekt verweist, das derzeit der Box gehört (unter Verwendung der UID des übergeordneten Objekts). Wenn etwas nicht passt (falsches übergeordnetes Objekt oder Objekt, das nicht wirklich vorhanden ist), wird der Vorgang abgebrochen.
  • Es gibt dann das eigentliche Toy-Objekt als eigenen Wert in der Transaktion zurück, was bedeutet, dass das Spielzeug jetzt unter der Kontrolle unserer Funktion steht.

Beachten Sie, dass wir &mut box.id übergeben mussten. Sui erzwingt, dass wir eineveränderbare Referenz auf die UIDdes Elternteils haben, um den Empfang aufzurufen.

Das ist eine clevere Zugriffskontrolle: Nur das Modul, das eine &mut-UID des Elternteils erzeugen kann, kann den Empfang zulassen. Normalerweise stellt das Definitionsmodul des übergeordneten Typs eine Funktion wie take_toy bereit, die interne Aufrufe empfangen. Wenn das übergeordnete Modul keine Funktion bereitstellt, die eine &mut-UID ausgibt (direkt oder indirekt), kann kein externer Code seine untergeordneten Elemente abrufen. Auf diese Weise steuert das Modul der Eltern, wie und wann auf Kinder zugegriffen werden kann.

Im Beispiel hat Box ein Feld id: UID. Da sich take_toy im selben Modul befindet, kann es &mut box.id ausleihen. Externe Module oder Transaktionen können take_toy (box_obj, ticket) aufrufen, aber sie können nicht selbst transfer: :receive auf Box aufrufen, da box.id privat ist.

**Dieses Muster stellt sicher, dass nur autorisierter Code Kinder abrufen kann.**✅

Was ist mit verschachtelten Objekten? Wenn Toy buchstäblich ein Feld in der Box wäre (sagen wir Box {id, toy: Toy}), bräuchten wir keinen Empfang — das Spielzeug wäre immer zugänglich, wenn Sie &mut Box haben. Das bedeutet aber auch, dass es schwieriger ist, es zu entfernen oder es separat zu behandeln (es ist wie ein Teil der Box). Bei Objekten für Kinder entkoppeln wir den Stauraum: Das Spielzeug ist separat und muss explizit herausgenommen werden. Diese Deutlichkeit ist der Grund, warum Sui die Option „Ticket annehmen“ und „Anruf annehmen“ verlangt — so wird das Abrufen von Kindern zu einer autorisierten Aktion.

Veränderbare Referenzanforderung: Sie fragen sich vielleicht, warum &mut UID und nicht nur &UID? Mutable stellt sicher, dass das übergeordnete Objekt während des Empfangsvorgangs gesperrt ist, wodurch gleichzeitige Änderungen verhindert werden und sichergestellt wird, dass der Anrufer tatsächlich das Recht hat, dieses übergeordnete Objekt zu ändern (was normalerweise bedeutet, dass er der Eigentümer ist). Das ist Teil der dynamischen Eigentumsüberprüfung von Sui. Indem Sui die UID des Elternteils veränderbar ausnutzt, garantiert Sui, dass keine andere Transaktion oder parallele Aktion stören kann, während Sie das Kind herausziehen. Es ist ein bisschen so, als würde man die Tür der Eltern verriegeln, bevor man den Inhalt herausnimmt.

Beispiel für die Verwendung in einem Transaktionsblock: Angenommen, ein Box-Objekt gehört Alice, und sie hat ein Toy-Objekt, das sie in die Box legen möchte und dann vielleicht Also nimm es später heraus. So könnte es aussehen, okay:

-Spielzeug an der Kiste befestigen: Alice ruft transfer: :public_transfer (toy, @); in einer PTB auf. Dadurch wird das Spielzeug unter die Box übertragen (wir verwenden hier public_transfer, weil es ein Transaktionskontext ist — dazu bald mehr). Jetzt ist das Spielzeug ein Kind der Box. -Rufen Sie in derselben oder einer anderen Transaktion Spielzeug ab: Alice ruft example: :toy_box: :take_toy (box_obj,) auf, wobei Receiving auf das Spielzeug verweist. Unter der Haube ruft take_toy den Empfang an, überprüft die Beziehung und gibt das Spielzeug zurück. Jetzt wäre das Spielzeug eine Ausgabe der Transaktion und landet normalerweise wieder unter Alices Adresse (da wir es von einer Eingabefunktion zurückgegeben haben).

Wichtige Erkenntnisse:

  • Auf untergeordnete Objekte kann standardmäßig nicht zugegriffen werden. Sie benötigen ein Empfangsticket und eine entsprechende Funktion, um sie herauszuholen. — Das übergeordnete Modul entscheidet, wie Sie Daten abrufen können (indem Sie eine Funktion mit &mut UID bereitstellen).
  • transfer: :receive wird innerhalb des Definitionsmoduls des übergeordneten Moduls für Objekte dieses Moduls oder seiner Freunde verwendet. Wenn der Typ des Kindes an anderer Stelle definiert ist, benötigen Sie einen anderen Ansatz (geben Sie public_receive... ein).

Bevor wir weitermachen, noch ein Detail: Wenn ein Objekttyp T nur die Schlüsselfähigkeit hat (kein Speichern), behandelt Sui sie etwas eingeschränkter. Solche Objekte können nicht mit generischem Code außerhalb ihres Moduls empfangen werden. In der Praxis bedeutet das, wenn T nur einen Schlüssel hat und ein untergeordnetes Objekt wird, müssen Sie den Abruf in einem eigenen Modul oder im Modul des Elternteils mit einer benutzerdefinierten Regel durchführen. Wenn T auch Speicher hat, haben wir über public_receive mehr Flexibilität. Lassen Sie uns das als Nächstes untersuchen.

  • Sui
3
Teilen
Kommentare
.

Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

368Beiträge503Antworten
Sui.X.Peera.

Verdiene deinen Anteil an 1000 Sui

Sammle Reputationspunkte und erhalte Belohnungen für deine Hilfe beim Wachstum der Sui-Community.

BelohnungskampagneJuli