-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add example and tutorial (#18)
- Loading branch information
Showing
9 changed files
with
694 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"tutorial": "Tutorial", | ||
"event-spec": "Events" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
Oops, something went wrong.