Flipper: our first Coco program
In this example, we're going to go step by step from installing Coco compiler to writing, compiling and running a small logic.
The logic, called Flipper
demonstrates the use of Coco compiler and test environment Cocolab. The only tool that's needed for
the whole example is a coco
binary one can install as described in installation instructions.
Create module
Coco module is the basic source code that compiles to a manifest that can be deployed to MOI. It contains a coco.nut
file that serves as a configuration for module compilation, containing amonng other module name, output name, output options etc.
To create a module, first create a new folder, then run an nut init
command in it.
mkdir flipper
cd flipper
coco nut init Flipper
nut init
command creates a file coco.nut
in the current folder that specifies Flipper
as the module name, flipper.yaml
as the output
and PISA v0.5.0 in BIN format as the output. You can manually edit this file and most of the options in coco.nut
file can be overridden with coco
command options.
Write Coco code
Now let's write our first program. Coco module is a collection of all files in a folder with .coco
extension and with coco <module_name>
(in our example, coco Flipper
) in the first line of code. As our example is simple, we'll just create one file, called flipper.coco
:
coco Flipper
state logic:
values Map[Identifier]Bool
endpoint deploy Init():
mutate values <- Flipper.Logic.values:
values[Sender] = true
endpoint dynamic Flip():
mutate values <- Flipper.Logic.values:
values[Sender] = !values[Sender]
endpoint Mode() -> (value Bool):
observe values <- Flipper.Logic.values:
value = values[Sender]
endpoint dynamic Set(value Bool):
mutate values <- Flipper.Logic.values:
values[Sender] = value
Compiling with Coco is simple
coco compile
compile
command compiles the module, it uses all .coco files in the folder, compiles and produces the manifest, in our case flipper.yaml
.
Manifest is the logic that can be deployed on the blockchain, but coco
can also run it locally so you can test it before deployment.
Starting Cocolab
coco
binary also contains a tool that can execute the manifest, called Cocolab
. It's started with:
coco lab start
lab start
starts a REPL (Read-Eval-Print-Loop), an interactive environment where one can run and evaluate the program.
Before running anything, we need to create at least one user and declare it to be the default.sender
. You can use any
username (e.g. your own name), but we're using a generic default_user
name here.
register default_user
set default.sender default_user
To compile the manifest to local logic, we issue a compile
command:
compile Flipper from manifest(flipper.yaml)
As all of the above commands are repeated every time one starts Cocolab, there's also a shortcut, you can run Cocolab using init
and have a default_user
registered, set as default.sender
and the logic in the current folder (one in coco.nut
file) compiled.
coco lab init
Running Flipper in Cocolab
Once Flipper is compiled and we have a default_user
that acts as a default.sender
we can check if it works. In Cocolab, let's
check if we have the user and the logic:
users
and we should get a response like
default_user [0x199a5ef028fd0bf4b632f110edb498999211f5f1045493f5287269ad3ff23a04]
The identifier (a 32-byte hex code) will be different for everyone, but we should have at least one user.
logics
[0] Flipper [0x5c6801eadefac2187d3b04543ef59caf37d3eb3644cc69ec79eb6a683eb78af6]
again, the logic's identifier will be different, but Flipper
should be there.
Let's deploy
the logic first: every logic has to be deployed and only then we can invoke endpoints and check the data.
On blockchain, the logic can be deployed by passing the manifest, and at the time we can also perform
some initialization. This is done by invoking an endpoint that has deploy
qualifier. In our case, we have Init
endpoint.
deploy Flipper.Init()
This command initializes the logic, as our example was written, it writes some initial value true
into the values
field of the logic's state for the Sender
- i.e. the user (actor) that has deployed the logic.
So let's check the logic's state for this user.
observe Flipper.Logic.values[default_user]
We should get a response
true
Looks like deployment has worked and that state was set to true
.
Now, let's flip the value by invoking Flip
endpoint.
invoke Flipper.Flip()
and let's read the value not by directly observing the value as above (with observe
command in the REPL) but by invoking Mode
endpoint.
invoke Flipper.Mode()
The last line of the response should read
Execution Outputs ||| value:false
So, the returned data was value: false
, looke like Flipper works. Let's check if direct setting of the value using Set
endpoint works:
invoke Flipper.Set(value: true)
observe Flipper.Logic.values[default_user]
The value is true
, looks like Flipper works.
Now, let's register a new user and invoke the logic as this new user: their value should also work. First, register the user, wipe the current default.sender and set it to the new user, so invoke
commands will be sent as this new user.
register Robert
wipe default.sender
set default.sender Robert
invoke Flipper.Set(value: false)
invoke Flipper.Mode()
invoke Flipper.Flip()
observe Flipper.Logic.values[Robert]
The above should set the value for user Robert to false
, then flip it and it should be observed as true
.
Congratulations, your first Coco program works, you can leave Cocolab!
exit