Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(devx): edit iota-101 access-time.mdx and using-events.mdx #3646

Merged
merged 5 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 38 additions & 19 deletions docs/content/developer/iota-101/access-time.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,66 +2,85 @@
title: Access On-Chain Time
description: Access network-based time for your transactions. IOTA provides a Clock module to capture near-real time or epoch time in your IOTA packages.
---

import Quiz from '@site/src/components/Quiz';
import questions from '/json/developer/iota-101/access-time.json';

You have options when needing to access network-based time for your transactions. If you need a near real-time measurement (within a few seconds), use the immutable reference of time provided by the `Clock` module in Move. The reference value from this module updates with every network checkpoint. If you don't need as current a time slice, use the `epoch_timestamp_ms` function to capture the precise moment the current epoch started.
# Accessing On-Chain Time in IOTA

When you need to access network-based time for your transactions on IOTA, you have several options:

## The iota::clock::Clock Module
- **Near Real-Time Measurement**: Use the immutable reference of time provided by the [`Clock`](../../references/framework/iota-framework/clock.mdx) module in Move. This value updates with every network checkpoint.
- **Epoch Start Time**: Use the [`epoch_timestamp_ms`](../../references/framework/iota-framework/tx_context.mdx#function-epoch_timestamp_ms) function to capture the precise moment the current epoch started.

To access a prompt timestamp, you must pass a read-only reference of `iota::clock::Clock` as an entry function parameter in your transactions. An instance of `Clock` is provided at address `0x6`, no new instances can be created.
## Using the `iota::clock::Clock` Module

Use the `timestamp_ms` function from the `iota::clock` module to extract a unix timestamp in milliseconds.
To access a prompt timestamp, you can pass a read-only reference of [`iota::clock::Clock`](../../references/framework/iota-framework/clock.mdx) as an entry function parameter in your transactions.
An instance of `Clock` is provided at the address `0x6`, and no new instances can be created.

Use the [`timestamp_ms`](../../references/framework/iota-framework/clock.mdx#function-timestamp_ms) function from the `iota::clock` module to extract a Unix timestamp in milliseconds.

```move file=<rootDir>/crates/iota-framework/packages/iota-framework/sources/clock.move#L29-L33
```

The example below demonstrates an entry function that emits an event containing a timestamp from the `Clock`:
### Example: Emitting an Event with a Timestamp

The following example demonstrates an entry function that emits an event containing a timestamp from the `Clock`:

```move file=<rootDir>/examples/move/basics/sources/clock.move#L5-L15
```

A call to the previous entry function takes the following form, passing `0x6` as the address for the `Clock` parameter:
To call the previous entry function, pass `0x6` as the address for the `Clock` parameter:

```shell
iota client call --package <EXAMPLE> --module 'clock' --function 'access' --args '0x6'
```

Expect the `Clock` timestamp to change at the rate the network generates checkpoints, which is **every 1 second** with Narwhal/Bullshark consensus and **every 0.1 to 0.2 seconds** with Mysticeti consensus.
**Note**: The `Clock` timestamp changes at the rate the network generates checkpoints, which is **every 1 second** with Narwhal/Bullshark consensus and **every 0.1 to 0.2 seconds** with Mysticeti consensus.

Successive calls to `iota::clock::timestamp_ms` in the same transaction always produce the same result (transactions are considered to take effect instantly), but timestamps from `Clock` are otherwise monotonic across transactions that touch the same shared objects: Successive transactions seeing a greater or equal timestamp to their predecessors.
Successive calls to `iota::clock::timestamp_ms` within the same transaction will always produce the same result because transactions are considered to take effect instantly.
However, timestamps from `Clock` are monotonic across transactions that touch the same shared objects, meaning successive transactions see a greater or equal timestamp compared to their predecessors.

Any transaction that requires access to a `Clock` must go through consensus because the only available instance is a shared object. As a result, this technique is not suitable for transactions that must use the single-owner fastpath (see Epoch timestamps for a single-owner-compatible source of timestamps).
### Transaction Requirements

Transactions that use the clock must accept it as an **immutable reference** (not a mutable reference or value). This prevents contention, as transactions that access the `Clock` can only read it, so do not need to be sequenced relative to each other. Validators refuse to sign transactions that do not meet this requirement and packages that include entry functions that accept a `Clock` or `&mut Clock` fail to publish.
- **Consensus Requirement**: Any transaction that requires access to a `Clock` must go through consensus because the only available instance is a shared object.
- **Immutable Reference**: Transactions that use the clock must accept it as an **immutable reference** (`&Clock`), not as a mutable reference or value. This prevents contention, as transactions that access the `Clock` can only read it.

The following functions test `Clock`-dependent code by manually creating a `Clock` object and manipulating its timestamp. This is possible only in test code:
Validators will refuse to sign transactions that do not meet this requirement, and packages that include entry functions accepting a `Clock` or `&mut Clock` will fail to publish.

### Testing `Clock`-Dependent Code

The following functions allow you to test `Clock`-dependent code by manually creating a `Clock` object and manipulating its timestamp. This is possible only in test code:

```move file=<rootDir>/crates/iota-framework/packages/iota-framework/sources/clock.move#L65-L93
```

The next example presents a basic test that creates a Clock, increments it, and then checks its value:

Here's a basic test that creates a `Clock`, increments it, and then checks its value:

```move file=<rootDir>/crates/iota-framework/packages/iota-framework/tests/clock_tests.move#L6-L22
```

## Epoch Timestamps
## Using Epoch Timestamps

Use the following function from the `iota::tx_context` module to access the timestamp for the start of the current epoch for all transactions (including ones that do not go through consensus):
If you don't need a near real-time measurement,
you can use the [`epoch_timestamp_ms`](../../references/framework/iota-framework/tx_context.mdx#function-epoch_timestamp_ms) function
from the [`iota::tx_context`](../../references/framework/iota-framework/tx_context.mdx) module to access the timestamp for the start of the
current epoch. This function works for all transactions, including those that do not go through consensus:

```move file=<rootDir>/crates/iota-framework/packages/iota-framework/sources/tx_context.move#L54-L56
```

The preceding function returns the point in time when the current epoch started, as a millisecond granularity unix timestamp in a `u64`. This value changes roughly **once every 24 hours**, when the epoch changes.
The function returns the point in time when the current epoch started, as a Unix timestamp in milliseconds (`u64`).
This value changes roughly **once every 24 hours** when the epoch changes.

Tests based on `iota::test_scenario` can use `later_epoch` (following code), to exercise time-sensitive code that uses `epoch_timestamp_ms` (previous code):
### Testing Epoch-Sensitive Code

Tests based on [`iota::test_scenario`] can use `later_epoch` to exercise time-sensitive code that uses `epoch_timestamp_ms`:

```move file=<rootDir>/crates/iota-framework/packages/iota-framework/sources/test/test_scenario.move#L141-L148
```

`later_epoch` behaves like `iota::test_scenario::next_epoch` (finishes the current transaction and epoch in the test scenario), but also increments the timestamp by `delta_ms` milliseconds to simulate the progress of time.
The `later_epoch` function behaves like `iota::test_scenario::next_epoch` (finishes the current transaction and epoch in the test scenario)
but also increments the timestamp by `delta_ms` milliseconds to simulate the passage of time.

<Quiz questions={questions} />
<Quiz questions={questions} />
53 changes: 33 additions & 20 deletions docs/content/developer/iota-101/using-events.mdx
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
---
title: Using Events
description: Monitor IOTA on-chain activity by subscribing to events that Move packages published on IOTA emit.
description: Learn how to monitor IOTA on-chain activity by subscribing to events emitted by Move packages.
---
import AlphaNet from "../../_snippets/alphanet.mdx";
import Quiz from '@site/src/components/Quiz';
import questions from '/json/developer/iota-101/using-events.json';

The IOTA network stores countless objects on chain where Move code can perform actions using those objects. Tracking this activity is often desired, for example, to discover how many times a module mints an NFT or to tally the amount of IOTA in transactions that a smart contract generates.
# Subscribing to On-Chain Events in IOTA

To support activity monitoring, Move provides a structure to emit events on the IOTA network. When you establish a connection with the IOTA network, you create a two-way interactive communication session between your client and a IOTA network node. With an open session, you can subscribe to specific events that the IOTA network adds to the stream to create real-time monitoring of events.
Monitoring on-chain activity is essential for understanding and reacting to actions performed by smart contracts on the IOTA network.
By subscribing to events emitted by Move packages, you can track activities such as NFT minting or IOTA transactions in real-time.
This guide will show you how to emit events in Move and subscribe to them using the IOTA network.

## Move Event Structure
## Understanding Events in IOTA

Events in IOTA provide a structured way to capture and broadcast on-chain activities.
Each event contains specific attributes that offer detailed information about what occurred.

### Event Structure

An event object in IOTA consists of the following attributes:

Expand All @@ -23,23 +29,26 @@ An event object in IOTA consists of the following attributes:
- `bcs`: Binary canonical serialization value.
- `timestampMs`: Unix epoch timestamp in milliseconds.

## Discovering Events
## Exploring Available Events

If you want to subscribe to events on chain, you first need to know what events are available. You typically know or can discover the events your own code emits, but it's not as straightforward when you need to subscribe to on-chain events from packages you don't own. The IOTA RPC provides a [queryEvents](/iota-api-ref#iotax_queryevents) method to query on-chain packages and return available events that you can subscribe to.
To subscribe to on-chain events, you first need to identify which events are available. While you can easily track events emitted by your own code, discovering events from external packages can be more challenging. The IOTA RPC provides the [`queryEvents`](/iota-api-ref#iotax_queryevents) method, which allows you to query on-chain packages and obtain a list of events you can subscribe to.

## Filter Events
## Applying Event Filters

You can filter the events your code targets for either querying or subscribing. Both filter options are similar but have some differences.
When targeting specific events for querying or subscribing, you can use filters to refine your results. Although the filtering options for querying and subscribing are similar, there are notable differences to be aware of.

## Emit Events in Move
## Emitting Events in Move

To create an event in your Move modules, add the `iota::event` dependency.
To emit events from your Move modules, you need to use the [`iota::event`](../../references/framework/iota-framework/event.mdx) module.
Emitting events allows external applications to subscribe and respond to specific on-chain activities.

First, import the `event` module in your Move code:

```move
use iota::event;
```

With the dependency added, you can use the `emit` function to fire an event whenever the action you want to monitor fires. For example, the following code is part of an example application using digital donuts. The `collect_profits` function handles the collection of IOTA and emits an event whenever the function is called. To act on that event, you need to subscribe to it.
Then, within your function, you can emit an event using the [`emit`](../../references/framework/iota-framework/event.mdx#function-emit) function. For example:

```move
/// Take coin from `DonutShop` and transfer it to tx sender.
Expand All @@ -53,11 +62,12 @@ public fun collect_profits( _: &ShopOwnerCap, shop: &mut DonutShop, ctx: &mut Tx
}
```

## Subscribe to Events in Move
## Subscribing to Events

Firing events is not very useful in a vacuum. You also need the ability to listen for those events so that you can act on them. In IOTA, you subscribe to those events and provide logic that triggers when the event fires.
To react to events emitted by Move modules, you need to subscribe to them.
IOTA full nodes support event subscriptions via JSON-RPC notifications over WebSocket. You can interact with the [RPC directly][iotax_subscribeEvent](/iota-api-ref#iotax_subscribeevent), [iotax_subscribeTransaction](/iota-api-ref#iotax_subscribetransaction) or use an SDK like the [IOTA TypeScript SDK](../../references/ts-sdk/typescript/index.mdx).

IOTA Full nodes support subscribe functionality using JSON-RPC notifications transmitted through the WebSocket API. You can interact with the RPC directly ([iotax_subscribeEvent](/iota-api-ref#iotax_subscribeevent), [iotax_subscribeTransaction](/iota-api-ref#iotax_subscribetransaction)) or you can use an SDK like the IOTA TypeScript SDK. The following excerpt from one of the examples uses the TypeScript SDK to create an asynchronous subscription to the filter identified in the filter.
The following excerpt from one of the examples uses the TypeScript SDK to create an asynchronous subscription to the filter identified in the filter.

```move
let unsubscribe = await provider.subscribeEvent({
Expand Down Expand Up @@ -90,7 +100,7 @@ Move smart contracts can call other smart contracts that emit events. For exampl

## Examples

## Subscribe to Event
### Subscribe to Event

This example leverages the IOTA TypeScript SDK to subscribe to events the package with ID `<PACKAGE_ID>` emits. Each time the event fires, the code displays the response to the console.

Expand Down Expand Up @@ -192,16 +202,19 @@ subscribeEvent {
</TabItem>
</Tabs>

## Filtering Event Queries
## Filtering Events

To filter the events returned from your queries, use the following data structures.
You can filter events when querying or subscribing to receive only the events you are interested in.

:::info

This set of filters applies only to event querying APIs. It differs from the filters offered for the subscriptions API (see following section). In particular, it does not support combinations like `"All": [...]`, `"Any": [...]`, `"And": [_, _]`, `"Or": [_, _]`, and `"Not": _`.

:::

### Filtering Event Queries

When querying events, use the following filters:

| Query | Description | JSON-RPC Parameter Example |
| ------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
Expand All @@ -216,9 +229,9 @@ This set of filters applies only to event querying APIs. It differs from the fil
| `Object` | Return events associated with the given object | `{"Object":"0x727b37454ab13d5c1dbb22e8741bff72b145d1e660f71b275c01f24e7860e5e5"}` |
| `TimeRange` | Return events emitted in [start_time, end_time] interval | `{"TimeRange":{"startTime":1669039504014, "endTime":1669039604014}}` |

## Filtering Events for Subscription
### Filtering Events for Subscription

To create a subscription, you can set a filter to return only the set of events you're interested in listening for. Unlike filtering event queries, you are able to combine subscription filters.
When subscribing to events, you can combine filters for more precise results:

| Filter | Description | JSON-RPC Parameter Example |
| ----------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------ |
Expand Down
Loading