"access function" -> "main function"
This commit is contained in:
parent
f4d688df7b
commit
feaf143209
@ -1,24 +1,24 @@
|
|||||||
---
|
---
|
||||||
id: entrypoints-contracts
|
id: entrypoints-contracts
|
||||||
title: Access function and Entrypoints
|
title: Main function and Entrypoints
|
||||||
---
|
---
|
||||||
|
|
||||||
## Access Functions
|
## Access Functions
|
||||||
|
|
||||||
A LIGO contract is made of a series of constant and function
|
A LIGO contract is made of a series of constant and function
|
||||||
declarations. Only functions having a special type can be called when
|
declarations. Only functions having a special type can be called when
|
||||||
the contract is activated: we called them *access functions*. An
|
the contract is activated: we called them *main functions*. A main
|
||||||
access function takes two parameters, the *contract parameter* and the
|
function takes two parameters, the *contract parameter* and the
|
||||||
*on-chain storage*, and returns a pair made of a *list of operations*
|
*on-chain storage*, and returns a pair made of a *list of operations*
|
||||||
and a (new) storage.
|
and a (new) storage.
|
||||||
|
|
||||||
When the contract is originated, the initial value of the storage is
|
When the contract is originated, the initial value of the storage is
|
||||||
provided. When an access function is later called, only the parameter
|
provided. When a main function is later called, only the parameter is
|
||||||
is provided, but the type of an access function contains both.
|
provided, but the type of a main function contains both.
|
||||||
|
|
||||||
The type of the contract parameter and the storage are up to the
|
The type of the contract parameter and the storage are up to the
|
||||||
contract designer, but the type for list operations is not. The return
|
contract designer, but the type for list operations is not. The return
|
||||||
type of an access function is as follows, assuming that the type
|
type of a main function is as follows, assuming that the type
|
||||||
`storage` has been defined elsewhere. (Note that you can use any type
|
`storage` has been defined elsewhere. (Note that you can use any type
|
||||||
with any name for the storage.)
|
with any name for the storage.)
|
||||||
|
|
||||||
@ -42,13 +42,12 @@ type return = (list (operation), storage);
|
|||||||
```
|
```
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
The contract storage can only be modified by activating an access
|
The contract storage can only be modified by activating a main
|
||||||
function. It is important to understand what that means. What it does
|
function. It is important to understand what that means. What it does
|
||||||
*not* mean is that some global variable holding the storage is
|
*not* mean is that some global variable holding the storage is
|
||||||
modified by the access function. Instead, what it *does* mean is that,
|
modified by the main function. Instead, what it *does* mean is that,
|
||||||
given the state of the storage *on-chain*, an access function
|
given the state of the storage *on-chain*, a main function specifies
|
||||||
specifies how to create another state for it, depending on a
|
how to create another state for it, depending on a parameter.
|
||||||
parameter.
|
|
||||||
|
|
||||||
Here is an example where the storage is a single natural number that
|
Here is an example where the storage is a single natural number that
|
||||||
is updated by the parameter.
|
is updated by the parameter.
|
||||||
@ -89,17 +88,18 @@ let main = ((action, store): (parameter, storage)) : return =>
|
|||||||
|
|
||||||
## Entrypoints
|
## Entrypoints
|
||||||
|
|
||||||
In LIGO, the design pattern is to have *one* access function that
|
In LIGO, the design pattern is to have *one* main function called
|
||||||
dispatches the control flow according to its parameter. Those
|
`main`, that dispatches the control flow according to its
|
||||||
functions called for those actions are called *entrypoints*.
|
parameter. Those functions called for those actions are called
|
||||||
|
*entrypoints*.
|
||||||
|
|
||||||
As an analogy, in the C programming language, the `main` function is
|
As an analogy, in the C programming language, the `main` function is
|
||||||
the unique access function and any function called from it would be an
|
the unique main function and any function called from it would be an
|
||||||
entrypoint.
|
entrypoint.
|
||||||
|
|
||||||
The parameter of the contract is then a variant type, and, depending
|
The parameter of the contract is then a variant type, and, depending
|
||||||
on the constructors of that type, different functions in the contract
|
on the constructors of that type, different functions in the contract
|
||||||
are called. In other terms, the unique access function dispatches the
|
are called. In other terms, the unique main function dispatches the
|
||||||
control flow depending on a *pattern matching* on the contract
|
control flow depending on a *pattern matching* on the contract
|
||||||
parameter.
|
parameter.
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ function entry_A (const n : nat; const store : storage) : return is
|
|||||||
function entry_B (const s : string; const store : storage) : return is
|
function entry_B (const s : string; const store : storage) : return is
|
||||||
((nil : list (operation)), store with record [name = s])
|
((nil : list (operation)), store with record [name = s])
|
||||||
|
|
||||||
function access (const action : parameter; const store : storage): return is
|
function main (const action : parameter; const store : storage): return is
|
||||||
case action of
|
case action of
|
||||||
Action_A (n) -> entry_A (n, store)
|
Action_A (n) -> entry_A (n, store)
|
||||||
| Action_B (s) -> entry_B (s, store)
|
| Action_B (s) -> entry_B (s, store)
|
||||||
@ -154,7 +154,7 @@ let entry_A (n, store : nat * storage) : return =
|
|||||||
let entry_B (s, store : string * storage) : return =
|
let entry_B (s, store : string * storage) : return =
|
||||||
([] : operation list), {store with name = s}
|
([] : operation list), {store with name = s}
|
||||||
|
|
||||||
let access (action, store: parameter * storage) : return =
|
let main (action, store: parameter * storage) : return =
|
||||||
match action with
|
match action with
|
||||||
Action_A n -> entry_A (n, store)
|
Action_A n -> entry_A (n, store)
|
||||||
| Action_B s -> entry_B (s, store)
|
| Action_B s -> entry_B (s, store)
|
||||||
@ -179,7 +179,7 @@ let entry_A = ((n, store): (nat, storage)) : return =>
|
|||||||
let entry_B = ((s, store): (string, storage)) : return =>
|
let entry_B = ((s, store): (string, storage)) : return =>
|
||||||
(([] : list (operation)), {...store, name : s});
|
(([] : list (operation)), {...store, name : s});
|
||||||
|
|
||||||
let access = ((action, store): (parameter, storage)) : return =>
|
let main = ((action, store): (parameter, storage)) : return =>
|
||||||
switch (action) {
|
switch (action) {
|
||||||
| Action_A (n) => entry_A ((n, store))
|
| Action_A (n) => entry_A ((n, store))
|
||||||
| Action_B (s) => entry_B ((s, store))
|
| Action_B (s) => entry_B ((s, store))
|
||||||
@ -249,7 +249,7 @@ This example shows how `sender` or `source` can be used to deny access to an ent
|
|||||||
```pascaligo group=c
|
```pascaligo group=c
|
||||||
const owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
|
const owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
|
||||||
|
|
||||||
function filter (const action : parameter; const store : storage) : return is
|
function main (const action : parameter; const store : storage) : return is
|
||||||
if source =/= owner then (failwith ("Access denied.") : return)
|
if source =/= owner then (failwith ("Access denied.") : return)
|
||||||
else ((nil : list(operation)), store)
|
else ((nil : list(operation)), store)
|
||||||
```
|
```
|
||||||
@ -258,7 +258,7 @@ function filter (const action : parameter; const store : storage) : return is
|
|||||||
```cameligo group=c
|
```cameligo group=c
|
||||||
let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address)
|
let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address)
|
||||||
|
|
||||||
let filter (action, store: parameter * storage) : return =
|
let main (action, store: parameter * storage) : return =
|
||||||
if source <> owner then (failwith "Access denied." : return)
|
if source <> owner then (failwith "Access denied." : return)
|
||||||
else (([] : operation list), store)
|
else (([] : operation list), store)
|
||||||
```
|
```
|
||||||
@ -267,7 +267,7 @@ let filter (action, store: parameter * storage) : return =
|
|||||||
```reasonligo group=c
|
```reasonligo group=c
|
||||||
let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
|
let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
|
||||||
|
|
||||||
let access = ((action, store): (parameter, storage)) : storage => {
|
let main = ((action, store): (parameter, storage)) : storage => {
|
||||||
if (source != owner) { (failwith ("Access denied.") : return); }
|
if (source != owner) { (failwith ("Access denied.") : return); }
|
||||||
else { (([] : list (operation)), store); };
|
else { (([] : list (operation)), store); };
|
||||||
};
|
};
|
||||||
|
@ -11,13 +11,14 @@ We will be implementing a counter contract.
|
|||||||
## Dry-running a Contract
|
## Dry-running a Contract
|
||||||
|
|
||||||
Testing a contract can be quite easy if we utilize LIGO's built-in dry
|
Testing a contract can be quite easy if we utilize LIGO's built-in dry
|
||||||
run feature. Dry-run works by simulating the access function
|
run feature. Dry-run works by simulating the main function execution,
|
||||||
execution, as if it were deployed on a real chain. You need to provide
|
as if it were deployed on a real chain. You need to provide the
|
||||||
the following:
|
following:
|
||||||
|
|
||||||
- `file` - contract to run
|
- `file` - contract to run
|
||||||
- `entrypoint` - name of the function to execute
|
- `entrypoint` - name of the function to execute
|
||||||
- `parameter` - parameter passed to the access function (in a theoretical invocation operation)
|
- `parameter` - parameter passed to the main function (in a
|
||||||
|
theoretical invocation operation)
|
||||||
- `storage` - a mock storage value, as if it were stored on a real chain
|
- `storage` - a mock storage value, as if it were stored on a real chain
|
||||||
|
|
||||||
Here is a full example:
|
Here is a full example:
|
||||||
@ -33,15 +34,15 @@ ligo dry-run src/basic.ligo main Unit Unit
|
|||||||
```
|
```
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
Output of the `dry-run` is the return value of our access function, we
|
Output of the `dry-run` is the return value of our main function, we
|
||||||
can see the operations emited - in our case an empty list, and the new
|
can see the operations emitted (in our case an empty list, and the new
|
||||||
storage value being returned - which in our case is still `Unit`.
|
storage value being returned) which in our case is still `Unit`.
|
||||||
|
|
||||||
## A Counter Contract
|
## A Counter Contract
|
||||||
|
|
||||||
Our counter contract will store a single `int` as it's storage, and
|
Our counter contract will store a single `int` as it's storage, and
|
||||||
will accept an `action` variant in order to re-route our single `main`
|
will accept an `action` variant in order to re-route our single `main`
|
||||||
access function to two entrypoints for `addition` and `subtraction`.
|
function to two entrypoints for `addition` and `subtraction`.
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
|
@ -99,7 +99,7 @@ called the *head*, and the sub-list after the head is called the
|
|||||||
think of a list a *stack*, where the top is written on the left.
|
think of a list a *stack*, where the top is written on the left.
|
||||||
|
|
||||||
> 💡 Lists are needed when returning operations from a smart
|
> 💡 Lists are needed when returning operations from a smart
|
||||||
> contract's access function.
|
> contract's main function.
|
||||||
|
|
||||||
### Defining Lists
|
### Defining Lists
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ type return is list (operation) * taco_shop_storage
|
|||||||
const ownerAddress : address = "tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV"
|
const ownerAddress : address = "tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV"
|
||||||
const donationAddress : address = "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"
|
const donationAddress : address = "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"
|
||||||
|
|
||||||
function buy_taco (const taco_kind_index : nat; var taco_shop_storage : taco_shop_storage) : return is
|
function main (const taco_kind_index : nat; var taco_shop_storage : taco_shop_storage) : return is
|
||||||
block {
|
block {
|
||||||
// Retrieve the taco_kind from the contract's storage or fail
|
// Retrieve the taco_kind from the contract's storage or fail
|
||||||
const taco_kind : taco_supply =
|
const taco_kind : taco_supply =
|
||||||
|
@ -8,7 +8,7 @@ type taco_shop_storage is map (nat, taco_supply)
|
|||||||
|
|
||||||
type return is list (operation) * taco_shop_storage
|
type return is list (operation) * taco_shop_storage
|
||||||
|
|
||||||
function buy_taco (const taco_kind_index : nat ; var taco_shop_storage : taco_shop_storage) : return is
|
function main (const taco_kind_index : nat ; var taco_shop_storage : taco_shop_storage) : return is
|
||||||
block {
|
block {
|
||||||
// Retrieve the taco_kind from the contract's storage or fail
|
// Retrieve the taco_kind from the contract's storage or fail
|
||||||
const taco_kind : taco_supply =
|
const taco_kind : taco_supply =
|
||||||
|
@ -76,18 +76,18 @@ screenshot below:
|
|||||||
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/install-ligo.png" />
|
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/install-ligo.png" />
|
||||||
<div style="opacity: 0.7; text-align: center; font-size: 12px; margin-top:-24px;">Installing the <b>next</b> version of LIGO's CLI</div>
|
<div style="opacity: 0.7; text-align: center; font-size: 12px; margin-top:-24px;">Installing the <b>next</b> version of LIGO's CLI</div>
|
||||||
|
|
||||||
## Implementing our first access function
|
## Implementing our First `main` Function
|
||||||
|
|
||||||
> From now on we will get a bit more technical. If you run into
|
> From now on we will get a bit more technical. If you run into
|
||||||
> something we have not covered yet - please try checking out the
|
> something we have not covered yet - please try checking out the
|
||||||
> [LIGO cheat sheet](api/cheat-sheet.md) for some extra tips & tricks.
|
> [LIGO cheat sheet](api/cheat-sheet.md) for some extra tips & tricks.
|
||||||
|
|
||||||
To begin implementing our smart contract, we need an *access
|
To begin implementing our smart contract, we need a *main function*,
|
||||||
function*, that is the first function being executed. We will call it
|
that is the first function being executed. We will call it `main` and
|
||||||
`main` and it will specify our contract's storage (`int`) and input
|
it will specify our contract's storage (`int`) and input parameter
|
||||||
parameter (`int`). Of course this is not the final storage/parameter
|
(`int`). Of course this is not the final storage/parameter of our
|
||||||
of our contract, but it is something to get us started and test our
|
contract, but it is something to get us started and test our LIGO
|
||||||
LIGO installation as well.
|
installation as well.
|
||||||
|
|
||||||
### `taco-shop.ligo`
|
### `taco-shop.ligo`
|
||||||
```pascaligo group=a
|
```pascaligo group=a
|
||||||
@ -99,7 +99,7 @@ list (operation) * int is
|
|||||||
Let us break down the contract above to make sure we understand each
|
Let us break down the contract above to make sure we understand each
|
||||||
bit of the LIGO syntax:
|
bit of the LIGO syntax:
|
||||||
|
|
||||||
- **`function main`** - definition of the access function, which takes
|
- **`function main`** - definition of the main function, which takes
|
||||||
a the parameter of the contract and the storage
|
a the parameter of the contract and the storage
|
||||||
- **`(const parameter : int; const contractStorage : int)`** -
|
- **`(const parameter : int; const contractStorage : int)`** -
|
||||||
parameters passed to the function: the first is called `parameter`
|
parameters passed to the function: the first is called `parameter`
|
||||||
@ -129,11 +129,11 @@ also an `int`.
|
|||||||
|
|
||||||
The `dry-run` command requires a few parameters:
|
The `dry-run` command requires a few parameters:
|
||||||
- **contract** *(file path)*
|
- **contract** *(file path)*
|
||||||
- **entrypoint** *(name of the access function in the contract)*
|
- **entrypoint** *(name of the main function in the contract)*
|
||||||
- **parameter** *(parameter to execute our contract with)*
|
- **parameter** *(parameter to execute our contract with)*
|
||||||
- **storage** *(starting storage before our contract's code is executed)*
|
- **storage** *(starting storage before our contract's code is executed)*
|
||||||
|
|
||||||
It outputs what is returned from our access function: in our case a
|
It outputs what is returned from our main function: in our case a
|
||||||
tuple containing an empty list (of operations to apply) and the new
|
tuple containing an empty list (of operations to apply) and the new
|
||||||
storage value, which, in our case, is the sum of the previous storage
|
storage value, which, in our case, is the sum of the previous storage
|
||||||
and the parameter we have used for the invocation.
|
and the parameter we have used for the invocation.
|
||||||
@ -176,7 +176,7 @@ type taco_supply is record [
|
|||||||
type taco_shop_storage is map (nat, taco_supply)
|
type taco_shop_storage is map (nat, taco_supply)
|
||||||
```
|
```
|
||||||
|
|
||||||
Next step is to update the `main` access function to include
|
Next step is to update the `main` function to include
|
||||||
`taco_shop_storage` in its storage. In the meanwhile, let us set the
|
`taco_shop_storage` in its storage. In the meanwhile, let us set the
|
||||||
`parameter` to `unit` as well to clear things up.
|
`parameter` to `unit` as well to clear things up.
|
||||||
|
|
||||||
@ -249,17 +249,15 @@ ligo dry-run taco-shop.ligo --syntax pascaligo main unit "map [
|
|||||||
## Providing another Access Function for Buying Tacos
|
## Providing another Access Function for Buying Tacos
|
||||||
|
|
||||||
Now that we have our stock well defined in form of storage, we can
|
Now that we have our stock well defined in form of storage, we can
|
||||||
move on to the actual sales. We will replace the `main` access
|
move on to the actual sales. The `main` function will take a key `id`
|
||||||
function with another, `buy_taco`, that takes a key `id` from our
|
from our `taco_shop_storage` map. This will allow us to calculate
|
||||||
`taco_shop_storage` map. This will allow us to calculate pricing, and
|
pricing, and if the sale is successful, we will be able to reduce our
|
||||||
if the sale is successful, we will be able to reduce our stock because
|
stock because we have sold a taco!
|
||||||
we have sold a taco!
|
|
||||||
|
|
||||||
### Selling the Tacos for Free
|
### Selling the Tacos for Free
|
||||||
|
|
||||||
Let is start by customizing our contract a bit, we will:
|
Let is start by customizing our contract a bit, we will:
|
||||||
|
|
||||||
- rename the access function from `main` to `buy_taco`
|
|
||||||
- rename `parameter` to `taco_kind_index`
|
- rename `parameter` to `taco_kind_index`
|
||||||
- change `taco_shop_storage` to a `var` instead of a `const`, because
|
- change `taco_shop_storage` to a `var` instead of a `const`, because
|
||||||
we will want to modify it
|
we will want to modify it
|
||||||
@ -275,7 +273,7 @@ type taco_shop_storage is map (nat, taco_supply)
|
|||||||
|
|
||||||
type return is list (operation) * taco_shop_storage
|
type return is list (operation) * taco_shop_storage
|
||||||
|
|
||||||
function buy_taco (const taco_kind_index : nat; var taco_shop_storage : taco_shop_storage) : return is
|
function main (const taco_kind_index : nat; var taco_shop_storage : taco_shop_storage) : return is
|
||||||
((nil : list (operation)), taco_shop_storage)
|
((nil : list (operation)), taco_shop_storage)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -303,7 +301,7 @@ type taco_shop_storage is map (nat, taco_supply)
|
|||||||
|
|
||||||
type return is list (operation) * taco_shop_storage
|
type return is list (operation) * taco_shop_storage
|
||||||
|
|
||||||
function buy_taco (const taco_kind_index : nat; var taco_shop_storage : taco_shop_storage) : return is
|
function main (const taco_kind_index : nat; var taco_shop_storage : taco_shop_storage) : return is
|
||||||
block {
|
block {
|
||||||
// Retrieve the taco_kind from the contract's storage or fail
|
// Retrieve the taco_kind from the contract's storage or fail
|
||||||
const taco_kind : taco_supply =
|
const taco_kind : taco_supply =
|
||||||
@ -352,7 +350,7 @@ type taco_shop_storage is map (nat, taco_supply)
|
|||||||
|
|
||||||
type return is list (operation) * taco_shop_storage
|
type return is list (operation) * taco_shop_storage
|
||||||
|
|
||||||
function buy_taco (const taco_kind_index : nat ; var taco_shop_storage : taco_shop_storage) : return is
|
function main (const taco_kind_index : nat ; var taco_shop_storage : taco_shop_storage) : return is
|
||||||
block {
|
block {
|
||||||
// Retrieve the taco_kind from the contract's storage or fail
|
// Retrieve the taco_kind from the contract's storage or fail
|
||||||
const taco_kind : taco_supply =
|
const taco_kind : taco_supply =
|
||||||
@ -381,7 +379,7 @@ In order to test the `amount` sent, we will use the `--amount` option
|
|||||||
of `dry-run`:
|
of `dry-run`:
|
||||||
|
|
||||||
```zsh
|
```zsh
|
||||||
ligo dry-run taco-shop.ligo --syntax pascaligo --amount 1 buy_taco 1n "map [
|
ligo dry-run taco-shop.ligo --syntax pascaligo --amount 1 main 1n "map [
|
||||||
1n -> record [
|
1n -> record [
|
||||||
current_stock = 50n;
|
current_stock = 50n;
|
||||||
max_price = 50tez
|
max_price = 50tez
|
||||||
|
Loading…
Reference in New Issue
Block a user