Publicación
Comparte tu conocimiento.
Mecánica de recepción y control de acceso a objetos
Esta es la segunda parte de la serie «Objetos entre padres e hijos en movimiento». Puedes leer la primera parte aquí
Mecánica de transferencia de control de acceso a objetos: :receive
Si has colocado un objetoXdentro de unPprincipal (transfiriendo X al identificador de P), ¿cómo puedes recuperarlo o usarlo? 🤔 Ahí es donde entra en juego el mecanismo de recepción especial de Sui.
Cuando un objeto se transfiere a un objeto principal, no aparece automáticamente. Está ahí, propiedad deP. Para usar o eliminar ese objeto secundario en una transacción, debesrecibirlo.
Piense en Recibir
¿Cómo se obtiene un recibo
Importante: Recibir
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
}
}
En take_toy, el toy_ticket: Receiving
-verificaen tiempo de ejecución que el toy_ticket realmente hace referencia a un objeto que actualmente es propiedad de la caja (utilizando el UID del dispositivo principal). Si algo no coincide (el objeto principal es incorrecto o el objeto no está realmente ahí), se cancelará.
- A continuación, devuelve el objeto Toy real como un valor propio en la transacción, lo que significa que ahora el Toy está bajo el control de nuestra función.
Tenga en cuenta que tuvimos que pasar &mut box.id. Sui exige que tengamos unareferencia mutable al UID del padrepara llamar a receive.
Se trata de un control de acceso inteligente: solo el módulo que puede generar un UID &mut del elemento principal puede permitir la recepción. Normalmente, el módulo de definición del tipo principal mostrará una función como take_toy que llama internamente a receive. Si el módulo principal no muestra ninguna función que proporcione un UID de &mut (directa o indirectamente), ningún código externo podrá arrebatar a sus hijos. De esta forma, el módulo principal controla cómo y cuándo se puede acceder a los niños.
En el ejemplo, Box tiene un campo id: UID. Como take_toy está en el mismo módulo, puede tomar prestado &mut box.id. Los módulos o transacciones externos pueden llamar a take_toy (box_obj, ticket), pero no pueden llamar por sí mismos a transfer: :receive en Box porque box.id es privado.
**Este patrón garantiza que solo el código autorizado pueda recuperar a los niños.**✅
¿Qué pasa con los objetos anidados? Si Toy fuera literalmente un campo dentro de Box (por ejemplo, Box {id, toy: Toy}), no necesitaríamos recibirlo: el juguete estaría accesible siempre que tuvieras &mut Box. Pero eso también significa que es más difícil quitarlo o tratarlo por separado (es como si fuera parte de la caja). En el caso de los objetos infantiles, desvinculamos el almacenamiento: el juguete está separado y debe sacarse de forma explícita. Esta es la razón por la que Sui exige la recepción del billete y la recepción de la llamada, lo que convierte la recogida de un niño en una acción autorizada.
Requisito de referencia mutable: Quizás te preguntes, ¿por qué &mut UID y no solo &UID? Mutable garantiza que el elemento principal esté bloqueado durante la operación de recepción, lo que evita la modificación simultánea y garantiza que la persona que llama tiene realmente el derecho de modificar ese elemento principal (lo que normalmente implica que es el propietario). Forma parte de las comprobaciones dinámicas de propiedad de Sui: al tomar un préstamo mutable del UID de la madre, Sui garantiza que ninguna otra transacción o acción paralela pueda interferir mientras tú extraes al hijo. Es un poco como cerrar la puerta de los padres antes de retirar el contenido.
Ejemplo de uso en un bloque de transacciones: Supongamos que un objeto Box es propiedad de Alicia, y ella tiene un objeto Toy que quiere poner dentro de la caja y, después, quizás Así que sácalo más tarde. Así es como podría verse bien:
-Fija el juguete a la caja: Alice llama a transfer: :public_transfer (toy, @
Conclusiones clave:
- Los objetos infantiles no son accesibles de forma predeterminada; necesitas un
ticket de recepción y una función adecuada para sacarlos. - El módulo principal decide cómo se puede recuperar (proporcionando una función con el UID &mut).
- transfer: :receive se usa dentro del módulo de definición del módulo principal para los objetos de ese módulo o de sus amigos. Si el tipo del niño está definido en otro lugar, necesitarás un enfoque diferente (escribe public_receive...).
Antes de continuar, un detalle más: si un objeto del tipo T solo tiene la habilidad clave (sin almacenar), Sui la considera un poco más restringida. Estos objetos no pueden recibirse mediante código genérico fuera de su módulo. En la práctica, esto significa que si T solo utiliza una clave y se convierte en un elemento secundario, tendrás que gestionar su recuperación en su propio módulo o en el módulo principal con una regla personalizada. Si T también tiene almacenamiento, tenemos más flexibilidad a través de public_receive. Exploremos eso a continuación.
- Sui
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.