Skip to content

Commit

Permalink
content and snippets
Browse files Browse the repository at this point in the history
  • Loading branch information
ronny-mysten committed Oct 25, 2023
1 parent 40601c0 commit 85b325f
Show file tree
Hide file tree
Showing 259 changed files with 16,571 additions and 592 deletions.
193 changes: 184 additions & 9 deletions docs/content/concepts/dynamic-fields/dynamic-object-fields.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,195 @@
title: Dynamic Object Fields
---

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Scelerisque fermentum dui faucibus in ornare. Ut tristique et egestas quis ipsum suspendisse. Ac placerat vestibulum lectus mauris ultrices eros. Lorem ipsum dolor sit amet. Justo nec ultrices dui sapien eget mi proin sed libero. Nunc lobortis mattis aliquam faucibus. Nec ultrices dui sapien eget mi proin sed. Tellus elementum sagittis vitae et. Tellus at urna condimentum mattis pellentesque id nibh tortor. Sit amet venenatis urna cursus. Imperdiet sed euismod nisi porta lorem mollis aliquam ut. Malesuada fames ac turpis egestas maecenas pharetra convallis posuere.
There are various ways to use object fields to store primitive data and other objects (wrapping), but there are a few limitations to these:

## Vel orci
1. Object's have a finite set of fields keyed by identifiers that are fixed when you publish its module (limited to the fields in the `struct` declaration).
2. An object can become very large if it wraps several other objects. Larger objects can lead to higher gas fees in transactions. In addition, there is an upper bound on object size.
3. There are use cases where you need to store a collection of objects of heterogeneous types. Because the Move `vector` type must be instantiated with one single type `<T>`, it is not suitable for this.

Vel orci porta non pulvinar neque laoreet suspendisse interdum. Gravida rutrum quisque non tellus orci ac. Odio ut sem nulla pharetra diam. Ipsum consequat nisl vel pretium lectus quam id. Vitae justo eget magna fermentum iaculis eu non diam. Est ultricies integer quis auctor elit sed vulputate mi. Vulputate enim nulla aliquet porttitor lacus luctus accumsan. Aliquet risus feugiat in ante metus dictum at tempor. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare. In fermentum et sollicitudin ac orci phasellus egestas. Morbi tristique senectus et netus et malesuada fames. Eros in cursus turpis massa tincidunt dui ut ornare. Id porta nibh venenatis cras sed felis eget. Sem et tortor consequat id porta nibh. Tempus egestas sed sed risus pretium quam. Vitae tempus quam pellentesque nec nam aliquam. Scelerisque varius morbi enim nunc faucibus a pellentesque. Ut pharetra sit amet aliquam id diam maecenas.
Fortunately, Sui provides *dynamic fields* with arbitrary names (not just identifiers), added and removed on-the-fly (not fixed at publish), which only affect gas when they are accessed, and can store heterogeneous values. Use the libraries in this topic to interact with this kind of field.

## Nunc mi ipsum
### Fields versus object fields

Nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit. Id venenatis a condimentum vitae. Porta lorem mollis aliquam ut. Ornare suspendisse sed nisi lacus sed. Purus ut faucibus pulvinar elementum integer enim. Egestas integer eget aliquet nibh praesent tristique magna sit. Massa tempor nec feugiat nisl pretium fusce id velit. Integer malesuada nunc vel risus commodo viverra maecenas accumsan. Mi proin sed libero enim. Nunc sed id semper risus in. Pretium vulputate sapien nec sagittis aliquam malesuada. Duis tristique sollicitudin nibh sit amet. Tincidunt praesent semper feugiat nibh sed pulvinar proin gravida hendrerit. Purus gravida quis blandit turpis cursus in hac habitasse. Lacus sed viverra tellus in hac habitasse platea dictumst vestibulum. A scelerisque purus semper eget duis at tellus at. Vitae tempus quam pellentesque nec nam. Id eu nisl nunc mi ipsum faucibus vitae aliquet.
There are two flavors of dynamic field -- "fields" and "object fields" -- which differ based on how you store their values:

## Dis parturient montes
- **Fields** can store any value that has `store`, however an object stored in this kind of field is considered wrapped and is not accessible via its ID by external tools (explorers, wallets, and so on) accessing storage.
- **Object field** values must be objects (have the `key` ability, and `id: UID` as the first field), but are still accessible at their ID to external tools.

Dis parturient montes nascetur ridiculus. Aliquam malesuada bibendum arcu vitae elementum curabitur vitae nunc sed. Adipiscing elit pellentesque habitant morbi. Enim diam vulputate ut pharetra. Feugiat pretium nibh ipsum consequat. Ullamcorper morbi tincidunt ornare massa. Malesuada fames ac turpis egestas integer eget aliquet nibh. Ac turpis egestas integer eget aliquet nibh. Consequat mauris nunc congue nisi. Vitae semper quis lectus nulla at volutpat diam ut. Risus quis varius quam quisque id diam vel. Massa tempor nec feugiat nisl pretium fusce. Fringilla phasellus faucibus scelerisque eleifend donec pretium vulputate. Mollis aliquam ut porttitor leo a diam sollicitudin tempor id.
The modules for interacting with these fields can be found at [`dynamic_field`](https://github.com/MystenLabs/sui/tree/main/crates/sui-framework/packages/sui-framework/sources/dynamic_field.move) and [`dynamic_object_field`](https://github.com/MystenLabs/sui/tree/main/crates/sui-framework/packages/sui-framework/sources/dynamic_object_field.move) respectively.

## Augue mauris
### Field names

Augue mauris augue neque gravida in fermentum et sollicitudin ac. Augue eget arcu dictum varius. Maecenas volutpat blandit aliquam etiam erat velit scelerisque. Mi ipsum faucibus vitae aliquet nec. Eros donec ac odio tempor orci. Tellus molestie nunc non blandit massa enim nec dui nunc. Nullam vehicula ipsum a arcu cursus vitae congue mauris. Curabitur gravida arcu ac tortor dignissim convallis aenean et. Varius sit amet mattis vulputate enim nulla aliquet porttitor. Amet purus gravida quis blandit turpis. Non sodales neque sodales ut etiam sit. Fermentum iaculis eu non diam phasellus vestibulum lorem. Cras adipiscing enim eu turpis egestas. Ac feugiat sed lectus vestibulum mattis ullamcorper velit. Elit duis tristique sollicitudin nibh.
Unlike an object's regular fields where names must be Move identifiers, dynamic field names can be any value that has `copy`, `drop`, and `store`. This includes all Move primitives (integers, Booleans, byte strings), and structs whose contents all have `copy`, `drop`, and `store`.

### Adding dynamic fields

Add dynamic fields with the following APIs:

```rust
module sui::dynamic_field {

public fun add<Name: copy + drop + store, Value: store>(
object: &mut UID,
name: Name,
value: Value,
);

}
```

```rust
module sui::dynamic_object_field {

public fun add<Name: copy + drop + store, Value: key + store>(
object: &mut UID,
name: Name,
value: Value,
);

}
```

These functions add a field with name `name` and value `value` to `object`. To see it in action, consider these code snippets:

First, define two object types for the parent and the child:

```rust
struct Parent has key {
id: UID,
}

struct Child has key, store {
id: UID,
count: u64,
}
```

Next, define an API to add a `Child` object as a dynamic field of a `Parent` object:

```rust
use sui::dynamic_object_field as ofield;

public fun add_child(parent: &mut Parent, child: Child) {
ofield::add(&mut parent.id, b"child", child);
}
```

This function takes the `Child` object by value and makes it a dynamic field of `parent` with name `b"child"` (a byte string of type `vector<u8>`). This call results in the following ownership relationship:

1. Sender address (still) owns the `Parent` object.
2. The `Parent` object owns the `Child` object, and can refer to it by the name `b"child"`.

It is an error to overwrite a field (attempt to add a field with the same `<Name>` type and value as one that is already defined), and a transaction that does this fails. You can modify fields in-place by borrowing them mutably and you can overwrite them safely (such as to change its value type) by removing the old value first.

### Accessing dynamic fields

You can reference dynamic fields by reference using the following APIs:

```rust
module sui::dynamic_field {

public fun borrow<Name: copy + drop + store, Value: store>(
object: &UID,
name: Name,
): &Value;

public fun borrow_mut<Name: copy + drop + store, Value: store>(
object: &mut UID,
name: Name,
): &mut Value;

}
```

Where `object` is the UID of the object the field is defined on and `name` is the field's name.

:::info

`sui::dynamic_object_field` has equivalent functions for object fields, but with the added constraint `Value: key + store`.

:::

To use these APIs with the `Parent` and `Child` types defined earlier:

```rust
use sui::dynamic_object_field as ofield;

public fun mutate_child(child: &mut Child) {
child.count = child.count + 1;
}

public fun mutate_child_via_parent(parent: &mut Parent) {
mutate_child(ofield::borrow_mut(
&mut parent.id,
b"child",
));
}
```

The first function accepts a mutable reference to the `Child` object directly, and you can call it with `Child` objects that haven't been added as fields to `Parent` objects.

The second function accepts a mutable reference to the `Parent` object and accesses its dynamic field using `borrow_mut`, to pass to `mutate_child`. This can only be called on `Parent` objects that have a `b"child"` field defined. A `Child` object that has been added to a `Parent` *must* be accessed via its dynamic field, so it can only by mutated using `mutate_child_via_parent`, not `mutate_child`, even if its ID is known.

:::tip

A transaction fails if it attempts to borrow a field that does not exist.

:::

The `<Value>` type passed to `borrow` and `borrow_mut` must match the type of the stored field, or the transaction aborts.

You must access dynamic object field values through these APIs. A transaction that attempts to use those objects as inputs (by value or by reference), is rejected for having invalid inputs.

### Removing a dynamic field

Similar to unwrapping an object held in a regular field, you can remove a dynamic field, exposing its value:

```rust
module sui::dynamic_field {

public fun remove<Name: copy + drop + store, Value: store>(
object: &mut UID,
name: Name,
): Value;

}
```

This function takes a mutable reference to the ID of the `object` the field is defined on, and the field's `name`. If a field with a `value: Value` is defined on `object` at `name`, it is removed and `value` returned, otherwise it aborts. Future attempts to access this field on `object` will fail.

:::tip

`sui::dynamic_object_field` has an equivalent function for object fields.

:::

The value that is returned can be interacted with just like any other value (because it is any other value). For example, removed dynamic object field values can then be `delete`-d or `transfer`-ed to an address (back to the sender):

```rust
use sui::dynamic_object_field as ofield;
use sui::{object, transfer, tx_context};
use sui::tx_context::TxContext;

public fun delete_child(parent: &mut Parent) {
let Child { id, count: _ } = reclaim_child(parent);

object::delete(id);
}

public fun reclaim_child(parent: &mut Parent, ctx: &mut TxContext): Child {
ofield::remove(
&mut parent.id,
b"child",
);

}
```

Similar to borrowing a field, a transaction that attempts to remove a non-existent field, or a field with a different `Value` type, fails.

### Deleting an object with dynamic fields

It is possible to delete an object that has (potentially non-`drop`) dynamic fields still defined on it. Because field values can be accessed only via the dynamic field's associated object and field name, deleting an object that has dynamic fields still defined on it renders them all inaccessible to future transactions. This is true regardless of whether the field's value has the `drop` ability. This might not be a concern when adding a small number of statically known additional fields to an object, but is particularly undesirable for on-chain collection types that could be holding unboundedly many key-value pairs as dynamic fields.

Sui provides `Table` and `Bag` collections built using dynamic fields, but with additional support to count the number of entries they contain to protect against accidental deletion when non-empty. To learn more, see [Tables and Bags](./tables-bags.mdx).
Loading

0 comments on commit 85b325f

Please sign in to comment.