Skip to content

Commit

Permalink
docs: add example and tutorial (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
alegadea authored Aug 4, 2024
1 parent 494b542 commit 5980db8
Show file tree
Hide file tree
Showing 9 changed files with 694 additions and 1 deletion.
5 changes: 4 additions & 1 deletion docs/pages/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@
"layout": "full"
}
},
"introduction": "Introduction"
"introduction": "Introduction",
"nomenclature": "Nomenclature",
"events": "Events",
"order-book-example": "Order book example"
}
104 changes: 104 additions & 0 deletions docs/pages/events.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Events
We define the following events as available to a [bod](/nomenclature):

### Request event

Represent an external message sent directly to the _bod_ that is expecting a response. The mechanism used to relay the message is out-of-scope of the framework and it's a responsibility of the [crane](/nomenclature), but it's usually through an HTTP call.

A request handler will receive a parameter containing the specifics of the request (aka: body) and the output will be relayed as the response of the request.

The following snippet show a non-spec approach of how we could potentially connect message events onto handler functions:

```rust
#[on_request]
fn new_order(payload: OrderSpec) -> Result<Order> {}
```

### PubSub event

Represent an external message sent directly to the _bod_ that is NOT expecting a synchronous response. The mechanism used to relay the message is out-of-scope of the framework and it's a responsibility of the [crane](/nomenclature), but it's usually through a message queue.

A pubsub message is composed of two elements:

- `topic`: a arbitrary key that is used by the bod to discriminate between handlers of the event.
- `payload`: arbitrary, structured data with relevant information for the handler of the event.

The following snippet show a non-spec approach of how we could potentially connect message events onto handler functions:

```rust
#[on_message(topic="xyz")]
fn new_order(payload: OrderSpec) {}
```

### Chain event

Represent an event that occurred on-chain. The mechanism used to monitor the chain is out of scope and it's a responsability of the [crane](/nomenclature). Chain events are one-way, they don't expect any response.

Since on-chain data is quite complex, we need to define stereotypes for particular payloads relevant to dApps. We call these payloads _projections_.

We identify the following projections:

- Txs: a view of a self-contained Tx.
- UTxO: a view of a self-contained UTxO.
- Cert: a view of a self-container Certificate.

From these projections we can identify events that map to on-chain operations:

- A Tx is seen on-chain
- A Tx has been rolled-back
- An UTxO is produces by a Tx
- An UTxO is consumed by a Tx

From the above events we identify optional filters that can be used to narrow down specific operations:

- A Tx that consumes UTxOs from a specific address
- A Tx that produces UTxOs to a specific address
- A Tx that mints a specific token
- A Tx that burns a specific token
- A tx that consumes an UTxO holding a specific token
- A tx that produces an UTxO holding a specific token
- An UTxO that is being locked in a specific address
- An UTxO that is being unlocked from a specific address
- An UTxO that is being locked holding a specific token
- An UTxO that is being unlocked holding a specific token
- A certificate of a specific type

The following snippet show a non-spec approach of how we could potentially connect message events onto handler functions:

```rust
#[on_chain(address="addr1")]
fn my_handler(utxo: Utxo);

#[on_chain(address="stake1")]
fn my_handler(utxo: Utxo);

#[on_chain(address="addr1")]
fn my_handler(stxi: Stxi);

#[on_chain(holds="policy1xxx")]
fn my_handler(utxo: Utxo);

#[on_chain(holds="asset1xxx")]
fn my_handler(utxo: Utxo);

#[on_chain(mints="asset1xxx")]
fn my_handler(tx: Tx);

#[on_chain(burns="asset1xxx")]
fn my_handler(tx: Tx);

#[on_chain(certifies="Delegation")]
fn my_handler(cert: Cert);

#[on_chain(certifies="PoolRegistration")]
fn my_handler(cert: Cert);
```

### Timer event

A timer event is one that gets triggered automatically at specific intervals. The intervals are defined by the bod using cron syntax (eg: `0 15 * * *`).

```rust
#[on_timer(cron="0 15 * * *")]
fn my_handler(now: Instant);
```
8 changes: 8 additions & 0 deletions docs/pages/nomenclature.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Common nomenclature
Throughout the project, the following terms should be interpreted according the presented definition:

- Headless dApp: A software system integrated with a blockchain that is meant to be operated programmatically (through an API, without a frontend).
- Hollow: An SDK (Software Development Kit) for building headless dApps.
- Bod: an instance of a headless dapp built using Hollow (analogous to an Actor in the Actor Model)
- Crane: an execution runtime for hosting bods (headless dapps)

4 changes: 4 additions & 0 deletions docs/pages/order-book-example/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"tutorial": "Tutorial",
"event-spec": "Events"
}
53 changes: 53 additions & 0 deletions docs/pages/order-book-example/event-spec.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Attributes as events

## HTTP calls

- `extrinsic`

This attribute creates associates a function to an endpoint of the name of the function associated to attribute.

This examples creates an endpoint at the `<root>/resolve` path of the server and will validate the body of the request to match the type of the `ResolveOrderBody` struct.
```rust
#[extrinsic]
fn resolve(request: Request<ResolveOrderBody>) {}
```


- `on_http(method=<METHOD>, path=<PATH>)`

This attribute is associates a function to an HTTP request specified by METHOD and PATH. The body of the request if there is one can be specified by the type of the parameter associated to the body.
PATH can be *dynamic* as shown in the **Order Book** example.

```rust
#[on_http(method="POST", path=("/order"/ String))]
fn cancel(tx_out_ref: String, cancel_data: CancelOrderBody) {}
```

- The decorated function executes on a POST operation to a path like `/order/001117d7817713204579ba11f8f9584dd41ccc5deee05b79e867a18a876a3e09#0` and it extracts the dynamic path such that: `tx_out_ref` is `001117d7817713204579ba11f8f9584dd41ccc5deee05b79e867a18a876a3e09#0` and the body of the request is an instance of `CancelOrderBody` (similar to warp)
- First parameter of associated function is the query param and the second parameter is the validated body of the request. If a dynamic parameter doesn't exist, then its first parameter is the body of the request. If the body of the request is not important, then there is no body parameter.


## Chain event

- `match....(...)`

This attribute is associated to a function that executes based on the blockchain event is listening to. Let's explore `match_tx_variant`.


a) `match_tx_variant(type="address_eq", value="addr_...", details=true)`: It executes if there is a new transaction in the blockchain such that a UTxO is consumed from or created into the address passed in to the second parameter. With details as true, then the full transaction is sent as a parameter to the associated function.
b) `match_tx_variant(type="policy_eq", value="ae12...", details=false)`: It executes if there is a new transaction in the blockchain such that a UTxO is consumed or created and it involves a token with the policy id that matches the one specified by value. The associated function receives the base information of a transaction as a parameter given that details is fase

In the orderbook example:

```rust
#[match_tx_variant(type="address_eq",address_equal=ORDER_BOOK, details=true)]
fn on_order_book_change(tx: Transaction) {}
```
The fuction `on_order_book_change` executes when a transaction involving the address `ORDER_BOOK` is added to the blockchain. This transaction is received as the first parameter of the function and similarly to `Oura`, it will include the details of the transaction (input, output, etc.).


## Timer event

- `[on_timer(cron=<CRON>)]`

A function with this attribute will be executed at a time specified by cron. The format of `CRON` is [here](https://en.wikipedia.org/wiki/Cron). The associated function must have a parameter that accepts a date. This function will be called with the date it was called on.
Loading

0 comments on commit 5980db8

Please sign in to comment.