I tested Tezos Part. 2
Following our first part that you can find here: https://medium.com/p/b254504775be
In this story we’re going to see how Tezos’ smart contracts work and which language is being used to code them.
Github : https://github.com/chainaccelerator/auction
Setting up Sandbox Node for Emacs mode
Go to your tezos folder:
chainacc@tezos:~$ cd tezos/
In your terminal, type the following line to locally start a tezos-node in sandbox node:
chainacc@tezos:~/tezos$ ./src/bin_node/tezos-sandboxed-node.sh 1 --connections 1
Which should give something like:
Generating a new identity... (level: 0.00)
Stored the new identity (idrMVR5dNmsviQiKS4175fGmkCKX3J) into '/tmp/tezos-node.PfMXk8J7/identity.json'.
Apr 24 02:26:54 - node.main: Starting the Tezos node...
Apr 24 02:26:54 - node.main: No local peer discovery.
Apr 24 02:26:54 - node.main: Peer's global id: idrMVR5dNmsviQiKS4175fGmkCKX3J
Apr 24 02:26:54 - node.worker: bootstrapping chain...
Apr 24 02:26:54 - validator.block: Worker started
Apr 24 02:26:54 - validation_process.sequential: Intialized
Apr 24 02:26:54 - node.validator: activate chain NetXgtSLGNJvNye
Apr 24 02:26:54 - validator.chain(1): Worker started for NetXgtSLGNJvN
Apr 24 02:26:54 - node.chain_validator: no prevalidator filter found for protocol 'Ps6mwMrF2ER2'
Apr 24 02:26:54 - prevalidator.NetXgtSLGNJvN.Ps6mwMrF2ER2(1): Worker started for NetXgtSLGNJvN.Ps6mwMrF2ER2
Apr 24 02:26:54 - node.main: Starting a RPC server listening on ::ffff:127.0.0.1:18731.
Apr 24 02:26:54 - node.main: The Tezos node is now running!
You can now type the following command in another terminal (make sure to be in the tezos/ folder as well):
chainacc@tezos:~/tezos$ eval `./src/bin_client/tezos-init-sandboxed-client.sh 1`
Which should give you something similar to:
Warning:
The node you are connecting to claims to be running in a
Tezos TEST SANDBOX.
Do NOT use your fundraiser keys on this network.
You should not see this message if you are not a developer.## Tezos address added: tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx
Warning:
The node you are connecting to claims to be running in a
Tezos TEST SANDBOX.
Do NOT use your fundraiser keys on this network.
You should not see this message if you are not a developer.## Tezos address added: tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN
Warning:
The node you are connecting to claims to be running in a
Tezos TEST SANDBOX.
Do NOT use your fundraiser keys on this network.
You should not see this message if you are not a developer.## Tezos address added: tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU
Warning:
The node you are connecting to claims to be running in a
Tezos TEST SANDBOX.
Do NOT use your fundraiser keys on this network.
You should not see this message if you are not a developer.## Tezos address added: tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv
Warning:
The node you are connecting to claims to be running in a
Tezos TEST SANDBOX.
Do NOT use your fundraiser keys on this network.
You should not see this message if you are not a developer.## Tezos address added: tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv
Warning:
The node you are connecting to claims to be running in a
Tezos TEST SANDBOX.
Do NOT use your fundraiser keys on this network.
You should not see this message if you are not a developer.## Tezos address added: tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV
##
## The client is now properly initialized. In the rest of this shell
## session, you might now run `tezos-client` to communicate with a
## tezos node launched with `launch-sandboxed-node 1`. For instance:
##
## tezos-client rpc get /chains/main/blocks/head/metadata
##
## Note: if the current protocol version, as reported by the previous
## command, is "Ps6mwMrF2ER2s51cp9yYpjDcuzQjsc2yAz8bQsRgdaRxw4Fk95H", you
## may have to activate in your "sandboxed network" the same economic
## protocol as used by the alphanet by running:
##
## tezos-activate-alpha
##
## Warning: all the client data will be removed when you close this shell
## or if you run this command a second time.
##
## Activate tab completion by running:
##
## tezos-autocomplete
##
And now, go ahead and type:
chainacc@tezos:~/tezos$ tezos-activate-alpha
Result:
Warning:
The node you are connecting to claims to be running in a
Tezos TEST SANDBOX.
Do NOT use your fundraiser keys on this network.
You should not see this message if you are not a developer.Injected BKtCW7cDf8N4
Finally, you can type a last command:
chainacc@tezos:~/tezos$ tezos-autocomplete
We’re almost done, we now need to setup emacs, which should already be installed. Open your .emacs
file:
chainacc@tezos:~/tezos$ emacs ~/.emacs
And add the following lines to it:
Save and close emacs, and restart it. Once it’s restarted, simply do Alt + X
, write package-install
and hit enter. Now, install the deferred
and exec-path-from-shell
packages like this:
And hit enter for both of them. It should install them.
One more thing and we’re done. Open your .emacs
file and add this to the bottom:
(load “~/tezos/emacs/michelson-mode.el” nil t)
(setq michelson-client-command “tezos-client”)
(setq michelson-alphanet nil)
Be careful, if you copy and paste the above 3 lines, make sure to re-write the "
each time. Just remove them when you paste it, and replace them by your own "
.
Your .emacs
file should now look like this:
You can now save and close emacs.
The michelson-mode
is now activated, but you must open emacs on the same terminal you’ve been using to setup everything.
Michelson
Before we actually get to code, let’s first introduce Michelson using Tezos’ words.
Michelson is the smart contract language of the Tezos blockchain. It is stack-based, meaning that computation is performed by mutating a sequence of data elements (the stack) according to some sequence of instructions (the program). Basically, our program will act on the stack and modify it according to our instructions.
For more information about Michelson, please refer to this link: http://tezos.gitlab.io/alphanet/whitedoc/michelson.html
Hello Medium
Let’s kick things off by opening emacs in the SAME terminal, and create a file named helloMedium.tz, like this:
chainacc@tezos:~/tezos$ emacs helloMedium.tz
And let’s type the following code in it:
And save the file.
michelson-mode
Let’s see how to use the michelson-mode
with an example. On emacs, place your cursor on the letter R of the PAIR
instruction, and you should see this:
If you take a look down your emacs, you will see the michelson-mode. Basically, it represents the state of the stack at two different moments. On the left, you can see the stack BEFORE the PAIR
instruction, containing a (list operation)
and a string
. On the right, you can see the stack AFTER the PAIR
instruction, containing a (pair)
of (list operation)
and string
.
That’s basically how you can use the michelson-mode
on emacs. Place your cursor on an instruction and see what it does to the stack.
Running the program
Let’s first check if our script is well-typed, by asking the alphanet node:
chainacc@tezos:~/tezos$ tezos-client typecheck script helloMedium.tz
which should give you this:
Warning:
The node you are connecting to claims to be running in a
Tezos TEST SANDBOX.
Do NOT use your fundraiser keys on this network.
You should not see this message if you are not a developer.Well typed
Gas remaining: 399813 units remining
If it doesn’t typecheck well, it means that either the code isn’t right, or that there have been breaking changes to the Michelson semantics since this tutorial.
To run a Michelson program in a sandbox, you have to use the following command:
chainacc@tezos:~/tezos$ tezos-client run script <path> on storage <data> and input <data>where:
<path> is the path to the .tz file
<data> is some Michelson value
Let’s adapt this command to run our own script:
chainacc@tezos:~/tezos$ tezos-client run script helloMedium.tz on storage '""' and input Unit
And here is our result:
storage
"Hello Medium!"
emitted operations
Hey, we’ve just run our first smart contract in Michelson. I’m proud of us! ;)
Taking a deeper look at the code
Before taking a look at how the code works, here are some VERY important explanations on how the contract works:
All Michelson smart contracts are functions that take two arguments, an input parameter and a storage value, and return a pair of a list of network operations and a storage value. The storage value is effectively a return value, and the list of network operations are the effects (such as a transaction, delegation or new contract creation) the contract will emit onto the Tezos network. You can think of a contract’s return value as the pair of how the contract mutates the global blockchain state and how the contract mutates its own state.
There are many different ways to notate types signatures but here’s what the Michelson type signature of a contract looks like:
lambda (pair 'parameter 'storage) (pair (list operation) 'storage)
The first two lines of our helloMedium.tz
program are here to specify the types of the contract’s two arguments, meaning that we can adapt the above line to this:
lambda (pair unit string) (pair (list operation) string)
Now that we know that, we can take a deeper look at our code. When we first run the code, our stack contains one element: the (pair unit string)
which is a pair of our two arguments (unit
and string
).
When we used the following command to run our program:
chainacc@tezos:~/tezos$ tezos-client run script helloMedium.tz on storage '""' and input Unit
We told our program to use an empty string for the storage argument (""
) and Unit
as the data constructor of the unit
type. So when we first start, our stack contains one element: (Pair Unit "")
and its type is (pair unit string)
.
Pair
is a data constructor and pair
is a type. In Michelson, data constructors start with a capital, whereas types are lowercase.
Now that we know our initial stack, let’s go through our code’s instructions:
DROP
Removes the top element of the stack. Meaning that it will remove our pair of arguments, making the stack empty after this instruction.
PUSH
Adds a value with a certain type onto the top of the stack. In our case, the value is “Hello Medium!” and its type is string
.
NIL
Adds an empty list of a certain type onto the top of the stack. In our case, it adds an empty list of operation
. We do this because we have to return a pair containing a list of operation and a storage value. Here, our list of operation will be empty since we didn’t have any.
PAIR
Removes the top two elements of the stack, create a pair with them and push it onto the top of the stack. In our case, it takes our (list operation)
and our string
, create a pair with them, and push the pair on top of our stack.
At the end of our smart contract, we returned our stack containing pair (list operation) string
which is what we wanted, as the type matches our expected return type (pair `operations `storage)
.
Let’s summarize what we’ve done so far
- We learned the VERY basics of Michelson
- We wrote and executed a simple michelson contract called helloMedium.tz
- We learned about some of the Michelson types, values and operations.
If we want to go further
Let’s learn a few more operations and go a little bit further.
Hello <input>
Create a new file and name it helloInput.tz
. We want to display “Hello <input>” , input being a string argument we send to our program. As our previous example, let’s add our two argument lines:
parameter string;
storage string;
Notice that we changed our parameter type from unit
to string
since our input will be a string.
Now, let’s add our code:
First we need to get the left-hand element of our arguments pair to get our string. The CAR;
instruction does so. We then push our string “Hello “. The CONCAT;
instruction will concatenate the top two elements of the stack. We already learned about NIL;
and PAIR;
operations, so let’s run it:
chainacc@tezos:~/tezos$ tezos-client run script helloInput.tz on storage '""' and input '"Example!"'
which results in:
storage
"Hello Example!"
emitted operations
We used parameter for this example, but we can also do it with storage. In that case, we would have to use the CDR;
instruction to get the storage. CDR;
is the same as CAR;
except that it takes the right-hand of the pair instead of the left-hand. So, the following code:
parameter unit;
storage string;
code {CDR;
PUSH string "Hello ";
CONCAT;
NIL operation; PAIR;};
when executed like this:
chainacc@tezos:~/tezos$ tezos-client run script helloStorage.tz on storage '"ExampleTwo!"' and input Unit
would give:
storage
"Hello ExampleTwo!"
emitted operations
Hello Input and Storage
To learn about 2–3 more operations, let’s write a contract that concatenates an input string and a storage string, and outputs the result preceded by “Hello”. To do so, let’s create a file called helloInputAndStorage.tz
and write the following code:
parameter string;
storage string;
code {DUP;
CDR;
SWAP;
CAR;
CONCAT;
PUSH string "Hello ";
CONCAT;
NIL operation; PAIR;};
DUP;
instruction duplicates the top of the stack to get two pairs instead of one. SWAP;
instruction exchanges the top two elements of the stack to put the second pair on top of it. Once we have the two parts that we want storage
and parameter
, we can concatenate them, add the “Hello “ string, concatenate again and end our program in the way we’ve seen before.
When executed like this:
chainacc@tezos:~/tezos$ tezos-client run script helloInputAndStorage.tz on storage '"bar"' and input '"foo"'
It gives us:
storage
"Hello foobar"
emitted operations
As we wanted.
And we’re done for this article! ;) Stay tuned for next ones!