"access function" -> "main function"

This commit is contained in:
Christian Rinderknecht 2020-02-21 18:13:09 +01:00
parent f4d688df7b
commit feaf143209
6 changed files with 53 additions and 54 deletions

View File

@ -1,24 +1,24 @@
---
id: entrypoints-contracts
title: Access function and Entrypoints
title: Main function and Entrypoints
---
## Access Functions
A LIGO contract is made of a series of constant and function
declarations. Only functions having a special type can be called when
the contract is activated: we called them *access functions*. An
access function takes two parameters, the *contract parameter* and the
the contract is activated: we called them *main functions*. A main
function takes two parameters, the *contract parameter* and the
*on-chain storage*, and returns a pair made of a *list of operations*
and a (new) storage.
When the contract is originated, the initial value of the storage is
provided. When an access function is later called, only the parameter
is provided, but the type of an access function contains both.
provided. When a main function is later called, only the parameter is
provided, but the type of a main function contains both.
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
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
with any name for the storage.)
@ -42,13 +42,12 @@ type return = (list (operation), storage);
```
<!--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
*not* mean is that some global variable holding the storage is
modified by the access function. Instead, what it *does* mean is that,
given the state of the storage *on-chain*, an access function
specifies how to create another state for it, depending on a
parameter.
modified by the main function. Instead, what it *does* mean is that,
given the state of the storage *on-chain*, a main function specifies
how to create another state for it, depending on a parameter.
Here is an example where the storage is a single natural number that
is updated by the parameter.
@ -89,17 +88,18 @@ let main = ((action, store): (parameter, storage)) : return =>
## Entrypoints
In LIGO, the design pattern is to have *one* access function that
dispatches the control flow according to its parameter. Those
functions called for those actions are called *entrypoints*.
In LIGO, the design pattern is to have *one* main function called
`main`, that dispatches the control flow according to its
parameter. Those functions called for those actions are called
*entrypoints*.
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.
The parameter of the contract is then a variant type, and, depending
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
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
((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
Action_A (n) -> entry_A (n, 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 =
([] : operation list), {store with name = s}
let access (action, store: parameter * storage) : return =
let main (action, store: parameter * storage) : return =
match action with
Action_A n -> entry_A (n, 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 =>
(([] : list (operation)), {...store, name : s});
let access = ((action, store): (parameter, storage)) : return =>
let main = ((action, store): (parameter, storage)) : return =>
switch (action) {
| Action_A (n) => entry_A ((n, 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
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)
else ((nil : list(operation)), store)
```
@ -258,7 +258,7 @@ function filter (const action : parameter; const store : storage) : return is
```cameligo group=c
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)
else (([] : operation list), store)
```
@ -267,7 +267,7 @@ let filter (action, store: parameter * storage) : return =
```reasonligo group=c
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); }
else { (([] : list (operation)), store); };
};

View File

@ -11,13 +11,14 @@ We will be implementing a counter contract.
## Dry-running a Contract
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
execution, as if it were deployed on a real chain. You need to provide
the following:
run feature. Dry-run works by simulating the main function execution,
as if it were deployed on a real chain. You need to provide the
following:
- `file` - contract to run
- `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
Here is a full example:
@ -33,15 +34,15 @@ ligo dry-run src/basic.ligo main Unit Unit
```
<!--END_DOCUSAURUS_CODE_TABS-->
Output of the `dry-run` is the return value of our access function, we
can see the operations emited - in our case an empty list, and the new
storage value being returned - which in our case is still `Unit`.
Output of the `dry-run` is the return value of our main function, we
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`.
## A Counter Contract
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`
access function to two entrypoints for `addition` and `subtraction`.
function to two entrypoints for `addition` and `subtraction`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->

View File

@ -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.
> 💡 Lists are needed when returning operations from a smart
> contract's access function.
> contract's main function.
### Defining Lists

View File

@ -11,7 +11,7 @@ type return is list (operation) * taco_shop_storage
const ownerAddress : address = "tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV"
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 {
// Retrieve the taco_kind from the contract's storage or fail
const taco_kind : taco_supply =

View File

@ -8,7 +8,7 @@ type taco_shop_storage is map (nat, taco_supply)
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 {
// Retrieve the taco_kind from the contract's storage or fail
const taco_kind : taco_supply =

View File

@ -76,18 +76,18 @@ screenshot below:
<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>
## Implementing our first access function
## Implementing our First `main` Function
> 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
> [LIGO cheat sheet](api/cheat-sheet.md) for some extra tips & tricks.
To begin implementing our smart contract, we need an *access
function*, that is the first function being executed. We will call it
`main` and it will specify our contract's storage (`int`) and input
parameter (`int`). Of course this is not the final storage/parameter
of our contract, but it is something to get us started and test our
LIGO installation as well.
To begin implementing our smart contract, we need a *main function*,
that is the first function being executed. We will call it `main` and
it will specify our contract's storage (`int`) and input parameter
(`int`). Of course this is not the final storage/parameter of our
contract, but it is something to get us started and test our LIGO
installation as well.
### `taco-shop.ligo`
```pascaligo group=a
@ -99,7 +99,7 @@ list (operation) * int is
Let us break down the contract above to make sure we understand each
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
- **`(const parameter : int; const contractStorage : int)`** -
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:
- **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)*
- **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
storage value, which, in our case, is the sum of the previous storage
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)
```
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
`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
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
function with another, `buy_taco`, that takes a key `id` from our
`taco_shop_storage` map. This will allow us to calculate pricing, and
if the sale is successful, we will be able to reduce our stock because
we have sold a taco!
move on to the actual sales. The `main` function will take a key `id`
from our `taco_shop_storage` map. This will allow us to calculate
pricing, and if the sale is successful, we will be able to reduce our
stock because we have sold a taco!
### Selling the Tacos for Free
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`
- change `taco_shop_storage` to a `var` instead of a `const`, because
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
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)
```
@ -303,7 +301,7 @@ type taco_shop_storage is map (nat, taco_supply)
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 {
// Retrieve the taco_kind from the contract's storage or fail
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
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 {
// Retrieve the taco_kind from the contract's storage or fail
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`:
```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 [
current_stock = 50n;
max_price = 50tez