Publicación
Comparte tu conocimiento.
Administración de niños entre módulos con public_receive
Esta es la tercera parte de la serie «Objetos entre padres e hijos en movimiento».
A veces, los tipos de padre e hijo se definen en diferentes módulos o incluso en paquetes diferentes. Por ejemplo, es posible que tengas un objeto Warehouse genérico que pueda almacenar cualquier tipo de objeto Parcel. El módulo Warehouse quiere extraer un paquete secundario, pero el tipo de paquete se define en otro lugar. En estos casos, utilizamos transfer: :public_receive, que es el primo de receive entre módulos.
###receive vs public_receive
Como hemos visto, transfer: :receive
transfer: :public_receive
¿Por qué requerir una tienda? Porque almacenar marcas de que el objeto puede conservarse y distribuirse de forma segura fuera de su módulo de definición. Los objetos de solo clave pueden tener invariantes personalizados que el módulo original quiera aplicar al transferirlos o recibirlos; al excluir los de public_receive, Sui obliga a los desarrolladores a gestionarlos dentro del módulo (como veremos con los objetos enlazados al alma). Si un objeto tiene almacenamiento, es más permisivo, y Sui permite una lógica genérica de transferencia/recepción para gestionarlo externamente.
###Ejemplo: módulos separados para padres e hijo
Vamos a ilustrarlo con un escenario sencillo: un almacén que almacena objetos de paquetería. El tipo de paquete se define en su propio módulo y el almacén en otro. Mostraremos cómo Warehouse puede recibir un paquete secundario mediante public_receive.
module demo::parcel { // Child module
use sui::object::{Self, UID};
use sui::tx_context::{Self, TxContext};
/// A parcel object that can be stored in a Warehouse.
/// It has both key and store, so it can be transferred across modules.
struct Parcel has key, store { id: UID, contents: vector<u8> }
public entry fun create_parcel(contents: vector<u8>, ctx: &mut TxContext): Parcel {
Parcel { id: object::new(ctx), contents }
}
}
module demo::warehouse { // Parent module
use sui::transfer::{Self, Receiving, public_receive};
use demo::parcel::{Self, Parcel};
use sui::object::{UID};
use sui::tx_context::{Self, TxContext};
struct Warehouse has key { id: UID, location: address }
public entry fun create_warehouse(location: address, ctx: &mut TxContext): Warehouse {
Warehouse { id: object::new(ctx), location }
}
/// Receive a Parcel that was sent to this Warehouse.
/// Returns the Parcel to the caller (transferred to caller's address).
public entry fun withdraw_parcel(
warehouse: &mut Warehouse,
parcel_ticket: Receiving<Parcel>,
ctx: &mut TxContext
): Parcel {
// Using public_receive because Parcel is defined in another module and has store
let parcel = public_receive<Parcel>(&mut warehouse.id, parcel_ticket) [oai_citation_attribution:27‡docs.sui.io](https://docs.sui.io/concepts/transfers/transfer-to-object#:~:text=%2F%2F%2F%20Given%20mutable%20,argument) [oai_citation_attribution:28‡github.com](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/transfer.move#:~:text=public%20fun%20public_receive,T%3E%29%3A%20T);
// Transfer the parcel to the transaction sender (so the caller gets ownership)
transfer::transfer(parcel, tx_context::sender(ctx));
// We return nothing because we've transferred the Parcel out to the caller.
}
}
Analicemos lo que está sucediendo en draw_parcel:
- Llamamos a public_receive
(&mut warehouse.id, parcel_ticket). Como Parcel tiene la capacidad de almacenar, esta llamada está permitida aunque no estemos en el módulo de paquetería. En principio, realiza las mismas comprobaciones y extracciones que las de recepción, pero se permite usar varios módulos, ya que la tienda indica que es seguro hacerlo. https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/transfer.move#:~:text=public%20fun%20public_receive,T%3E%29%3A%20T - A continuación, transferimos inmediatamente el paquete recibido a la dirección de la persona que llama (tx_context: :sender (ctx)). Este paso garantiza que el paquete salga del almacén y llegue al usuario que inició la retirada. También podríamos haber devuelto Parcel desde la función y Sui lo trataría como una salida que pertenecería a la dirección de la persona que llama (ya que es una salida de una función de entrada). Hacer una transferencia explícita es más detallado, pero deja claro lo que está sucediendo (y nos permite hacer cualquier comprobación antes de liberar el objeto).
¿Por qué incluir la tienda en Parcel? Si Parcel carecía de la capacidad de almacenar (es decir, solo tenía una clave), la
Patrón de llamada a una función: Para usarlos en una transacción, el flujo sería:
1.**Depósito (transferencia al objeto) :**Llama a transfer: :public_transfer (parcel_obj, @warehouse_id) para enviar un paquete a un almacén. Esto marca al propietario del paquete como el almacén. (Aquí utilizamos public_transfer porque está fuera del módulo Parcel y Parcel tiene un almacén. Dentro del módulo del paquete, una simple transferencia también funcionaría).
2.
Tras la llamada a withdrawal _parcel, el propietario del paquete vuelve a su dirección (la suya), por lo que vuelve a ser un objeto propiedad de una dirección normal. El almacén ya no es su propietario.
Consideraciones relacionadas con varios módulos: Tenga en cuenta que el módulo de almacén necesitaba conocer el tipo de paquete (utilizamos demo: :parcel: :Parcel).
¿Por qué public_receive en lugar de simplemente llamar a receive? Si probáramos con transfer: :receive
No olvides el permiso de los padres: Incluso con public_receive, necesitarás ese &mut warehouse.id. Lo tenemos porque draw_parcel está en el módulo de Warehouse y acepta &mut Warehouse. Por lo tanto, solo alguien que pueda llamar a esa persona (el propietario del almacén) puede retirar el paquete. Si el módulo de almacén no proporcionara esta función de forma pública, tampoco se podría invocar externamente a public_receive en sus módulos secundarios. Por lo tanto, los módulos cruzados no eluden el control del padre; solo permiten que el código del padre funcione con elementos secundarios de tipos que no ha definido.
Nota sobre la posibilidad de almacenar objetos: Ofrecer un almacén de objetos hace que sea más flexible, pero un poco menos restringido: cualquier módulo que tenga la referencia principal puede extraerla usando public_receive. Si quieresrestringirla forma en que se recupera un objeto (por ejemplo, aplicar una lógica personalizada o impedir que se extraiga fácilmente), puedes hacer que sea solo con clave de forma deliberada. Veremos un ejemplo de ello con objetos ligados al alma. En esos casos, puedes implementar una función de recepción personalizada en lugar de confiar en public_receive.
Para resumir esta parte: public_receive es tu mejor opción para administrar objetos secundarios definidos en otros módulos, siempre que esos objetos tengan la capacidad de almacenamiento. Te permite crear sistemas multimodulares (como nuestro almacén/paquetería) sin dejar de respetar la propiedad y el control de acceso. Solo recuerda incluir los tipos secundarios de almacenamiento y usar public_transfer cuando los envíes a un padre desde fuera de su módulo.
- Sui
- Architecture
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
Gana tu parte de 1000 Sui
Gana puntos de reputación y obtén recompensas por ayudar a crecer a la comunidad de Sui.

- 0xduckmove... SUI+25
1
- MoonBags... SUI+20
2
- DRAMA... SUI+5
3
- ... SUI1 Luca+5
- ... SUIderiss+5
- ... SUIRamirez+5
- ... SUIElvin CLONE +5
- ... SUI
- ... SUI
- ... SUIHaGiang+3