Docs: new documentation structure using Sphinx/RST

- Provides a toplevel documentation structure using Sphinx
 - Adds a `doc-html` target to the main Makefile
 - Converts existing documentation to RST format
 - Add some new documentation / tutorials
 - Links the developer manual and OCaml documentation
 - Synchronized documentation on Gitlab pages

This patch is co-authored by:
 - Benjamin Canou <benjamin@canou.fr>
 - Bruno Bernardo <bernardobruno@gmail.com>
 - Pietro Abate <pietro.abate@inria.fr>
This commit is contained in:
Benjamin Canou 2017-11-11 11:40:20 +01:00
parent 64c65558d8
commit adf860ea40
38 changed files with 6375 additions and 3466 deletions

5
.gitignore vendored
View File

@ -1,7 +1,10 @@
.DS_Store
__pycache__
/_build
/docs/introduction/readme.rst
_build
*.install
/tezos-node

View File

@ -458,3 +458,21 @@ deploy:bootstrap6:
# - ./scripts/delete_ci_image.sh gitlab-ci-token "${CI_BUILD_TOKEN}"
# "${CI_PROJECT_PATH}/build"
# "${CI_BUILD_REF}"
pages:
stage: publish
image: ${CI_REGISTRY_IMAGE}/build:${CI_BUILD_REF}
only:
- master@tezos/tezos
artifacts:
paths:
- public
script:
- cd /home/opam/tezos
- sudo apk update && sudo apk upgrade
- sudo apk add py3-sphinx py3-sphinx_rtd_theme
- sudo ln -s /usr/bin/sphinx-build-3 /usr/bin/sphinx-build
- opam install odoc
- make doc-html && sudo mv docs/_build "${CI_PROJECT_DIR}"/public
dependencies:
- build

View File

@ -1,6 +1,9 @@
For the next reset
Alphanet changelog
==================
For the next reset
------------------
[Alpha]
- Do not allow revealing the same endorsement twice.
@ -34,7 +37,7 @@ For the next reset
Reset 2017-11-20
==================
------------------
[Alphanet]
@ -104,7 +107,7 @@ Reset 2017-11-20
- Add `SIZE` on lists.
Reset 2017-11-17
================
----------------
[Node]
@ -112,7 +115,7 @@ Reset 2017-11-17
- Irmin: restore usage `git-repack`... (mistakenly removed)
Reset 2017-10-13
================
----------------
[Client]
@ -134,7 +137,7 @@ Reset 2017-10-13
prevent an error raised when using an unrevealed key.
Reset 2017-09-21
================
----------------
[Node]
@ -156,7 +159,7 @@ Reset 2017-09-21
prevent an error raised when using an unrevealed key.
Reset 2017-08-10
================
----------------
This update includes changes in the on-disk state of the node and in
the format of blocks and operations. It thus requires a chain reset.

View File

@ -12,6 +12,10 @@ all:
doc-html:
@jbuilder build @doc ${DEV}
@mkdir -p $$(pwd)/docs/_build/api/odoc
@rm -rf $$(pwd)/docs/_build/api/odoc/*
@cp -r $$(pwd)/_build/default/_doc/* $$(pwd)/docs/_build/api/odoc/
@make -C docs
build-test:
@jbuilder build @buildtest ${DEV}
@ -28,5 +32,6 @@ docker-image:
clean:
@-jbuilder clean
@-rm -f tezos-node tezos-client tezos-protocol-compiler
@-make -C docs clean
.PHONY: all test build-deps docker-image clean

413
README.md
View File

@ -1,413 +0,0 @@
TEZOS
=====
Tezos is a distributed consensus platform with meta-consensus capability. Tezos
not only comes to consensus about state, like BTC or ETH. It also comes to
consensus about how the protocol and the nodes should adapt and upgrade.
See https://www.tezos.com/ for more information about the project.
Build instructions
------------------
To compile Tezos, you need an OCaml compiler (version 4.04.2) and all the
libraries listed in the various `tezos-*.opam` files.
The best way to install all dependencies is by first installing
[OPAM](https://opam.ocaml.org/), the OCaml package manager.
Then, you need to create a new switch alias for Tezos. A switch is
your own version of the OPAM configuration, including the OCaml
compiler, all packages, and package manager configuration related to
your project. This is necessary so that the project doesn't conflict
with other OCaml projects or other versions of Tezos.
```
opam update
opam switch "tezos" --alias-of 4.04.2
```
Note that if you previously created a switch named `tezos` but with an
older OCaml version you need to remove the switch with `opam switch
remove "tezos"`.
When the switch is ready, you need to activate it:
```
eval `opam config env`
```
Install the libraries which Tezos depends on:
```
make build-deps
```
While building the dependencies, `opam` is able to handle correctly
the OCaml libraries but it is not always able to handle all external C
libraries we depend on. On most system, it is able to suggest a call
to the system package manager but it currently does not handle version
check. In particular, the `libsodium-dev` packages on Ubuntu is too
old for building Tezos, we rely on version `1.0.11` at least.
At last, compile the project:
```
make
```
This should produce three binaries:
* `tezos-node`: the tezos daemon itself;
* `tezos-client`: a minimal command-line client;
* `tezos-protocol-compiler`: a protocol compiler used for developing new version of the economic protocol.
Currently Tezos is being developed for Linux only. It should work on mac OS,
but it has not been tested recently. A Windows port is in progress.
Note that, when executing `make build-deps`, OPAM will detect if
required system dependencies are installed. However, it is not able to
detect which versions you actually have. Typically, `make` will
probably fail if you have an libsodium < 1.0.11. In this case, make
sure you have a recent version of libsodium and libsodium-dev, or
download and install them from, eg,
https://pkgs.org/download/libsodium18 and
https://pkgs.org/download/libsodium-dev
Running the node
----------------
So far there is no official Tezos network being run, but you might run a local
test network (the development team is running its own testnet, if you're interested
in joining this network, please make a request on our slack channel. We have
limited support abilities at the moment but we'll try to help you best we can).
Use the following command to run a node that will accept incoming
connections:
```
./tezos-node identity generate 24.
```
This will first generate a new node identity and compute the
associated stamp of proof-of-work. Then, the node will listen to
connections coming in on `[::]:9732`. All used data is stored at
`$HOME/.tezos-node/`. For example, the default configuration file is
at `$HOME/.tezos-node/config.json`.
To run multiple nodes on the same machine, you can duplicate and edit
`$HOME/.tezos-node/config.json` while making sure they don't share paths to the
database or any other data file (cf. options `db.store` ; `db.context` ;
`db.protocol`, `net.peers-metadata` and `net.identity`).
You could also let Tezos generate a config file by specifying options on the
command line. For instance, if `$dir/config.json` does not exist, the following
command will generate it and replace the default values with the values from
the command line:
```
./tezos-node run --data-dir "$dir" --net-addr localhost:9733
```
The Tezos server has a built-in mechanism to discover peers on the local
network (using UDP packets broadcasted on port 7732).
If this mechanism is not sufficient, one can provide Tezos with a list of
initial peers, either by editing the option `net.bootstrap-peers` in the
`config.json` file, or by specifying a command line parameter:
```
./tezos-node run \
--data-dir "$dir" --net-addr localhost:2023 \
--peer localhost:2021 --peer localhost:2022
```
If `"$dir"/config.json` exists, the command line options override those
read in the config file. By default, Tezos won't modify the content of an
existing `"$dir"/config.json` file. But, you may explicit ask the node
to reset or to update the file according to the command line parameters
with the following commands line:
```
./tezos-node config reset --data-dir "$dir" --net-addr localhost:9733
./tezos-node config update --data-dir "$dir" --net-addr localhost:9734
```
Running the node in a sandbox
-----------------------------
To run a 'localhost-only' instance of a Tezos network, we provide two
helper scripts:
- `./bin_node/tezos-sandboxed-node.sh`
- `./bin_client/tezos-init-sandboxed-client.sh`
For instance, if you want to run local network with two nodes, in a
first terminal, the following command will initialize a node listening
for peers on port `19731` and listening for RPC on port `18731`.
```
./bin_node/tezos-sandboxed-node.sh 1
```
This node will store its data in a temporary directory which will be
removed when the node is killed.
To launch the second node, just run the following command, it will
listen on port `19739` and `18739`:
```
./bin_node/tezos-sandboxed-node.sh 9
```
You might replace `1` or `9` by any number in between if you want to
run more than two nodes. But, if you intend to run a single node
network, you might remove the spurious "Too few connections" warnings
by lowering the number of expected connection, by running the
following command instead:
```
./bin_node/tezos-sandboxed-node.sh 1 --connections 0
```
Once your node(s) is/are running, open a new terminal and initialize
the "sandboxed" client data:
```
eval `./bin_client/tezos-init-sandboxed-client.sh 1`
```
It will initialize the client data in a temporary directory. It will
also defines in the current shell session an alias `tezos-client`
preconfigured for communicating the same-numbered node. For instance:
```
$ tezos-client rpc call blocks/head/hash
{ "hash": "BLockGenesisGenesisGenesisGenesisGenesisGeneskvg68z" }
```
When you bootstrap a new network, the network is initialized with a
dummy economic protocol, called "genesis". If you want to run the same
protocol than the alphanet, `init-sandboxed-client` also defines an
alias `tezos-activate-alpha`, that you need to execute once for
activating the whole network. For instance:
```
$ tezos-client rpc call blocks/head/protocol
{ "protocol": "ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im" }
$ tezos-activate-alpha
Injected BMBcK869jaHQDc
$ tezos-client rpc call blocks/head/protocol
{ "protocol": "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK" }
```
Configuration options
---------------------
Here is an example configuration file with all parameters
specified. Most of the time it uses default values, except for cases
where the default is not explanatory enough (i.e. "bootstrap-peers" is
an empty list by default). Comments are not allowed in JSON, so this
configuration file would not parse. They are just provided here to
help writing your own configuration file if needed.
```
{
/* Location of the data dir on disk. */
"data-dir": "/home/tezos/my_data_dir"
/* Configuration of net parameters */
"net": {
/* Floating point number between 0 and 256 that represents a
difficulty, 24 signifies for example that at least 24 leading
zeroes are expected in the hash. */
"expected-proof-of-work": 24.5,
/* List of hosts. Tezos can connect to both IPv6 and IPv4
hosts. If the port is not specified, default port 9732 will be
assumed. */
"bootstrap-peers": ["::1:10732", "::ffff:192.168.1.3:9733", "mynode.tezos.com"],
/* Specify if the network is closed or not. A closed network
allows only peers listed in "bootstrap-peers". */
"closed": false,
/* Network limits */
"limits": {
/* Delay granted to a peer to perform authentication, in
seconds. */
"authentication-timeout": 5,
/* Strict minimum number of connections (triggers an urgent
maintenance). */
"min-connections": 50,
/* Targeted number of connections to reach when bootstraping /
maintaining. */
"expected-connections": 100,
/* Maximum number of connections (exceeding peers are
disconnected). */
"max-connections": 200,
/* Number above which pending incoming connections are
immediately rejected. */
"backlog": 20,
/* Maximum allowed number of incoming connections that are
pending authentication. */
"max-incoming-connections": 20,
/* Max download and upload speeds in KiB/s. */
"max-download-speed": 1024,
"max-upload-speed": 1024,
/* Size of the buffer passed to read(2). */
"read-buffer-size": 16384,
}
},
/* Configuration of rpc parameters */
"rpc": {
/* Host to listen to. If the port is not specified, the default
port 8732 will be assumed. */
"listen-addr": "localhost:8733",
/* Cross Origin Resource Sharing parameters, see
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing. */
"cors-origin": [],
"cors-headers": [],
/* Certificate and key files (necessary when TLS is used). */
"crt": "tezos-node.crt",
"key": "tezos-node.key"
},
/* Configuration of log parameters */
"log": {
/* Output for the logging function. Either "stdout", "stderr" or
the name of a log file . */
"output": "tezos-node.log",
/* Verbosity level: one of 'fatal', 'error', 'warn', 'notice',
'info', 'debug'. */
"level": "info",
/* Fine-grained logging instructions. Same format as described in
`tezos-node run --help`, DEBUG section. In the example below,
sections "net" and all sections starting by "client" will have
their messages logged up to the debug level, whereas the rest of
log sections will be logged up to the notice level. */
"rules": "client* -> debug, net -> debug, * -> notice",
/* Format for the log file, see
http://ocsigen.org/lwt/dev/api/Lwt_log_core#2_Logtemplates. */
"template": "$(date) - $(section): $(message)"
},
/* Configuration for the validator and mempool parameters */
"shell": {
/* The number of peers to synchronize with
before declaring the node 'bootstrapped'. */
"bootstrap_threshold": 4
}
}
```
Debugging
---------
It is possible to set independant log levels for different logging
sections in Tezos, as well as specifying an output file for
logging. See the description of log parameters above as well as
documentation under the DEBUG section diplayed by `tezos-node run
--help'.
JSON/RPC interface
------------------
The Tezos node provides a JSON/RPC interface. Note that it is an RPC, and it is
JSON based, but it does not follow the "JSON-RPC" protocol. It is not active by
default and it must be explicitely activated with the `--rpc-addr` option.
Typically, if you are not trying to run a local network and just want to
explore the RPC, you would run:
```
./tezos-node run --rpc-addr localhost
```
The RPC interface is self-documented and the `tezos-client` executable is able
to pretty-print the RPC API. For instance, to see the API provided by the Tezos
Shell:
```
./tezos-client rpc list
```
To get API attached to the "genesis" block, including the remote procedures
provided by the associated economic protocol version:
```
./tezos-client rpc list /blocks/genesis/
```
You might also want the JSON schema describing the expected input and output of
a RPC. For instance:
```
./tezos-client rpc schema /blocks/genesis/hash
```
Note: you can get the same information, but as a raw JSON object, with a simple
HTTP request:
```
wget --post-data '{ "recursive": true }' -O - http://localhost:8732/describe
wget --post-data '{ "recursive": true }' -O - http://localhost:8732/describe/blocks/genesis
wget -O - http://localhost:8732/describe/blocks/genesis/hash
```
The minimal CLI client
----------------------
Work in progress.
See `./tezos-client -help` for available commands.

409
README.rst Normal file
View File

@ -0,0 +1,409 @@
TEZOS
=====
Tezos is a distributed consensus platform with meta-consensus
capability. Tezos not only comes to consensus about state, like BTC or
ETH. It also comes to consensus about how the protocol and the nodes
should adapt and upgrade.
See https://www.tezos.com/ for more information about the project.
Build instructions
------------------
To compile Tezos, you need an OCaml compiler (version 4.04.2) and all
the libraries listed in the various ``tezos-*.opam`` files.
The best way to install all dependencies is by first installing
`OPAM <https://opam.ocaml.org/>`__, the OCaml package manager.
Then, you need to create a new switch alias for Tezos. A switch is your
own version of the OPAM configuration, including the OCaml compiler, all
packages, and package manager configuration related to your project.
This is necessary so that the project doesnt conflict with other OCaml
projects or other versions of Tezos.
::
opam update
opam switch "tezos" --alias-of 4.04.2
Note that if you previously created a switch named ``tezos`` but with an
older OCaml version you need to remove the switch with
``opam switch remove "tezos"``.
When the switch is ready, you need to activate it:
::
eval `opam config env`
Install the libraries which Tezos depends on:
::
make build-deps
While building the dependencies, ``opam`` is able to handle correctly
the OCaml libraries but it is not always able to handle all external C
libraries we depend on. On most system, it is able to suggest a call to
the system package manager but it currently does not handle version
check. In particular, the ``libsodium-dev`` packages on Ubuntu is too
old for building Tezos, we rely on version ``1.0.11`` at least.
At last, compile the project:
::
make
This should produce three binaries:
- ``tezos-node``: the tezos daemon itself;
- ``tezos-client``: a minimal command-line client;
- ``tezos-protocol-compiler``: a protocol compiler used for developing
new version of the economic protocol.
Currently Tezos is being developed for Linux only. It should work on mac
OS, but it has not been tested recently. A Windows port is in progress.
Note that, when executing ``make build-deps``, OPAM will detect if
required system dependencies are installed. However, it is not able to
detect which versions you actually have. Typically, ``make`` will
probably fail if you have an libsodium < 1.0.11. In this case, make sure
you have a recent version of libsodium and libsodium-dev, or download
and install them from, eg, https://pkgs.org/download/libsodium18 and
https://pkgs.org/download/libsodium-dev
Running the node
----------------
So far there is no official Tezos network being run, but you might run a
local test network (the development team is running its own testnet, if
youre interested in joining this network, please make a request on our
slack channel. We have limited support abilities at the moment but well
try to help you best we can).
Use the following command to run a node that will accept incoming
connections:
::
./tezos-node identity generate 24.
This will first generate a new node identity and compute the associated
stamp of proof-of-work. Then, the node will listen to connections coming
in on ``[::]:9732``. All used data is stored at ``$HOME/.tezos-node/``.
For example, the default configuration file is at
``$HOME/.tezos-node/config.json``.
To run multiple nodes on the same machine, you can duplicate and edit
``$HOME/.tezos-node/config.json`` while making sure they dont share
paths to the database or any other data file (cf. options ``db.store`` ;
``db.context`` ; ``db.protocol``, ``net.peers-metadata`` and
``net.identity``).
You could also let Tezos generate a config file by specifying options on
the command line. For instance, if ``$dir/config.json`` does not exist,
the following command will generate it and replace the default values
with the values from the command line:
::
./tezos-node run --data-dir "$dir" --net-addr localhost:9733
The Tezos server has a built-in mechanism to discover peers on the local
network (using UDP packets broadcasted on port 7732).
If this mechanism is not sufficient, one can provide Tezos with a list
of initial peers, either by editing the option ``net.bootstrap-peers``
in the ``config.json`` file, or by specifying a command line parameter:
::
./tezos-node run \
--data-dir "$dir" --net-addr localhost:2023 \
--peer localhost:2021 --peer localhost:2022
If ``"$dir"/config.json`` exists, the command line options override
those read in the config file. By default, Tezos wont modify the
content of an existing ``"$dir"/config.json`` file. But, you may
explicit ask the node to reset or to update the file according to the
command line parameters with the following commands line:
::
./tezos-node config reset --data-dir "$dir" --net-addr localhost:9733
./tezos-node config update --data-dir "$dir" --net-addr localhost:9734
Running the node in a sandbox
-----------------------------
To run a localhost-only instance of a Tezos network, we provide two
helper scripts:
- ``./bin_node/tezos-sandboxed-node.sh``
- ``./bin_client/tezos-init-sandboxed-client.sh``
For instance, if you want to run local network with two nodes, in a
first terminal, the following command will initialize a node listening
for peers on port ``19731`` and listening for RPC on port ``18731``.
::
./bin_node/tezos-sandboxed-node.sh 1
This node will store its data in a temporary directory which will be
removed when the node is killed.
To launch the second node, just run the following command, it will
listen on port ``19739`` and ``18739``:
::
./bin_node/tezos-sandboxed-node.sh 9
You might replace ``1`` or ``9`` by any number in between if you want to
run more than two nodes. But, if you intend to run a single node
network, you might remove the spurious “Too few connections” warnings by
lowering the number of expected connection, by running the following
command instead:
::
./bin_node/tezos-sandboxed-node.sh 1 --connections 0
Once your node(s) is/are running, open a new terminal and initialize the
“sandboxed” client data:
::
eval `./bin_client/tezos-init-sandboxed-client.sh 1`
It will initialize the client data in a temporary directory. It will
also defines in the current shell session an alias ``tezos-client``
preconfigured for communicating the same-numbered node. For instance:
::
$ tezos-client rpc call blocks/head/hash
{ "hash": "BLockGenesisGenesisGenesisGenesisGenesisGeneskvg68z" }
When you bootstrap a new network, the network is initialized with a
dummy economic protocol, called “genesis”. If you want to run the same
protocol than the alphanet, ``init-sandboxed-client`` also defines an
alias ``tezos-activate-alpha``, that you need to execute once for
activating the whole network. For instance:
::
$ tezos-client rpc call blocks/head/protocol
{ "protocol": "ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im" }
$ tezos-activate-alpha
Injected BMBcK869jaHQDc
$ tezos-client rpc call blocks/head/protocol
{ "protocol": "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK" }
Configuration options
---------------------
Here is an example configuration file with all parameters specified.
Most of the time it uses default values, except for cases where the
default is not explanatory enough (i.e. “bootstrap-peers” is an empty
list by default). Comments are not allowed in JSON, so this
configuration file would not parse. They are just provided here to help
writing your own configuration file if needed.
::
{
/* Location of the data dir on disk. */
"data-dir": "/home/tezos/my_data_dir"
/* Configuration of net parameters */
"net": {
/* Floating point number between 0 and 256 that represents a
difficulty, 24 signifies for example that at least 24 leading
zeroes are expected in the hash. */
"expected-proof-of-work": 24.5,
/* List of hosts. Tezos can connect to both IPv6 and IPv4
hosts. If the port is not specified, default port 9732 will be
assumed. */
"bootstrap-peers": ["::1:10732", "::ffff:192.168.1.3:9733", "mynode.tezos.com"],
/* Specify if the network is closed or not. A closed network
allows only peers listed in "bootstrap-peers". */
"closed": false,
/* Network limits */
"limits": {
/* Delay granted to a peer to perform authentication, in
seconds. */
"authentication-timeout": 5,
/* Strict minimum number of connections (triggers an urgent
maintenance). */
"min-connections": 50,
/* Targeted number of connections to reach when bootstraping /
maintaining. */
"expected-connections": 100,
/* Maximum number of connections (exceeding peers are
disconnected). */
"max-connections": 200,
/* Number above which pending incoming connections are
immediately rejected. */
"backlog": 20,
/* Maximum allowed number of incoming connections that are
pending authentication. */
"max-incoming-connections": 20,
/* Max download and upload speeds in KiB/s. */
"max-download-speed": 1024,
"max-upload-speed": 1024,
/* Size of the buffer passed to read(2). */
"read-buffer-size": 16384,
}
},
/* Configuration of rpc parameters */
"rpc": {
/* Host to listen to. If the port is not specified, the default
port 8732 will be assumed. */
"listen-addr": "localhost:8733",
/* Cross Origin Resource Sharing parameters, see
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing. */
"cors-origin": [],
"cors-headers": [],
/* Certificate and key files (necessary when TLS is used). */
"crt": "tezos-node.crt",
"key": "tezos-node.key"
},
/* Configuration of log parameters */
"log": {
/* Output for the logging function. Either "stdout", "stderr" or
the name of a log file . */
"output": "tezos-node.log",
/* Verbosity level: one of 'fatal', 'error', 'warn', 'notice',
'info', 'debug'. */
"level": "info",
/* Fine-grained logging instructions. Same format as described in
`tezos-node run --help`, DEBUG section. In the example below,
sections "net" and all sections starting by "client" will have
their messages logged up to the debug level, whereas the rest of
log sections will be logged up to the notice level. */
"rules": "client* -> debug, net -> debug, * -> notice",
/* Format for the log file, see
http://ocsigen.org/lwt/dev/api/Lwt_log_core#2_Logtemplates. */
"template": "$(date) - $(section): $(message)"
},
/* Configuration for the validator and mempool parameters */
"shell": {
/* The number of peers to synchronize with
before declaring the node 'bootstrapped'. */
"bootstrap_threshold": 4
}
}
Debugging
---------
It is possible to set independant log levels for different logging
sections in Tezos, as well as specifying an output file for logging. See
the description of log parameters above as well as documentation under
the DEBUG section diplayed by \`tezos-node run help.
JSON/RPC interface
------------------
The Tezos node provides a JSON/RPC interface. Note that it is an RPC,
and it is JSON based, but it does not follow the “JSON-RPC” protocol. It
is not active by default and it must be explicitely activated with the
``--rpc-addr`` option. Typically, if you are not trying to run a local
network and just want to explore the RPC, you would run:
::
./tezos-node run --rpc-addr localhost
The RPC interface is self-documented and the ``tezos-client`` executable
is able to pretty-print the RPC API. For instance, to see the API
provided by the Tezos Shell:
::
./tezos-client rpc list
To get API attached to the “genesis” block, including the remote
procedures provided by the associated economic protocol version:
::
./tezos-client rpc list /blocks/genesis/
You might also want the JSON schema describing the expected input and
output of a RPC. For instance:
::
./tezos-client rpc schema /blocks/genesis/hash
Note: you can get the same information, but as a raw JSON object, with a
simple HTTP request:
::
wget --post-data '{ "recursive": true }' -O - http://localhost:8732/describe
wget --post-data '{ "recursive": true }' -O - http://localhost:8732/describe/blocks/genesis
wget -O - http://localhost:8732/describe/blocks/genesis/hash
The minimal CLI client
----------------------
Work in progress.
See ``./tezos-client -help`` for available commands.

25
docs/Makefile Normal file
View File

@ -0,0 +1,25 @@
# You can set these variables from the command line.
SPHINXOPTS = -aE -n
SPHINXBUILD = sphinx-build
SPHINXPROJ = Tezos
SOURCEDIR = .
BUILDDIR = _build
all: html linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck "$(SOURCEDIR)" "$(BUILDDIR)"
introduction/readme.rst: ../README.rst
sed 's/TEZOS/How to build and run/' $< > $@
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
html: Makefile introduction/readme.rst
@$(SPHINXBUILD) -b html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
clean:
@-rm -Rf "$(BUILDDIR)"
@-rm introduction/readme.rst

View File

@ -1,321 +0,0 @@
Tezos (alphanet)
================
Welcome to the Tezos alphanet, which is a pre-release network for the
Tezos blockchain. Currently, the chain is reset every few weeks.
For news and support about the alphanet, please join IRC (`#tezos` on
freenode). Please, report bugs related to the alphanet on the IRC
channel before filling Github issues.
For more information about the project in general, see:
https://www.tezos.com/
How to join the alphanet ?
==========================
We provide two ways of joining the alphanet :
- use `docker` and prebuilt binaries
(recommended way, tested on windows/mac/linux)
- manual compilation and installation
(linux and mac only)
The `alphanet.sh` script
------------------------
The recommended way for running an up-to-date Tezos node connected to
the alphanet is to use `scripts/alphanet.sh`. Its only requirement is a
working installation of Docker:
https://www.docker.com/community-edition
First, you need to download the script:
```
wget https://raw.githubusercontent.com/tezos/tezos/alphanet/scripts/alphanet.sh
chmod +x alphanet.sh
```
You are now one step away from a working node:
```
./alphanet.sh start
```
This will launch a docker container running the various daemons that
form a working tezos node. The first launch might take a few minutes
to synchronize the chain.
On first launch the script will also create a cryptographic identity
(nicknamed `my_identity`) and provide you with free tezzies on a fresh
account (nicknamed `my_account`). You might check your balance with:
```
./alphanet.sh client get balance for my_account
```
On some circumstances the account creation might fail. If so, see
section "Known issues" below on how to force the account creation.
See `./alphanet.sh --help` for more informations about the script.
In particular see `./alphanet.sh client --help` and
`scripts/README.master` for more information about the client.
Every call to `alphanet.sh` will check for updates of the node and
will fail if your node is not up-to-date. For updating the node,
simply run:
```
./alphanet.sh restart
```
If you prefer to temporarily disable automatic updates, you just
have to set an environment variable:
```
export TEZOS_ALPHANET_DO_NOT_PULL=yes
```
Compilation from sources
------------------------
The `alphanet` branch in the tezos git repository will always contain
the up-to-date sources of the tezos-node required for running the
alphanet. See `docs/README.master` on how to compile it.
Once built, you might launch the a node by running:
```
./tezos-node identity generate 24.
./tezos-node run --rpc-addr localhost
```
By default this instance will store its data in `$HOME/.tezos-node`
and will listen to incoming peers on port 9732. It will also listen
to RPC requests on port 8732 (only from `localhost`). You might find
more options by running `./tezos-node config --help`.
If you want to stake (see below for more details), you will also have
to run:
```
./tezos-client launch daemon
```
That's all. For the rest of the document, to execute the example
commands, you will have to replace `./alphanet.sh client` by
`./tezos-client`.
How to observe the network ?
============================
The alphanet script provides a basic command `./alhpanet.sh head` that
allows you to see if your own node is synchronized.
The Tezos client also offers a lot of commands to introspect the state of
the node, and also to list and call the RPCs of the nodes.
Enthusiastic Tezos adopter fredcy has also developed a nice block explorer
for the alphanet. See [https://github.com/fredcy/tezos-client].
In an upcoming version, we will also provide an opt-in tool for node runners
that will allow us to provide a global monitoring panel of the alphanet.
How to obtain free Tez from the faucet contract ?
=================================================
The alphanet contains an ad-hoc faucet contract, that will generate
new tezzies for you to test. Obviously, this contract will not be
available outside of the test network.
First, if you don't have any cryptographic identity yet, you need to
generate one (replace `my_identity` with any name that suits you
best):
```
./alphanet.sh client gen keys "my_identity"
```
Then, you have to generate a new "free" account (replace `my_account`
with any name that suits you best and `my_identity` by the name used
in the previous command):
```
./alphanet.sh client originate free account "my_account" for "my_identity"
```
That's all. You might check your balance:
```
./alphanet.sh client get balance for "my_account"
```
If you want MORE tezzies, you need to generate as many free accounts as
you need (you should receive ꜩ100.000 per account) and then transfer
the tezzies into a single account. For instance:
```
./alphanet.sh client originate free account "my_alt_account" for "my_identity"
./alphanet.sh client transfer 100,000.00 from "my_alt_account" to "my_account" -fee 0.00
./alphanet.sh client forget contract "my_alt_account"
```
Note that the test network is kind enough to accept transactions
without fees...
How to play with smart-contracts ?
==================================
An advanced documentation of the smart contract language is in
`/docs/language.md`
Some test contracts are in
`/tests/contracts/`
For details and examples, see:
http://www.michelson-lang.com/
How to stake on the alphanet ?
==============================
By default, the faucet of the alphanet (the one behind `./alphanet.sh
originate free account "my_account" for "my_identity"`) creates
contracts which are managed by `my_identity` but whose staking rights
are delegated to the baker of the block including the
origination. That way we are sure that staking rights are attributed
to an active baker.
But, nonetheless, you might claim your staking rights!
The following command returns the current delegate of a contract:
```
./alphanet.sh client get delegate for "my_account"
```
If it is one the following, it is indeed one of our "bootstrap"
contracts!
- `tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc`
- `tz1irovm9SKduvL3npv8kDM54PSWY5VJXoyz`
- `tz1UsgSSdRwwhYrqq7iVp2jMbYvNsGbWTozp`
- `tz1TwYbKYYJxw7AyubY4A9BUm2BMCPq7moaC`
- `tz1QWft73Zhj5VSA1sCuEi9HhDDJqywE6BtC`
You might change the delegate of a contract with a single command:
```
./alphanet.sh client set delegate for "my_account" to "my_identity"
```
You now have staking rights!
Well, almost.
You should wait.
A little bit.
At most two cycles. Which, on the alphanet is 128 blocks (something
around 2 hours). On the mainnet, this will be between 2 weeks and a
month.
But, to enforce your right a last step is required. When baking or
endorsing a block, a bond is taken out of the default account
associated to the public key of the delegate. Hence, in order to
stake, you must be provisioning for bond deposit.
```
./alphanet.sh client transfer 50,000.00 from "my_account" to "my_identity"
```
On the alphanet, a bond is ꜩ1000. Hence, with the previous command you
provisioned 50 bonds. If you want more, see section "How to obtain
free Tez from the faucet contract ?".
Now, you are settled. The `alphanet` docker image runs a baker daemon
and a endorser daemon, by default for all your keys.
To know if you staked, just run:
```
./alphanet.sh baker log
./alphanet.sh endorser log
```
You should see lines such as:
```
Injected block BLxzbB7PBW1axq for bootstrap5 after BLSrg4dXzL2aqq (level 1381, slot 0, fitness 00::0000000000005441, operations 21)
```
Or:
```
Injected endorsement for block 'BLSrg4dXzL2aqq' (level 1381, slot 3, contract bootstrap5) 'oo524wKiEWBoPD'
```
On the alphanet, rewards for staking are credited after 24 hours. The
reward for baking or endorsing a block is ꜩ150. The safety bond is
returned together with the reward.
To know when you will be allowed to stake in the current cycle, you
might try the following RPCs, where you replaced `tz1iFY8ads...` by
the appropriate value:
```
$ ./alphanet.sh client list known identities
my_identity: tz1iFY8aDskx9QGbgBy68SNAGgkc7AE2iG9H (public key known) (secret key known)
$ ./alphanet.sh client rpc call /blocks/head/proto/helpers/rights/baking/delegate/tz1iFY8aDskx9QGbgBy68SNAGgkc7AE2iG9H with '{}'
{ "ok":
[ { "level": 1400.000000, "priority": 2.000000,
"timestamp": "2017-05-19T03:21:52Z" },
... ] }
```
Known issues
============
Missing account `my_account`
----------------------------
The chain synchronization has not been optimized yet and the
`alphanet.sh` script might misdetect the end of the synchronization
step. If so, it will try to create your free account in an outdated
context and your new account will never be included in the chain.
To fix this, just wait for your node to be synchronized: for that run
the following command, in the middle of a (raw) json object, it should
display the date of the last block (which should not be too far in the
past):
```
./alphanet.sh head
```
Please note that the printed date is GMT, don't forget the time shift.
Then, you need to remove from the client state the non-existant
contract and regenerate a new one:
```
./alphanet.sh client forget contract "my_account"
./alphanet.sh client originate free account "my_account" for "my_identity"
```

40
docs/README.rst Normal file
View File

@ -0,0 +1,40 @@
******************************
Building documentation locally
******************************
Building instructions
---------------------
To build the documentaion, you can use the main Makefile target ``doc-html``
.. code:: bash
make doc-html
The documentation is built by Sphinx, and uses the Read The Docs theme.
On a debian system, you can install the needed dependencies with:
.. code:: bash
sudo apt install \
python3-recommonmark \
python3-sphinx \
python3-sphinx-rtd-theme
OCaml documentation
-------------------
Odoc is used for OCaml API generation, that you can install with:
.. code:: bash
opam install odoc
Tezos generates the API documentation for all libraries in HTML format. The
generated HTML pages in ``_build/<context>/_doc``. It creates one sub-directory
per public library and generates an ``index.html`` file in each sub-directory.
The documentation is not installed on the system by Tezos. It is meant to be
read locally while developing and then published on the www when releasing
packages.

View File

@ -1,10 +0,0 @@
Tezos (zeronet)
===============
The Tezos zeronet is a development network that might be broken
multiple times a day.
If you wish to experiment with Tezos we recommend you to test the `alphanet`,
which is a more stable test network.
In particular, we offer no support about the zeronet.

View File

@ -1,65 +0,0 @@
# Tezos Code Tutorial
## Introduction
The purpose of this document is to help contributors get started with the Tezos
codebase. The code is organized in several layers in a way which largely reflects the philosophy of the project. It creates a very strict separation between the "node", which implements the network protocol described in the white paper and between the protocols themselves. Of course the seed protocol itself is a very important part of the Tezos project and it follows a similar organization. The economic protocol sits on top of a few layers of abstractions dealing primarily with storing and retrieving data from the current context.
## Overview of the source
This section presents a brief overview of the layout of the source files and their significance.
### node
The network shell
#### node/db
Persistent data structures used by the shell to store its state.
#### note/net
Connectivity for the gossip network and primitives to create RPC services
#### node/shell
The shell itself
#### node/updater
Manage on-the-fly updates to the protocol
### proto
This is where the protocols live
#### proto/environment
#### proto/current
### utils
### compiler
### client
### client/embedded
### Node, the network shell
### Storing the context
## Irmin
Tezos needs to store potentially different version of its context, corresponding to potentially different branches of the blockchain. This also implies the ability to roll back the changes made by any single block, and to make atomic changes to the structure on disk for eac block to avoid corruption.
To that extent, Tezos borrows from the MirageOS project a module called [Irmin](https://github.com/mirage/irmin "Irmin")
> Irmin is a library to persist and synchronize distributed data structures both on-disk and in-memory. It enables a style of programming very similar to the Git workflow, where distributed nodes fork, fetch, merge and push data between each other. The general idea is that you want every active node to get a local (partial) copy of a global database and always be very explicit about how and when data is shared and migrated.
Caveat: although Tezos **is** a distributed ledger, it does **not** rely on Irmin's distributed store capabilities. For our purposes we only use Irmin as a local storage. The git structure is particularly well suited to represent the versionning implicit in the state of a blockchain based ledger. In fact, the context of Tezos can be observed by running "git checkout" in the data directory.
## Netbits and Jsont
Netbits and Jsont are modules which allow for the typesafe serialization of OCaml objects in a binary format and in Json (respectively). Importantly, it does not make of the potentially brittle representation created by the compiler and access through the Obj.magic function. Serializers are created using a set of type constructors defined in a GADT.
## (MISC STUFF TO BE ORGANIZED IN THE DOCUMENT)
The "Main" module represents the fixed interface between the economic protocol and the shell.
A protocol consists of several .ml and .mli files and a file name TEZOS_PROTOCOL which lists the modules in order of inclusion for the compilation. Lower level modules sit below high level modules.
What are \\_repr modules?
These modules handle the low level representation of a type, in particular its serialization in Json and in binary format. A module based on this type will often exist on top of it and provide functionality around that type. This provides finely grained layers of encapsulation to mininize the visible interfaces.

View File

@ -0,0 +1,16 @@
from docutils import nodes
import os
import os.path
def setup(app):
app.add_role('package', package_role)
def package_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
rel_lvl = inliner.document.current_source.replace(os.getcwd(),'').count('/')
if not os.path.exists('_build/api/odoc/'+text):
raise ValueError('opam package ' + text + ' does not exist in the odoc')
url = "api/api-inline.html#" + text + '/index.html'
for i in range(1,rel_lvl):
url = '../' + url
node = nodes.reference(rawtext, text, refuri=url, **options)
return [node], []

19
docs/api/api-inline.rst Normal file
View File

@ -0,0 +1,19 @@
**************************
Online OCaml Documentation
**************************
.. raw:: html
<iframe id="docframe" height="100%" width="100%" src="../api/odoc/index.html"></iframe>
<style>
@media (max-width: 771px) {
#docframe { border:none; position: fixed; top: 70px; bottom: 0; right: 0; left: 0; }
}
@media (min-width: 770px) {
#docframe { border:none; position: fixed; top: 0px; bottom: 0; right: 0; left: 300px; }
}
</style>
<script language="JavaScript">
if (window.location.hash.endsWith(".html"))
document.getElementById('docframe').src = "../api/odoc/" + window.location.hash.slice(1)
</script>

175
docs/conf.py Normal file
View File

@ -0,0 +1,175 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Tezos documentation build configuration file, created by
# sphinx-quickstart on Wed Jan 17 18:04:32 2018.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# sys.path.insert(0, os.path.abspath('.'))
import os
import sys
sys.path.insert(0, os.path.abspath('.') + '/_extensions')
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.extlinks', 'tezos_custom_roles']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'Tezos'
copyright = '2017, Dynamic Ledger Solutions, Inc. <contact@tezos.com>'
author = 'Dynamic Ledger Solutions, Inc. <contact@tezos.com>'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.0.1'
# The full version, including alpha/beta/rc tags.
release = '0.0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# Deactivate syntax highlighting
# - http://www.sphinx-doc.org/en/stable/markup/code.html#code-examples
# - http://www.sphinx-doc.org/en/stable/config.html#confval-highlight_language
highlight_language = 'none'
# TODO write a Pygments lexer for Michelson
# cf. http://pygments.org/docs/lexerdevelopment/ and http://pygments.org/docs/lexers/
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = "sphinx_rtd_theme"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {'logo_only': True}
html_logo = "logo.svg"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
# html_sidebars = {
# '**': [
# 'relations.html', # needs 'show_related': True theme option to display
# 'searchbox.html',
# ]
# }
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'Tezosdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'Tezos.tex', 'Tezos Documentation',
'Dynamic Ledger Solutions, Inc. \\textless{}contact@tezos.com\\textgreater{}', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'tezos', 'Tezos Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'Tezos', 'Tezos Documentation',
author, 'Tezos', 'One line description of project.',
'Miscellaneous'),
]

View File

@ -1,172 +0,0 @@
* The data_encoding library
Throughout the Tezos protocol, data is serialized so that it can be used via RPC,
written to disk, or placed in a block. This serialization/deserialization is handled
via the [[../lib_data_encoding/data_encoding.mli][data_encoding library]]
by providing a set primitive encodings and a variety of combinators.
** Examples/Tutorial
*** Encoding an integer
Integers are defined as other concrete data types with a generic encoding type =type 'a encoding=.
This means that it is an encoding to/from type =int=. There are a variety of ways to encode an integer,
depending on what binary serialization you want to achieve:
- =Data_encoding.int8=
- =Data_encoding.uint8=
- =Data_encoding.int16=
- =Data_encoding.uint16=
- =Data_encoding.int31=
- =Data_encoding.int32=
- =Data_encoding.int64=
For example, an encoding that represents a 31 bit integer has type
=Data_encoding.int31 = int Data_encoding.encoding=.
#+BEGIN_SRC ocaml
let int31_encoding = Data_encoding.int31
#+END_SRC
*** Encoding an object
Encoding a single integer is fairly uninteresting. The Data_encoding library provides a number of
combinators that can be used to build more complicated objects. Consider the type that represents an
interval from the first number to the second:
#+BEGIN_SRC ocaml
type interval = int64 * int64
#+END_SRC
We can define an encoding for this type as:
#+BEGIN_SRC ocaml
let interval_encoding =
Data_encoding.(obj2 (req "min" int64) (req "max" int64))
#+END_SRC
In the example above we construct a new value =interval_encoding= by combining
two int64 integers using the =obj2= constructor.
The library provides diffrent constructors, i.e. for objects
that have no data (=Data_encoding.empty=), constructors for object up to 10 fields,
contructors for tuples, list, etc.
These are serialized to binary by converting each internal object to binary and
placing them in the order of the original object and to JSON as a JSON object with field names.
*** Lists, arrays, and options
List, Arrays and options types can by built on top of ground data types.
#+BEGIN_SRC ocaml
type interval_list = interval list
type interval_array = interval array
type interval_option = interval option
#+END_SRC
And the encoders for these types as
#+BEGIN_SRC ocaml
let interval_list_encoding = Data_encoding.list interval_encoding
let interval_array_encoding = Data_encoding.array interval_encoding
let interval_option_encoding = Data_encoding.option interval_encoding
#+END_SRC
*** Union types
The Tezos codebase makes heavy use of variant types. Consider the following
variant type:
#+BEGIN_SRC ocaml
type variant = B of bool
| S of string
#+END_SRC
Encoding for this types can be expressed as:
#+BEGIN_SRC ocaml
let variant_encoding =
Data_encoding.(union ~tag_size:`Uint8
[ case
bool
(function B b -> Some b | _ -> None)
(fun b -> B b) ;
case
string
(function S s -> Some s | _ -> None)
(fun s -> S s) ])
#+END_SRC
This variant encoding is a bit more complicated. Let's look at the parts of the type:
- We include an optimization hint to the binary encoding to inform it of the number of elements we expect in the tag.
In most cases, we can use =`Uint8=, which allows you to have up to 256 possible cases (default).
- We provide a function to wrap the datatype. The encoding works by repeatedly trying to
decode the datatype using these functions until one returns =Some payload=. This payload
is then encoded using the data_encoding specified.
- We specify a function from the encoded type to the actual datatype.
Since the library does not provide an exhaustivity check on these constructors,
the user must be careful when constructucting unin types to avoid unfortunate runtime failures.
** How the Data_encoding module works
This section is 100% optional. You do not need to understand this section to use the library.
The library uses GADTs to provide type-safe serialization/deserialization. From there,
a runtime representation of JSON objects is parsed into the typesafe version.
First we define an untyped JSON AST:
#+BEGIN_SRC ocaml
type json =
[ `O of (string * json) list
| `Bool of bool
| `Float of float
| `A of json list
| `Null
| `String of string ]
#+END_SRC
This is then parsed into a typed AST ( we eliminate several cases for clarity):
#+BEGIN_SRC ocaml
type 'a desc =
| Null : unit desc
| Empty : unit desc
| Bool : bool desc
| Int64 : Int64.t desc
| Float : float desc
| Bytes : Kind.length -> MBytes.t desc
| String : Kind.length -> string desc
| String_enum : Kind.length * (string * 'a) list -> 'a desc
| Array : 'a t -> 'a array desc
| List : 'a t -> 'a list desc
| Obj : 'a field -> 'a desc
| Objs : Kind.t * 'a t * 'b t -> ('a * 'b) desc
| Tup : 'a t -> 'a desc
| Union : Kind.t * tag_size * 'a case list -> 'a desc
| Mu : Kind.enum * string * ('a t -> 'a t) -> 'a desc
| Conv :
{ proj : ('a -> 'b) ;
inj : ('b -> 'a) ;
encoding : 'b t ;
schema : Json_schema.schema option } -> 'a desc
| Describe :
{ title : string option ;
description : string option ;
encoding : 'a t } -> 'a desc
| Def : { name : string ;
encoding : 'a t } -> 'a desc
#+END_SRC
- The first set of constructures define all ground types.
- The constructors for =Bytes=, =String= and =String_enum= includes a length fields in order to provide safe binary serialization.
- The constructors for =Array= and =List= are used by the combinators we saw earlier.
- The =Obj= and =Objs= constructors create JSON objects.
These are wrapped in the =Conv= constructor to remove nesting that results when these constructors are used naively.
- The =Mu= constructor is used to create self-referential definitions.
- The =Conv= constructor allows you to clean up a nested definition or compute another type from an existing one.
- The =Describe= and =Def= constructors are used to add documentation
The library also provides various wrappers and convenience functions to make constructing these objects easier.
Reading the documentation in the [[../src/minutils/data_encoding.mli][mli file]] should orient
you on how to use these functions and their purposes.

View File

@ -1,276 +0,0 @@
* The Error Monad
This has been adapted from a blog post on [[www.michelson-lang.com][michelson-lang.com]].
If you're not familiar with monads, go take a few minutes and read a tutorial. I personally got a lot out of this [[http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf][paper]] by Philip Wadler, but there are a ton of others available online. Find one that works for you. The error monad isn't terribly scary as Monads go, so once you feel like you understand the gist, come on back and see if you can understand what's going on.
I'm going to omit some convenience operations that a lot of monads provide in the examples below. If you want to add them, they're not difficult.
** Why you want the error monad
In Tezos, we don't want to have the node be crashable by an improper input. To avoid this possibility, it was decided that the system should not use exceptions for error handling. Instead, it uses an error monad. This design forces errors to be handled or carried through before an output can be used. Exceptions are still occasionally used, but this is mostly in the client and only for internal errors.
We also mix in the Lwt library, which we use for concurrency. This is combined with the error monad and is once again used pervasively throughout the codebase. The Lwt monad is a lot like promises in other languages.
Without further ado, let's write an error monad.
** A simple version of the error monad
Here's a very simple error monad.
#+BEGIN_SRC ocaml
module Error : sig
type 'a t
(* Create a value of type t *)
val return : 'a -> 'a t
(* For when a computation fails *)
val error : 'a t
(* Apply an operation to a value in the error monad *)
val (>>?) : 'a t -> ('a -> 'b t) -> 'b t (* bind *)
end = struct
type 'a t = Ok of 'a | Error
let return x = Ok x
let error = Error
let (>>?) value func =
match value with
| Ok x -> func x
| Error -> Error
end
#+END_SRC
So, is this what Tezos uses? We actually already have a lot of the structure that we'll use later. The basic idea is that you return a value that's correct and return an error if the operation failed. Outside of the error module, you can't actually introspect an error value. You can only dispatch on the correctness/incorrectness of the value using bind.
What's wrong here?
- We can't report any information about an error case
- We can't report error traces, something that's used to improve the quality of error messages throughout Tezos
- We can't handle some errors and continue executing
** A slight improvement
Let's now enhance our error reporting by allowing errors to contain a description string. Now we can report messages along with our errors. Is this enough of an improvement? Not really. We don't have any flexibility about how the printing works. We still can't create error traces and we can't handle errors and resume executing the program.
#+BEGIN_SRC ocaml
module Error : sig
type 'a t
val return : 'a -> 'a t
val error : string -> 'a t
val (>>?) : 'a t -> ('a -> 'b t) -> 'b t (* bind *)
val print_value : ('a -> string) -> 'a t -> unit
end = struct
type 'a t = Ok of 'a | Error of string
let return x = Ok x
let error s = Error s
let (>>?) value func =
match value with
| Ok x -> func x
| Error s -> Error s
let print_value func = function
| Ok x -> Printf.printf "Success: %s\n" (func x)
| Error s -> Printf.printf "Error: %s\n" s
end
#+END_SRC
** Traces
Now that we have the basic structure down, we can add a mechanism to let us include traces. As a note, the error type I had above is exactly the =result= type from the OCaml standard library. The traces are just lists of error messages. If you have a call you think might fail, and you want to provide a series of errors, you can wrap that result in the =trace= function. If that call fails, an additional error is added.
#+BEGIN_SRC ocaml
module Error : sig
type 'a t
val return : 'a -> 'a t
val error : string -> 'a t
val (>>?) : 'a t -> ('a -> 'b t) -> 'b t (* bind *)
val print_value : ('a -> string) -> 'a t -> unit
val trace : string -> 'a t -> 'a t
end = struct
type 'a t = ('a, string list) result
let return x = Ok x
let error s = Error [ s ]
let (>>?) value func =
match value with
| Ok x -> func x
| Error errs -> Error errs
let print_value func = function
| Ok x -> Printf.printf "Success: %s\n" (func x)
| Error [ s ] -> Printf.printf "Error: %s\n" s
| Error errors -> Printf.printf "Errors:\t%s\n" (String.concat "\n\t" errors)
let trace error = function
| Ok x -> Ok x
| Error errors -> Error (error :: errors)
end
#+END_SRC
** A more descriptive message
Even though traces are nice, we really want to be able to store more interesting data in the messages. We're going to use an extensible variant type to do this. Extensible variants allow us to add a new case to a variant type at the cost of exhaustivity checking. We're going to need two new mechanisms to make this work well. The first is an error registration scheme. In the actual error monad, this involves the data encoding module, which is how all data is encoded/decoded in Tezos. This module is another decently complicated part of the codebase that should probably the subject of a future post. Since you can declare arbitrary new errors, we'll have a way of adding a printer for each error.
When we add a new error handler, we'll use the =register_handler= function. This function will take a function that takes an error and returns a =string option=. These functions will look something like this:
#+BEGIN_SRC ocaml
type error += Explosion_failure of string * int;;
register_error
(function
| Explosion_failure (s, i) ->
Some (Printf.sprintf "Everything exploded: %s at %d" s i)
| _ -> None)
#+END_SRC
I'm also renaming the =error= function to =fail=. This is the convention used by the actual Error_monad module. I'm also exposing the ='a t= type so that you can dispatch on it if you need to. This is used several times in the Tezos codebase.
#+BEGIN_SRC ocaml
module Error : sig
type error = ..
type 'a t = ('a, error list) result
val return : 'a -> 'a t
val fail : error -> 'a t
val (>>?) : ('a -> 'b t) -> 'a t -> 'b t (* bind *)
val print_value : ('a -> string) -> 'a t -> unit
val trace : error -> 'a t -> 'a t
end = struct
type error = ..
type 'a t = ('a, error list) result
let fail error = Error [ error ]
let return x = Ok x
let (>>?) func = function
| Ok x -> func x
| Error errs -> Error errs
let registered = ref []
let register_error handler =
registered := (handler :: !registered)
let default_handler error =
"Unregistered error: " ^ Obj.(extension_name @@ extension_constructor error)
let to_string error =
let rec find_handler = function
| [] -> default_handler error
| handler :: handlers ->
begin match handler error with
| None -> find_handler handlers
| Some s -> s
end
in find_handler !registered
let print_value func = function
| Ok x -> Printf.printf "Success: %s\n" (func x)
| Error [ s ] -> Printf.printf "Error: %s\n" (to_string s)
| Error errors -> Printf.printf "Errors:\t%s\n" (String.concat "\n\t" (List.map to_string errors))
let trace error = function
| Ok x -> Ok x
| Error errors -> Error (error :: errors)
end
#+END_SRC
** Putting =Lwt.t= in the mix
Tezos uses the [[http://ocsigen.org/lwt/][Lwt library]] for threading. The Lwt monad is mixed in with the error monad module. This requires us to add some extra combinators and reexport some functions from Lwt.
I'm also renaming the type =t= to =tzresult=, as used in the Tezos codebase.
#+BEGIN_SRC ocaml
module Error : sig
type error = ..
type 'a tzresult = ('a, error list) result
val ok : 'a -> 'a tzresult
val return : 'a -> 'a tzresult Lwt.t
val error : error -> 'a tzresult
val fail : error -> 'a tzresult Lwt.t
val (>>?) : 'a tzresult -> ('a -> 'b tzresult) -> 'b tzresult (* bind *)
val (>>=?) : 'a tzresult Lwt.t -> ('a -> 'b tzresult Lwt.t) -> 'b tzresult Lwt.t
val (>>=) : 'a Lwt.t -> ('a -> 'b Lwt.t) -> 'b Lwt.t
val print_value : ('a -> string) -> 'a tzresult Lwt.t -> unit Lwt.t
val trace : error -> 'a tzresult Lwt.t -> 'a tzresult Lwt.t
end = struct
type error = ..
type 'a tzresult = ('a, error list) result
let fail error = Lwt.return (Error [ error ])
let error error = (Error [ error ])
let ok x = Ok x
let return x = Lwt.return (ok x)
let (>>?) value func =
match value with
| Ok x -> func x
| Error errs -> Error errs
let (>>=) = Lwt.bind
let (>>=?) value func =
value >>= function
| Ok x -> func x
| Error errs -> Lwt.return (Error errs)
let registered = ref []
let register_error handler =
registered := (handler :: !registered)
let default_handler error =
"Unregistered error: " ^ Obj.(extension_name @@ extension_constructor error)
let to_string error =
let rec find_handler = function
| [] -> default_handler error
| handler :: handlers ->
begin match handler error with
| None -> find_handler handlers
| Some s -> s
end
in find_handler !registered
let print_value func value =
value >>= fun value ->
begin match value with
| Ok x -> Printf.printf "Success: %s\n" (func x)
| Error [ s ] -> Printf.printf "Error: %s\n" (to_string s)
| Error errors -> Printf.printf "Errors:\t%s\n" (String.concat "\n\t" (List.map to_string errors))
end; Lwt.return ()
let trace error value =
value >>= function
| Ok x -> return x
| Error errors -> Lwt.return (Error (error :: errors))
end
#+END_SRC
** The actual Tezos error monad
The actual Tezos error monad adds a few things. Firstly, there are three categories of errors:
- =`Temporary= - An error resulting from an operation that might be valid in the future, for example, a contract's balance being too low to execute the intended operation. This can be fixed by adding more to the contract's balance.
- =`Branch= - An error that occurs in one branch of the chain, but may not occur in a different one. For example, receiving an operation for an old or future protocol version.
- =`Permanent= - An error that is not recoverable because the operation is never going to be valid. For example, an invalid ꜩ notation.
The registration scheme also uses data encodings. Here's an example from the [[file:~/tezos/src/node/shell/validator.ml][validator]]:
#+BEGIN_SRC ocaml
register_error_kind
`Permanent
~id:"validator.wrong_level"
~title:"Wrong level"
~description:"The block level is not the expected one"
~pp:(fun ppf (e, g) ->
Format.fprintf ppf
"The declared level %ld is not %ld" g e)
Data_encoding.(obj2
(req "expected" int32)
(req "provided" int32))
(function Wrong_level (e, g) -> Some (e, g) | _ -> None)
(fun (e, g) -> Wrong_level (e, g))
#+END_SRC
An error takes a category, id, title, description, and encoding. You must specify a function to take an error to an optional value of the encoding type and a function to take a value of the encoded type and create an error value. A pretty printer can optionally be specified, but may also be omitted.
The actual error monad and it's tracing features can be seen in this function which parses contracts:
#+BEGIN_SRC ocaml
let parse_script
: ?type_logger: (int * (Script.expr list * Script.expr list) -> unit) ->
context -> Script.storage -> Script.code -> ex_script tzresult Lwt.t
= fun ?type_logger ctxt
{ storage; storage_type = init_storage_type }
{ code; arg_type; ret_type; storage_type } ->
trace
(Ill_formed_type (Some "parameter", arg_type))
(Lwt.return (parse_ty arg_type)) >>=? fun (Ex_ty arg_type) ->
trace
(Ill_formed_type (Some "return", ret_type))
(Lwt.return (parse_ty ret_type)) >>=? fun (Ex_ty ret_type) ->
trace
(Ill_formed_type (Some "initial storage", init_storage_type))
(Lwt.return (parse_ty init_storage_type)) >>=? fun (Ex_ty init_storage_type) ->
trace
(Ill_formed_type (Some "storage", storage_type))
(Lwt.return (parse_ty storage_type)) >>=? fun (Ex_ty storage_type) ->
let arg_type_full = Pair_t (arg_type, storage_type) in
let ret_type_full = Pair_t (ret_type, storage_type) in
Lwt.return (ty_eq init_storage_type storage_type) >>=? fun (Eq _) ->
trace
(Ill_typed_data (None, storage, storage_type))
(parse_data ?type_logger ctxt storage_type storage) >>=? fun storage ->
trace
(Ill_typed_contract (code, arg_type, ret_type, storage_type, []))
(parse_returning (Toplevel { storage_type }) ctxt ?type_logger arg_type_full ret_type_full code)
>>=? fun code ->
return (Ex_script { code; arg_type; ret_type; storage; storage_type })
#+END_SRC
Each specific type error from the typechecking process is wrapped in a more general error that explains which part of the program was malformed. This improves the error reporting. You can also see the bind operator used between functions to continue only if an error does not occur. This function also operates in the =Lwt= monad, which is largely hidden via the error monad.

53
docs/index.rst Normal file
View File

@ -0,0 +1,53 @@
.. Tezos documentation master file, created by
sphinx-quickstart on Sat Nov 11 11:08:48 2017.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Tezos's documentation!
=================================
.. toctree::
:maxdepth: 2
:caption: Introduction:
introduction/readme
introduction/contributing
.. toctree::
:maxdepth: 2
:caption: The Alphanet:
introduction/alphanet
introduction/alphanet_changes
introduction/zeronet
.. toctree::
:maxdepth: 2
:caption: White doc:
whitedoc/the_big_picture
whitedoc/michelson
.. toctree::
:maxdepth: 2
:caption: Tutorials:
tutorials/data_encoding
tutorials/error_monad
tutorials/michelson_anti_patterns
tutorials/entering_alpha
tutorials/protocol_environment
.. toctree::
:maxdepth: 2
:caption: OCaml API:
README
api/api-inline
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -0,0 +1,309 @@
Participating in the Alphanet
=============================
Welcome to the Tezos alphanet, which is a pre-release network for the
Tezos blockchain. Currently, the chain is reset every few weeks.
For news and support about the alphanet, please join IRC (``#tezos`` on
freenode). Please, report bugs related to the alphanet on the IRC
channel before filling Github issues.
For more information about the project in general, see:
https://www.tezos.com/
How to join the alphanet ?
--------------------------
We provide two ways of joining the alphanet :
- use ``docker`` and prebuilt binaries (recommended way, tested on
windows/mac/linux)
- manual compilation and installation (linux and mac only)
The ``alphanet.sh`` script
~~~~~~~~~~~~~~~~~~~~~~~~~~
The recommended way for running an up-to-date Tezos node connected to
the alphanet is to use ``scripts/alphanet.sh``. Its only requirement is
a working installation of Docker:
https://www.docker.com/community-edition
First, you need to download the script:
::
wget https://raw.githubusercontent.com/tezos/tezos/alphanet/scripts/alphanet.sh
chmod +x alphanet.sh
You are now one step away from a working node:
::
./alphanet.sh start
This will launch a docker container running the various daemons that
form a working tezos node. The first launch might take a few minutes to
synchronize the chain.
On first launch the script will also create a cryptographic identity
(nicknamed ``my_identity``) and provide you with free tezzies on a fresh
account (nicknamed ``my_account``). You might check your balance with:
::
./alphanet.sh client get balance for my_account
On some circumstances the account creation might fail. If so, see
section “Known issues” below on how to force the account creation.
See ``./alphanet.sh --help`` for more informations about the script. In
particular see ``./alphanet.sh client --help`` and
``scripts/README.master`` for more information about the client.
Every call to ``alphanet.sh`` will check for updates of the node and
will fail if your node is not up-to-date. For updating the node, simply
run:
::
./alphanet.sh restart
If you prefer to temporarily disable automatic updates, you just have to
set an environment variable:
::
export TEZOS_ALPHANET_DO_NOT_PULL=yes
Compilation from sources
~~~~~~~~~~~~~~~~~~~~~~~~
The ``alphanet`` branch in the tezos git repository will always contain
the up-to-date sources of the tezos-node required for running the
alphanet. See ``docs/README.master`` on how to compile it.
Once built, you might launch the a node by running:
::
./tezos-node identity generate 24.
./tezos-node run --rpc-addr localhost
By default this instance will store its data in ``$HOME/.tezos-node``
and will listen to incoming peers on port 9732. It will also listen to
RPC requests on port 8732 (only from ``localhost``). You might find more
options by running ``./tezos-node config --help``.
If you want to stake (see below for more details), you will also have to
run:
::
./tezos-client launch daemon
Thats all. For the rest of the document, to execute the example
commands, you will have to replace ``./alphanet.sh client`` by
``./tezos-client``.
How to observe the network ?
----------------------------
The alphanet script provides a basic command ``./alphanet.sh head`` that
allows you to see if your own node is synchronized.
The Tezos client also offers a lot of commands to introspect the state
of the node, and also to list and call the RPCs of the nodes.
Enthusiastic Tezos adopter fredcy has also developed a nice block
explorer for the alphanet. See https://github.com/fredcy/tezos-client.
In an upcoming version, we will also provide an opt-in tool for node
runners that will allow us to provide a global monitoring panel of the
alphanet.
How to obtain free Tez from the faucet contract ?
-------------------------------------------------
The alphanet contains an ad-hoc faucet contract, that will generate new
tezzies for you to test. Obviously, this contract will not be available
outside of the test network.
First, if you dont have any cryptographic identity yet, you need to
generate one (replace ``my_identity`` with any name that suits you
best):
::
./alphanet.sh client gen keys "my_identity"
Then, you have to generate a new “free” account (replace ``my_account``
with any name that suits you best and ``my_identity`` by the name used
in the previous command):
::
./alphanet.sh client originate free account "my_account" for "my_identity"
Thats all. You might check your balance:
::
./alphanet.sh client get balance for "my_account"
If you want MORE tezzies, you need to generate as many free accounts as
you need (you should receive ꜩ100.000 per account) and then transfer the
tezzies into a single account. For instance:
::
./alphanet.sh client originate free account "my_alt_account" for "my_identity"
./alphanet.sh client transfer 100,000.00 from "my_alt_account" to "my_account" -fee 0.00
./alphanet.sh client forget contract "my_alt_account"
Note that the test network is kind enough to accept transactions without
fees…
How to play with smart-contracts ?
----------------------------------
An advanced documentation of the smart contract language is in
``/docs/language.md``
Some test contracts are in
``/tests/contracts/``
For details and examples, see:
http://www.michelson-lang.com/
How to stake on the alphanet ?
------------------------------
By default, the faucet of the alphanet (the one behind
``./alphanet.sh originate free account "my_account" for "my_identity"``)
creates contracts which are managed by ``my_identity`` but whose staking
rights are delegated to the baker of the block including the
origination. That way we are sure that staking rights are attributed to
an active baker.
But, nonetheless, you might claim your staking rights!
The following command returns the current delegate of a contract:
::
./alphanet.sh client get delegate for "my_account"
If it is one the following, it is indeed one of our “bootstrap”
contracts!
- ``tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc``
- ``tz1irovm9SKduvL3npv8kDM54PSWY5VJXoyz``
- ``tz1UsgSSdRwwhYrqq7iVp2jMbYvNsGbWTozp``
- ``tz1TwYbKYYJxw7AyubY4A9BUm2BMCPq7moaC``
- ``tz1QWft73Zhj5VSA1sCuEi9HhDDJqywE6BtC``
You might change the delegate of a contract with a single command:
::
./alphanet.sh client set delegate for "my_account" to "my_identity"
You now have staking rights!
Well, almost.
You should wait.
A little bit.
At most two cycles. Which, on the alphanet is 128 blocks (something
around 2 hours). On the mainnet, this will be between 2 weeks and a
month.
But, to enforce your right a last step is required. When baking or
endorsing a block, a bond is taken out of the default account associated
to the public key of the delegate. Hence, in order to stake, you must be
provisioning for bond deposit.
::
./alphanet.sh client transfer 50,000.00 from "my_account" to "my_identity"
On the alphanet, a bond is ꜩ1000. Hence, with the previous command you
provisioned 50 bonds. If you want more, see section “How to obtain free
Tez from the faucet contract ?”.
Now, you are settled. The ``alphanet`` docker image runs a baker daemon
and a endorser daemon, by default for all your keys.
To know if you staked, just run:
::
./alphanet.sh baker log
./alphanet.sh endorser log
You should see lines such as:
::
Injected block BLxzbB7PBW1axq for bootstrap5 after BLSrg4dXzL2aqq (level 1381, slot 0, fitness 00::0000000000005441, operations 21)
Or:
::
Injected endorsement for block 'BLSrg4dXzL2aqq' (level 1381, slot 3, contract bootstrap5) 'oo524wKiEWBoPD'
On the alphanet, rewards for staking are credited after 24 hours. The
reward for baking or endorsing a block is ꜩ150. The safety bond is
returned together with the reward.
To know when you will be allowed to stake in the current cycle, you
might try the following RPCs, where you replaced ``tz1iFY8ads...`` by
the appropriate value:
::
$ ./alphanet.sh client list known identities
my_identity: tz1iFY8aDskx9QGbgBy68SNAGgkc7AE2iG9H (public key known) (secret key known)
$ ./alphanet.sh client rpc call /blocks/head/proto/helpers/rights/baking/delegate/tz1iFY8aDskx9QGbgBy68SNAGgkc7AE2iG9H with '{}'
{ "ok":
[ { "level": 1400.000000, "priority": 2.000000,
"timestamp": "2017-05-19T03:21:52Z" },
... ] }
Known issues
------------
Missing account ``my_account``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The chain synchronization has not been optimized yet and the
``alphanet.sh`` script might mis-detect the end of the synchronization
step. If so, it will try to create your free account in an outdated
context and your new account will never be included in the chain.
To fix this, just wait for your node to be synchronized: for that run
the following command, in the middle of a (raw) json object, it should
display the date of the last block (which should not be too far in the
past):
::
./alphanet.sh head
Please note that the printed date is GMT, dont forget the time shift.
Then, you need to remove from the client state the non-existent contract
and regenerate a new one:
::
./alphanet.sh client forget contract "my_account"
./alphanet.sh client originate free account "my_account" for "my_identity"

View File

@ -0,0 +1 @@
../../CHANGES.alphanet

View File

@ -0,0 +1 @@
../../CHANGES.alphanet

View File

@ -0,0 +1,82 @@
How to contribute
=================
Introduction
------------
The purpose of this document is to help contributors get started with
the Tezos OCaml codebase.
First steps
-----------
First, make sure that you are proficient enough in OCaml. The community
Website http://www.ocaml.org below gives a few pointer for that. In
particular, we use a lot of functors, and a few GADTs in the codebase,
so you may want to make sure that you master these advanced concepts.
Then, if you dont know well about the Lwt library, thats what you want
to learn. This library is used extensively throughout the code base, as
thats the one we use to handle concurrency, and Tezos is a very
concurrent system. You can use the online documentation. The `PDF
manual <https://ocsigen.org/download/lwt-manual.pdf>`__ is also quite
well written, but unfortunately not up to date, in particular the syntax
extension has changed. It is still a valid resource for the basic
concepts. The chapter on concurrency of `Real World
OCaml <https://github.com/dkim/rwo-lwt>`__ has also been ported to Lwt.
After that, it is a good idea to read the tutorials for
:ref:`error_monad<error_monad>` and
:ref:`data_encoding <data_encoding>`, two homegrown
libraries that we use pervasively.
Where to start
--------------
While you familiarize yourself with the basics as suggested above, you
can have a look at the :ref:`software architecture
<the_big_picture>` of Tezos. It will
give you the main components and their interactions, and links to the
documentations for the various parts.
Our git workflow
----------------
First, the repository is http://gitlab.com/tezos/tezos, the github one
is just a clone that exists for historical reasons. So if you want to
contribute, simply create an account there.
Then, there are many ways to use Git, here is ours.
We use almost only merge requests to push into master. Meaning, nobody
should push directly into master. Once a merge request is ready, it is
reviewed and approved, we merge it using the ``--fast-forward`` option
of Git, in order to maintain a linear history without merge patches.
For that to work, it means that merge requests must be direct suffixes
of the master branch. So whenever ``origin/master`` changes, you have to
rebase your branch on it, so that you patches always sit on top of
master. When that happens, you may have to edit your patches during the
rebase, and then use ``push -f`` in your branch to rewrite the history.
We also enforce a few hygiene rules, so make sure your MR respects them:
- Prefer small atomic commits over a large one that do many things.
- Dont mix refactoring and new features.
- Never mix reindentation, whitespace deletion, or other style changes
with actual code changes.
- Try as much as possible to make every patch compile, not only the
last.
- If you add new functions into a documented interface, dont forget to
extend the documentation for your addition.
- For parts whose specification is in the repository (e.g. Michelson),
make sure to keep it in sync with the implementation.
- Try and mimic the style of commit messages, and for non trivial
commits, add an extended commit message.
As per the hygiene of MRs themselves:
- Give appropriate titles to the MRs, and when non trivial add a
detailed motivated explanation.
- Give meaningful and consistent names to branches.
- Dont forget to put a ``WIP:`` flag when it is a work in progress.

View File

@ -0,0 +1,10 @@
The zeronet network
===================
The Tezos zeronet is a development network that might be broken multiple
times a day.
If you wish to experiment with Tezos we recommend you to test the
``alphanet``, which is a more stable test network.
In particular, we offer no support about the zeronet.

129
docs/logo.svg Normal file
View File

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48.739811mm"
height="22.914806mm"
viewBox="0 0 48.739811 22.914806"
version="1.1"
id="svg5074"
inkscape:version="0.92.1 r15371"
sodipodi:docname="logo.svg">
<defs
id="defs5068" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="152.39587"
inkscape:cy="33.859768"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1311"
inkscape:window-x="0"
inkscape:window-y="55"
inkscape:window-maximized="1"
inkscape:measure-start="71.0714,60.5357"
inkscape:measure-end="109.286,25.8929"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true" />
<metadata
id="metadata5071">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-58.404451,-81.16997)">
<path
style="opacity:1;fill:#4d4d4d;fill-opacity:1;stroke-width:1.22451675"
d="m 61.072266,-14.291016 a 32.000002,32.000002 0 0 0 -32,32 32.000002,32.000002 0 0 0 32,32 h 1.21289 94.751954 1.21289 a 32.000002,32.000002 0 0 0 32,-32 32.000002,32.000002 0 0 0 -32,-32 h -1.21289 -94.751954 z"
transform="matrix(0.26458333,0,0,0.26458333,56.807283,87.908796)"
id="path4516"
inkscape:connector-curvature="0" />
<circle
style="opacity:1;fill:#000000;fill-opacity:1;stroke-width:0.35944793"
id="path4529"
cx="69.861855"
cy="92.627373"
r="11.457403" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:18.16365242px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.45409128"
x="64.233612"
y="94.434319"
id="text5621"
transform="scale(0.98259142,1.017717)"><tspan
sodipodi:role="line"
id="tspan5619"
x="64.233612"
y="94.434319"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Code2000;-inkscape-font-specification:Code2000;fill:#ffffff;stroke-width:0.45409128">ꜩ</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="84.777519"
y="86.395416"
id="text5633"><tspan
sodipodi:role="line"
x="84.777519"
y="95.759186"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.88055563px;line-height:0;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:0.26458332"
id="tspan5650" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.88055563px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="91.852211"
y="95.18335"
id="text5660"><tspan
sodipodi:role="line"
x="91.852211"
y="95.18335"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0;font-family:Lato;-inkscape-font-specification:Lato;text-align:center;text-anchor:middle;fill:#ffffff;stroke-width:0.26458332"
id="tspan4521">Developer</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.88055563px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="83.283157"
y="98.462372"
id="text4535"><tspan
sodipodi:role="line"
id="tspan4533"
x="83.283157"
y="98.462372"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Lato;-inkscape-font-specification:Lato;fill:#ffffff;stroke-width:0.26458332">Resources</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.88055563px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="85.401657"
y="90.288643"
id="text4541"><tspan
sodipodi:role="line"
id="tspan4539"
x="85.401657"
y="90.288643"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:'Roboto Slab';-inkscape-font-specification:'Roboto Slab';fill:#ffffff;stroke-width:0.26458332">Tezos</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB

File diff suppressed because it is too large Load Diff

View File

@ -1,88 +0,0 @@
* Michelson Anti-Patterns
Even though Michelson is designed to make it easy to write secure contracts and difficult to write vulnerable ones, it is still possible to write buggy contracts that leak data and funds. This is a list of mistakes that you can make when writing or interacting with contracts on the Tezos blockchain and alternative ways to write code that avoid these problems.
_Note_: We are currently reworking the concurrency model of Michelson (how and when subtransactions ar made), so that some of these patterns will be prevented by the language itself.
** Refunding to a list of contracts
One common pattern in contracts is to refund a group of people's funds at once.
This is problematic if you accepted arbitrary contracts as a malicious user can
do cause various issues for you.
*** Possible issues:
- One contract swallows all the gas through a series of callbacks
- One contract writes transactions until the block is full
- Reentrancy bugs. Michelson intentionally makes these difficult to write, but it is still possible if you try.
- A contract calls the `FAIL` instruction, stopping all computation.
*** Alternatives/Solutions:
- Create a default account from people's keys. Default accounts cannot execute code, avoiding the bugs above. Have people submit keys rather than contracts.
- Have people pull their funds individually. Each user can break their own withdrawal only. *This does not protect against reentrancy bugs.*
** Avoid batch operations when users can increase the size of the batch
Contracts that rely on linear or super-linear operations are vulnerable to
malicious users supplying values until the contract cannot finish without
running into fuel limits. This can deadlock your contract.
*** Possible issues:
- Malicious users can force your contract into a pathological worst case, stopping it from finishing with available gas. Note that in the absence of hard gas limits, this can still be disabling as node operators may not want to run contracts that take more than a certain amount of gas.
- You may hit the slow case of an amortized algorithm or data structure at an inopportune time, using up all of your contract's available gas.
*** Alternatives/Solutions:
- Avoid data structures and algorithms that rely on amortized operations, especially when users may add data.
- Restrict the amount of data your contract can store to a level that will not overwhelm the available gas.
- Write your contract so that it may pause and resume batch operations. This would complicate these sequences and require constant checking of available gas, but it prevents various attacks.
*Do not assume an attack will be prohibitively expensive*
Cryptocurrencies have extreme price fluctuations frequently and an extremely motivated attacker may decide that an enormous expense is justified. Remember, an attack that disables a contract is not just targeted at the authors, but also the users of that contract.
** Signatures alone do not prevent replay attacks
If your contract uses signatures to authenticate messages, beware of replay attacks. If a user ever signs a piece of data, you /must/ make sure that that piece of data is never again a valid message to the contract. If you do not do this, anyone else can call your contract with the same input and piggyback on the earlier approval.
*** Possible issues:
- A previously approved action can be replayed.
*** Alternatives/Solutions
- Use an internal counter to make the data you ask users to sign unique. This counter should be per key so that users can find out what they need to approve. This should be paired with a signed hash of your contract to prevent cross-contract replays.
- Use the =SOURCE= instruction to verify that the expected sender is the source of the message.
*** Do not assume users will use a unique key for every smart contract
Users should always use a different key for every contract with which they interact. If this is not the case, a message the user signed for another contract can be sent to your contract. An internal counter alone does not protect against this attack. It /must/ be paired with a hash of your contract. You must verify the source of the message.
** Storing/transferring private data
Once data is published to anyone, including broadcasting a transaction, that data is public. Never transmit secret information via any part of the blockchain ecosystem. As soon as you have broadcast a transaction including that piece of information, anyone can see it. Furthermore, malicious nodes in the system can manipulate unsigned transactions by delaying, modifying, or reordering them.
*** Possible Issues
- If data is not signed, it can be modified
- Transactions can be delayed
- Secret information will become public
*** Alternatives/Solutions
- Do not store private information on the blockchain or broadcast it in transactions.
- Sign all transactions that contain information that, if manipulated, could be abused.
- Use counters to enforce transaction orders.
This will at least create a logical clock on messages sent to your contract.
** Not setting all state before a transfer
Reentrancy is a potential issue on the blockchain. When a contract makes a transfer to another contract, that contract can execute its own code,
and can make arbitrary further transfers, including back to the original contract. If state has not been updated before the transfer is made, a contract can call back in and execute actions based on old state.
*** Possible Issues
- Multiple withdrawals/actions
- Generating illegal state if state is updated twice later
*** Alternatives/Solutions
- Forbid reentrancy by means of a flag in your storage, unless you have a good reason to allow users to reenter your contract, this is likely the best option.
- Only make transfers to trusted contracts or default accounts. Default accounts cannot execute code, so it is always safe to transfer to them. Before trusting a contract, make sure that its behavior cannot be modified and that you have an extremely high degree of confidence in it.
** Do not store funds for others in spendable contracts
Tezos allows contracts to be marked as spendable. Managers of spendable contracts can make transfers using the funds stored inside the contract. This can subvert guarantees about the contract's behavior that are visibile in the code.
*** Possible Issues
- The funds of a contract can be removed.
- A contract may not be able to meet its obligations
*** Alternatives/Solutions
- Do not store funds in spendable contracts that you do not control.

View File

@ -0,0 +1,206 @@
.. _data_encoding:
The ``data_encoding`` library
=============================
Throughout the Tezos protocol, data is serialized so that it can be used
via RPC, written to disk, or placed in a block. This
serialization/de-serialization is handled via the :package:`tezos-data-encoding`
library by providing a set primitive encodings and a variety of combinators.
Examples/Tutorial
-----------------
Encoding an integer
~~~~~~~~~~~~~~~~~~~
Integers are defined as other concrete data types with a generic
encoding type ``type 'a encoding``. This means that it is an encoding
to/from type ``int``. There are a variety of ways to encode an integer,
depending on what binary serialization you want to achieve:
- ``Data_encoding.int8``
- ``Data_encoding.uint8``
- ``Data_encoding.int16``
- ``Data_encoding.uint16``
- ``Data_encoding.int31``
- ``Data_encoding.int32``
- ``Data_encoding.int64``
For example, an encoding that represents a 31 bit integer has type
``Data_encoding.int31 = int Data_encoding.encoding``.
.. code:: ocaml
let int31_encoding = Data_encoding.int31
Encoding an object
~~~~~~~~~~~~~~~~~~
Encoding a single integer is fairly uninteresting. The Dataencoding
library provides a number of combinators that can be used to build more
complicated objects. Consider the type that represents an interval from
the first number to the second:
.. code:: ocaml
type interval = int64 * int64
We can define an encoding for this type as:
.. code:: ocaml
let interval_encoding =
Data_encoding.(obj2 (req "min" int64) (req "max" int64))
In the example above we construct a new value ``interval_encoding`` by
combining two int64 integers using the ``obj2`` constructor.
The library provides different constructors, i.e. for objects that have
no data (``Data_encoding.empty``), constructors for object up to 10
fields, constructors for tuples, list, etc.
These are serialized to binary by converting each internal object to
binary and placing them in the order of the original object and to JSON
as a JSON object with field names.
Lists, arrays, and options
~~~~~~~~~~~~~~~~~~~~~~~~~~
List, Arrays and options types can by built on top of ground data types.
.. code:: ocaml
type interval_list = interval list
type interval_array = interval array
type interval_option = interval option
And the encoders for these types as
.. code:: ocaml
let interval_list_encoding = Data_encoding.list interval_encoding
let interval_array_encoding = Data_encoding.array interval_encoding
let interval_option_encoding = Data_encoding.option interval_encoding
Union types
~~~~~~~~~~~
The Tezos codebase makes heavy use of variant types. Consider the
following variant type:
.. code:: ocaml
type variant = B of bool
| S of string
Encoding for this types can be expressed as:
.. code:: ocaml
let variant_encoding =
Data_encoding.(union ~tag_size:`Uint8
[ case
bool
(function B b -> Some b | _ -> None)
(fun b -> B b) ;
case
string
(function S s -> Some s | _ -> None)
(fun s -> S s) ])
This variant encoding is a bit more complicated. Lets look at the parts
of the type:
- We include an optimization hint to the binary encoding to inform it
of the number of elements we expect in the tag. In most cases, we can
use :literal:`\`Uint8`, which allows you to have up to 256 possible
cases (default).
- We provide a function to wrap the datatype. The encoding works by
repeatedly trying to decode the datatype using these functions until
one returns ``Some payload``. This payload is then encoded using the
dataencoding specified.
- We specify a function from the encoded type to the actual datatype.
Since the library does not provide an exhaustive check on these
constructors, the user must be careful when constructing unin types to
avoid unfortunate runtime failures.
How the Dataencoding module works
---------------------------------
This section is 100% optional. You do not need to understand this
section to use the library.
The library uses GADTs to provide type-safe
serialization/de-serialization. From there, a runtime representation of
JSON objects is parsed into the type-safe version.
First we define an untyped JSON AST:
.. code:: ocaml
type json =
[ `O of (string * json) list
| `Bool of bool
| `Float of float
| `A of json list
| `Null
| `String of string ]
This is then parsed into a typed AST ( we eliminate several cases for
clarity):
.. code:: ocaml
type 'a desc =
| Null : unit desc
| Empty : unit desc
| Bool : bool desc
| Int64 : Int64.t desc
| Float : float desc
| Bytes : Kind.length -> MBytes.t desc
| String : Kind.length -> string desc
| String_enum : Kind.length * (string * 'a) list -> 'a desc
| Array : 'a t -> 'a array desc
| List : 'a t -> 'a list desc
| Obj : 'a field -> 'a desc
| Objs : Kind.t * 'a t * 'b t -> ('a * 'b) desc
| Tup : 'a t -> 'a desc
| Union : Kind.t * tag_size * 'a case list -> 'a desc
| Mu : Kind.enum * string * ('a t -> 'a t) -> 'a desc
| Conv :
{ proj : ('a -> 'b) ;
inj : ('b -> 'a) ;
encoding : 'b t ;
schema : Json_schema.schema option } -> 'a desc
| Describe :
{ title : string option ;
description : string option ;
encoding : 'a t } -> 'a desc
| Def : { name : string ;
encoding : 'a t } -> 'a desc
- The first set of constructors define all ground types.
- The constructors for ``Bytes``, ``String`` and ``String_enum``
includes a length fields in order to provide safe binary
serialization.
- The constructors for ``Array`` and ``List`` are used by the
combinators we saw earlier.
- The ``Obj`` and ``Objs`` constructors create JSON objects. These are
wrapped in the ``Conv`` constructor to remove nesting that results
when these constructors are used naively.
- The ``Mu`` constructor is used to create self-referential
definitions.
- The ``Conv`` constructor allows you to clean up a nested definition
or compute another type from an existing one.
- The ``Describe`` and ``Def`` constructors are used to add
documentation
The library also provides various wrappers and convenience functions to
make constructing these objects easier. Reading the documentation in the
`mli file
<../api/odoc/tezos-data-encoding/Tezos_data_encoding/Data_encoding/index.html>`__
should orient you on how to use these functions and their purposes.

View File

@ -0,0 +1,196 @@
How to start reading protocol Alpha
===================================
Protocol Alpha, whose Alpha has nothing to do with the one in Alphanet,
is the name of the initial economic protocol. Alpha is a placeholder
name, while we decide on the naming convention for protocol versions.
Before reading that document, you may want to:
- read the whitepaper,
- read :ref:`how the economic protocol is
sandboxed <protocol_environment>`.
As all protocols, Alpha is made of a series of OCaml interface and
implementation files, accompanied by a ``TEZOS_PROTOCOL`` file.
The ``TEZOS_PROTOCOL`` structure
--------------------------------
If you look at this file in the repository, you will see that it is
composed of the hash of the sources, and the list of its modules, in
linking order.
Protocol Alpha is structured as a tower of abstraction layers, a coding
discipline that we designed to have OCaml check as many invariants as
possible at typing time. You will also see empty lines in
``TEZOS_PROTOCOL`` that denotate these layers of abstraction.
These layers follow the linking order: the first modules are the towers
foundation that talk to the raw key-value store, and going forward in
the module list means climbing up the abstraction tower.
The big abstraction barrier: ``Tezos_context``
----------------------------------------------
the proof-of-stake algorithm, as described in the white paper, relies on
an abstract state of the ledger, that is read and transformed during
validation of a block.
Due to the polymorphic nature of Tezos, the ledgers state (that we call
**context** in the code), cannot be specific to protocol Alphas need.
The proof-of-stake is thus implemented over a generic key-value store
whose keys and associated binary data must implement the abstract
structure.
The ``Tezos_context`` module enforces the separation of concerns
between, on one hand, mapping the abstract state of the ledger to the
concrete structure of the key-value store, and, on the other hand,
implementing the proof-of-stake algorithm over this state.
In more practical terms, ``Tezos_context`` defines a type ``t`` that
represents a state of the ledger. This state is an abstracted out
version of the key-value store that can only be manipulated through the
use of the few selected manipulations reexported by ``Tezos_context``,
that always preserve the well-typed aspect and internal consistency
invariants of the state.
When validating a block, the low-level state that result from the
predecessor block is read from the disk, then abstracted out to a
``Tezos_context.t``, which is then only updated by high level operations
that preserve consistency, and finally, the low level state is extracted
to be committed on disk.
This way, we have two well separated parts in the code. The code below
``Tezos_context`` implements the ledgers state storage, while the code
on top of it is the proof-of-stake algorithm. Thanks to this barrier,
the latter can remain nice, readable OCaml that only manipulates plain
OCaml values.
Below the ``Tezos_context``
---------------------------
For this part, in a first discovery of the source code, you can start by
relying mostly on this coarse grained description, with a little bit of
cherry-picking when youre curious about how a specific invariant is
enforced.
The ``*_repr`` modules
~~~~~~~~~~~~~~~~~~~~~~
These modules abstract the values of the raw key-value context by using
:ref:`Data_encoding<data_encoding>`.
These modules define the data types used by the protocol that need to be
serialized (amounts, contract handles, script expressions, etc.). For
each type, it also defines its serialization format using
:ref:`Data_encoding<data_encoding>`.
Above this layer, the code should never see the byte sequences in the
database, the ones of transmitted blocks and operations, or the raw JSON
of data transmitted via RPCs. It only manipulates OCaml values.
The ``Storage`` module and storage functors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Even with the concrete formats of values in the context abstracted out,
type (or consistency) errors can still occur if the code accesses a
value with a wrong key, or a key bound to another value. The next
abstraction barrier is a remedy to that.
The storage module is the single place in the protocol where key
litterals are defined. Hence, it is the only module necessary to audit,
to know that the keys are not colliding.
It also abstracts the keys, so that each kind of key get its own
accessors. For instance, module ``Storage.Contract.Balance`` contains
accessors specific to contracts balances.
Moreover, the keys bear the type of the values they point to. For
instance, only values of type ``Tez_repr.t`` can by stored at keys
``Storage.Contract.Balance``. And in case a key is not a global key, but
a parametric one, this key is parametered by an OCaml value, and not the
raw key part.
So in the end, the only way to be used when accessing a contract balance
is ``Storage.Contract.Balance.get``, which takes a ``Contract_repr.t``
and gives a ``Tez_repr.t``.
All these well-typed operations are generated by a set of functors, that
come just before ``Storage`` in ``TEZOS_CONTEXT``.
The ``*_storage`` modules
~~~~~~~~~~~~~~~~~~~~~~~~~
The two previous steps ensure that the ledgers state is always accessed
and updated in a well-typed way.
However, it does not enforce that, for instance, when a contract is
deleted, all of the keys that store its state in the context are indeed
deleted.
This last series of modules named ``*_storage`` is there to enforce just
that kind of invariants: ensuring the insternal consistency of the
context structure.
These transaction do not go as far as checking that, for instance, when
the destination of a transaction is credited, the source is also
debitted, as in some cases, it might not be the case.
Above the ``Tezos_context``
---------------------------
The three next sections describe the main entrypoints to the protocol:
validation of blocks by the shell (that we often also call application),
smart contracts, and RPC services.
The ``Main`` module is the entrypoint thats used by the shell. It
respects the module type that all protocol must follow. For that, its
code is mostly plumbing,
Starting from ``Apply``
~~~~~~~~~~~~~~~~~~~~~~~
This is were you want to start on your first read. Even if some plumbing
code is woven in, such as error cases declaration and registration, most
of the proof-of-stake code has been written in a verbose style, to be
understood with minimum OCaml knowledge.
You want to start from the shell entry points (validation of the block
header, validation of an operation, finalization of a block validation),
and follow the control flow until you hit the ``Tezos_context``
abstraction barrier. This will lead you to reading modules ``Baking``
and ``Amendment``.
Smart contracts
~~~~~~~~~~~~~~~
From ``Apply``, you will also end up in modules ``Script_ir_translator``
and ``Script_interpreter``. The former is the typechecker of Michelson
that is called when creating a new smart contract, and the latter is the
interpreter that is called when transfering tokens to a new smart
contract.
Protocol RPC API
~~~~~~~~~~~~~~~~
Finally, the RPCs specific to Alpha are also defined above the
``Tezos_context`` barrier. The definition is split into two parts.
The first part, ``Services``, defines the RPC API: URL schemes with the
types of parameters, and input and output JSON schemas. This interface
serves three purposes. As it is thourouhgly tyoed, it makes sure that
the handlers have the right input and output types. It is also used by
the client to perform RPC calls, to make sure that the URL schemes and
JSON formats and consistent between the two parties. These two features
are extremely useful when refactoring, as the OCaml typechecker will
help us track the effects of an RPC API change on the whole codebase.
The third purpose is of course, to make automatic documentation
generation possible (as in ``tezos client rpc list/format``).
It can be useful if you are a third party developer who wants to read
the OCaml definition of the service hierarchy directly, instead of the
automatically generated JSON hierarchy.
The second part, ``Services_registration``, is responsible for plugging
the OCaml handler functions that implement the RPC API.

View File

@ -0,0 +1,366 @@
.. _error_monad:
The Error Monad
===============
This has been adapted from a blog post on *michelson-lang.com*.
If youre not familiar with monads, go take a few minutes and read a
tutorial. I personally got a lot out of this
`paper <http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf>`__
by Philip Wadler, but there are a ton of others available online. Find
one that works for you. The error monad isnt terribly scary as Monads
go, so once you feel like you understand the gist, come on back and see
if you can understand whats going on.
Im going to omit some convenience operations that a lot of monads
provide in the examples below. If you want to add them, theyre not
difficult.
Why you want the error monad
----------------------------
In Tezos, we dont want to have the node be crashable by an improper
input. To avoid this possibility, it was decided that the system should
not use exceptions for error handling. Instead, it uses an error monad.
This design forces errors to be handled or carried through before an
output can be used. Exceptions are still occasionally used, but this is
mostly in the client and only for internal errors.
We also mix in the Lwt library, which we use for concurrency. This is
combined with the error monad and is once again used pervasively
throughout the codebase. The Lwt monad is a lot like promises in other
languages.
Without further ado, lets write an error monad.
A simple version of the error monad
-----------------------------------
Heres a very simple error monad.
.. code:: ocaml
module Error : sig
type 'a t
(* Create a value of type t *)
val return : 'a -> 'a t
(* For when a computation fails *)
val error : 'a t
(* Apply an operation to a value in the error monad *)
val (>>?) : 'a t -> ('a -> 'b t) -> 'b t (* bind *)
end = struct
type 'a t = Ok of 'a | Error
let return x = Ok x
let error = Error
let (>>?) value func =
match value with
| Ok x -> func x
| Error -> Error
end
So, is this what Tezos uses? We actually already have a lot of the
structure that well use later. The basic idea is that you return a
value thats correct and return an error if the operation failed.
Outside of the error module, you cant actually introspect an error
value. You can only dispatch on the correctness/incorrectness of the
value using bind.
Whats wrong here?
- We cant report any information about an error case
- We cant report error traces, something thats used to improve the
quality of error messages throughout Tezos
- We cant handle some errors and continue executing
A slight improvement
--------------------
Lets now enhance our error reporting by allowing errors to contain a
description string. Now we can report messages along with our errors. Is
this enough of an improvement? Not really. We dont have any flexibility
about how the printing works. We still cant create error traces and we
cant handle errors and resume executing the program.
.. code:: ocaml
module Error : sig
type 'a t
val return : 'a -> 'a t
val error : string -> 'a t
val (>>?) : 'a t -> ('a -> 'b t) -> 'b t (* bind *)
val print_value : ('a -> string) -> 'a t -> unit
end = struct
type 'a t = Ok of 'a | Error of string
let return x = Ok x
let error s = Error s
let (>>?) value func =
match value with
| Ok x -> func x
| Error s -> Error s
let print_value func = function
| Ok x -> Printf.printf "Success: %s\n" (func x)
| Error s -> Printf.printf "Error: %s\n" s
end
Traces
------
Now that we have the basic structure down, we can add a mechanism to let
us include traces. As a note, the error type I had above is exactly the
``result`` type from the OCaml standard library. The traces are just
lists of error messages. If you have a call you think might fail, and
you want to provide a series of errors, you can wrap that result in the
``trace`` function. If that call fails, an additional error is added.
.. code:: ocaml
module Error : sig
type 'a t
val return : 'a -> 'a t
val error : string -> 'a t
val (>>?) : 'a t -> ('a -> 'b t) -> 'b t (* bind *)
val print_value : ('a -> string) -> 'a t -> unit
val trace : string -> 'a t -> 'a t
end = struct
type 'a t = ('a, string list) result
let return x = Ok x
let error s = Error [ s ]
let (>>?) value func =
match value with
| Ok x -> func x
| Error errs -> Error errs
let print_value func = function
| Ok x -> Printf.printf "Success: %s\n" (func x)
| Error [ s ] -> Printf.printf "Error: %s\n" s
| Error errors -> Printf.printf "Errors:\t%s\n" (String.concat "\n\t" errors)
let trace error = function
| Ok x -> Ok x
| Error errors -> Error (error :: errors)
end
A more descriptive message
--------------------------
Even though traces are nice, we really want to be able to store more
interesting data in the messages. Were going to use an extensible
variant type to do this. Extensible variants allow us to add a new case
to a variant type at the cost of exhaustivity checking. Were going to
need two new mechanisms to make this work well. The first is an error
registration scheme. In the actual error monad, this involves the data
encoding module, which is how all data is encoded/decoded in Tezos. This
module is another decently complicated part of the codebase that should
probably the subject of a future post. Since you can declare arbitrary
new errors, well have a way of adding a printer for each error.
When we add a new error handler, well use the ``register_handler``
function. This function will take a function that takes an error and
returns a ``string option``. These functions will look something like
this:
.. code:: ocaml
type error += Explosion_failure of string * int;;
register_error
(function
| Explosion_failure (s, i) ->
Some (Printf.sprintf "Everything exploded: %s at %d" s i)
| _ -> None)
Im also renaming the ``error`` function to ``fail``. This is the
convention used by the actual Errormonad module. Im also exposing the
``'a t`` type so that you can dispatch on it if you need to. This is
used several times in the Tezos codebase.
.. code:: ocaml
module Error : sig
type error = ..
type 'a t = ('a, error list) result
val return : 'a -> 'a t
val fail : error -> 'a t
val (>>?) : ('a -> 'b t) -> 'a t -> 'b t (* bind *)
val print_value : ('a -> string) -> 'a t -> unit
val trace : error -> 'a t -> 'a t
end = struct
type error = ..
type 'a t = ('a, error list) result
let fail error = Error [ error ]
let return x = Ok x
let (>>?) func = function
| Ok x -> func x
| Error errs -> Error errs
let registered = ref []
let register_error handler =
registered := (handler :: !registered)
let default_handler error =
"Unregistered error: " ^ Obj.(extension_name @@ extension_constructor error)
let to_string error =
let rec find_handler = function
| [] -> default_handler error
| handler :: handlers ->
begin match handler error with
| None -> find_handler handlers
| Some s -> s
end
in find_handler !registered
let print_value func = function
| Ok x -> Printf.printf "Success: %s\n" (func x)
| Error [ s ] -> Printf.printf "Error: %s\n" (to_string s)
| Error errors -> Printf.printf "Errors:\t%s\n" (String.concat "\n\t" (List.map to_string errors))
let trace error = function
| Ok x -> Ok x
| Error errors -> Error (error :: errors)
end
Putting ``Lwt.t`` in the mix
----------------------------
Tezos uses the `Lwt library <http://ocsigen.org/lwt/>`__ for threading.
The Lwt monad is mixed in with the error monad module. This requires us
to add some extra combinators and reexport some functions from Lwt.
Im also renaming the type ``t`` to ``tzresult``, as used in the Tezos
codebase.
.. code:: ocaml
module Error : sig
type error = ..
type 'a tzresult = ('a, error list) result
val ok : 'a -> 'a tzresult
val return : 'a -> 'a tzresult Lwt.t
val error : error -> 'a tzresult
val fail : error -> 'a tzresult Lwt.t
val (>>?) : 'a tzresult -> ('a -> 'b tzresult) -> 'b tzresult (* bind *)
val (>>=?) : 'a tzresult Lwt.t -> ('a -> 'b tzresult Lwt.t) -> 'b tzresult Lwt.t
val (>>=) : 'a Lwt.t -> ('a -> 'b Lwt.t) -> 'b Lwt.t
val print_value : ('a -> string) -> 'a tzresult Lwt.t -> unit Lwt.t
val trace : error -> 'a tzresult Lwt.t -> 'a tzresult Lwt.t
end = struct
type error = ..
type 'a tzresult = ('a, error list) result
let fail error = Lwt.return (Error [ error ])
let error error = (Error [ error ])
let ok x = Ok x
let return x = Lwt.return (ok x)
let (>>?) value func =
match value with
| Ok x -> func x
| Error errs -> Error errs
let (>>=) = Lwt.bind
let (>>=?) value func =
value >>= function
| Ok x -> func x
| Error errs -> Lwt.return (Error errs)
let registered = ref []
let register_error handler =
registered := (handler :: !registered)
let default_handler error =
"Unregistered error: " ^ Obj.(extension_name @@ extension_constructor error)
let to_string error =
let rec find_handler = function
| [] -> default_handler error
| handler :: handlers ->
begin match handler error with
| None -> find_handler handlers
| Some s -> s
end
in find_handler !registered
let print_value func value =
value >>= fun value ->
begin match value with
| Ok x -> Printf.printf "Success: %s\n" (func x)
| Error [ s ] -> Printf.printf "Error: %s\n" (to_string s)
| Error errors -> Printf.printf "Errors:\t%s\n" (String.concat "\n\t" (List.map to_string errors))
end; Lwt.return ()
let trace error value =
value >>= function
| Ok x -> return x
| Error errors -> Lwt.return (Error (error :: errors))
end
The actual Tezos error monad
----------------------------
The actual Tezos error monad adds a few things. Firstly, there are three
categories of errors:
- :literal:`\`Temporary` - An error resulting from an operation that
might be valid in the future, for example, a contracts balance being
too low to execute the intended operation. This can be fixed by
adding more to the contracts balance.
- :literal:`\`Branch` - An error that occurs in one branch of the
chain, but may not occur in a different one. For example, receiving
an operation for an old or future protocol version.
- :literal:`\`Permanent` - An error that is not recoverable because the
operation is never going to be valid. For example, an invalid ꜩ
notation.
The registration scheme also uses data encodings. Heres an example from
the `validator <../api/odoc/tezos-node-shell/Tezos_node_shell/Validator/index.html>`__:
.. code:: ocaml
register_error_kind
`Permanent
~id:"validator.wrong_level"
~title:"Wrong level"
~description:"The block level is not the expected one"
~pp:(fun ppf (e, g) ->
Format.fprintf ppf
"The declared level %ld is not %ld" g e)
Data_encoding.(obj2
(req "expected" int32)
(req "provided" int32))
(function Wrong_level (e, g) -> Some (e, g) | _ -> None)
(fun (e, g) -> Wrong_level (e, g))
An error takes a category, id, title, description, and encoding. You
must specify a function to take an error to an optional value of the
encoding type and a function to take a value of the encoded type and
create an error value. A pretty printer can optionally be specified, but
may also be omitted.
The actual error monad and its tracing features can be seen in this
function which parses contracts:
.. code:: ocaml
let parse_script
: ?type_logger: (int * (Script.expr list * Script.expr list) -> unit) ->
context -> Script.storage -> Script.code -> ex_script tzresult Lwt.t
= fun ?type_logger ctxt
{ storage; storage_type = init_storage_type }
{ code; arg_type; ret_type; storage_type } ->
trace
(Ill_formed_type (Some "parameter", arg_type))
(Lwt.return (parse_ty arg_type)) >>=? fun (Ex_ty arg_type) ->
trace
(Ill_formed_type (Some "return", ret_type))
(Lwt.return (parse_ty ret_type)) >>=? fun (Ex_ty ret_type) ->
trace
(Ill_formed_type (Some "initial storage", init_storage_type))
(Lwt.return (parse_ty init_storage_type)) >>=? fun (Ex_ty init_storage_type) ->
trace
(Ill_formed_type (Some "storage", storage_type))
(Lwt.return (parse_ty storage_type)) >>=? fun (Ex_ty storage_type) ->
let arg_type_full = Pair_t (arg_type, storage_type) in
let ret_type_full = Pair_t (ret_type, storage_type) in
Lwt.return (ty_eq init_storage_type storage_type) >>=? fun (Eq _) ->
trace
(Ill_typed_data (None, storage, storage_type))
(parse_data ?type_logger ctxt storage_type storage) >>=? fun storage ->
trace
(Ill_typed_contract (code, arg_type, ret_type, storage_type, []))
(parse_returning (Toplevel { storage_type }) ctxt ?type_logger arg_type_full ret_type_full code)
>>=? fun code ->
return (Ex_script { code; arg_type; ret_type; storage; storage_type })
Each specific type error from the typechecking process is wrapped in a
more general error that explains which part of the program was
malformed. This improves the error reporting. You can also see the bind
operator used between functions to continue only if an error does not
occur. This function also operates in the ``Lwt`` monad, which is
largely hidden via the error monad.

View File

@ -0,0 +1,203 @@
Michelson Anti-Patterns
=======================
Even though Michelson is designed to make it easy to write secure
contracts and difficult to write vulnerable ones, it is still possible
to write buggy contracts that leak data and funds. This is a list of
mistakes that you can make when writing or interacting with contracts on
the Tezos blockchain and alternative ways to write code that avoid these
problems.
Note: We are currently reworking the concurrency model of Michelson (how
and when sub-transactions are made), so that some of these patterns will
be prevented by the language itself.
Refunding to a list of contracts
--------------------------------
One common pattern in contracts is to refund a group of peoples funds
at once. This is problematic if you accepted arbitrary contracts as a
malicious user can do cause various issues for you.
Possible issues:
~~~~~~~~~~~~~~~~
- One contract swallows all the gas through a series of callbacks
- One contract writes transactions until the block is full
- Reentrancy bugs. Michelson intentionally makes these difficult to
write, but it is still possible if you try.
- A contract calls the \`FAIL\` instruction, stopping all computation.
Alternatives/Solutions:
~~~~~~~~~~~~~~~~~~~~~~~
- Create a default account from peoples keys. Default accounts cannot
execute code, avoiding the bugs above. Have people submit keys rather
than contracts.
- Have people pull their funds individually. Each user can break their
own withdrawal only. **This does not protect against reentrancy
bugs.**
Avoid batch operations when users can increase the size of the batch
--------------------------------------------------------------------
Contracts that rely on linear or super-linear operations are vulnerable
to malicious users supplying values until the contract cannot finish
without running into fuel limits. This can deadlock your contract.
.. _possible-issues-1:
Possible issues:
~~~~~~~~~~~~~~~~
- Malicious users can force your contract into a pathological worst
case, stopping it from finishing with available gas. Note that in the
absence of hard gas limits, this can still be disabling as node
operators may not want to run contracts that take more than a certain
amount of gas.
- You may hit the slow case of an amortized algorithm or data structure
at an inopportune time, using up all of your contracts available
gas.
.. _alternativessolutions-1:
Alternatives/Solutions:
~~~~~~~~~~~~~~~~~~~~~~~
- Avoid data structures and algorithms that rely on amortized
operations, especially when users may add data.
- Restrict the amount of data your contract can store to a level that
will not overwhelm the available gas.
- Write your contract so that it may pause and resume batch operations.
This would complicate these sequences and require constant checking
of available gas, but it prevents various attacks.
\*Do not assume an attack will be prohibitively expensive\*
Cryptocurrencies have extreme price fluctuations frequently and an
extremely motivated attacker may decide that an enormous expense is
justified. Remember, an attack that disables a contract is not just
targeted at the authors, but also the users of that contract.
Signatures alone do not prevent replay attacks
----------------------------------------------
If your contract uses signatures to authenticate messages, beware of
replay attacks. If a user ever signs a piece of data, you *must* make
sure that that piece of data is never again a valid message to the
contract. If you do not do this, anyone else can call your contract with
the same input and piggyback on the earlier approval.
.. _possible-issues-2:
Possible issues:
~~~~~~~~~~~~~~~~
- A previously approved action can be replayed.
.. _alternativessolutions-2:
Alternatives/Solutions
~~~~~~~~~~~~~~~~~~~~~~
- Use an internal counter to make the data you ask users to sign
unique. This counter should be per key so that users can find out
what they need to approve. This should be paired with a signed hash
of your contract to prevent cross-contract replays.
- Use the ``SOURCE`` instruction to verify that the expected sender is
the source of the message.
Do not assume users will use a unique key for every smart contract
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Users should always use a different key for every contract with which
they interact. If this is not the case, a message the user signed for
another contract can be sent to your contract. An internal counter alone
does not protect against this attack. It *must* be paired with a hash of
your contract. You must verify the source of the message.
Storing/transferring private data
---------------------------------
Once data is published to anyone, including broadcasting a transaction,
that data is public. Never transmit secret information via any part of
the blockchain ecosystem. As soon as you have broadcast a transaction
including that piece of information, anyone can see it. Furthermore,
malicious nodes in the system can manipulate unsigned transactions by
delaying, modifying, or reordering them.
.. _possible-issues-3:
Possible Issues
~~~~~~~~~~~~~~~
- If data is not signed, it can be modified
- Transactions can be delayed
- Secret information will become public
.. _alternativessolutions-3:
Alternatives/Solutions
~~~~~~~~~~~~~~~~~~~~~~
- Do not store private information on the blockchain or broadcast it in
transactions.
- Sign all transactions that contain information that, if manipulated,
could be abused.
- Use counters to enforce transaction orders.
This will at least create a logical clock on messages sent to your
contract.
Not setting all state before a transfer
---------------------------------------
Reentrancy is a potential issue on the blockchain. When a contract makes
a transfer to another contract, that contract can execute its own code,
and can make arbitrary further transfers, including back to the original
contract. If state has not been updated before the transfer is made, a
contract can call back in and execute actions based on old state.
.. _possible-issues-4:
Possible Issues
~~~~~~~~~~~~~~~
- Multiple withdrawals/actions
- Generating illegal state if state is updated twice later
.. _alternativessolutions-4:
Alternatives/Solutions
~~~~~~~~~~~~~~~~~~~~~~
- Forbid reentrancy by means of a flag in your storage, unless you have
a good reason to allow users to reenter your contract, this is likely
the best option.
- Only make transfers to trusted contracts or default accounts. Default
accounts cannot execute code, so it is always safe to transfer to
them. Before trusting a contract, make sure that its behavior cannot
be modified and that you have an extremely high degree of confidence
in it.
Do not store funds for others in spendable contracts
----------------------------------------------------
Tezos allows contracts to be marked as spendable. Managers of spendable
contracts can make transfers using the funds stored inside the contract.
This can subvert guarantees about the contracts behavior that are
visible in the code.
.. _possible-issues-5:
Possible Issues
~~~~~~~~~~~~~~~
- The funds of a contract can be removed.
- A contract may not be able to meet its obligations
.. _alternativessolutions-5:
Alternatives/Solutions
~~~~~~~~~~~~~~~~~~~~~~
- Do not store funds in spendable contracts that you do not control.

View File

@ -0,0 +1,48 @@
.. _protocol_environment:
Economic protocol sandboxing
============================
In Alpha, as in any sound future protocols, updates are approved by
voting. That way, the responsibility of switching to a new protocol code
is the responsibility of voters, and one could argue that it is up to
them to check that the code does not call, for instance, unsafe array
access functions.
Yet, we decided to introduce a minimum level of machine checks, by
compiling with a specific compiler that checks that no known-unsafe
function is used. This static form of sandboxing is performed by the
OCaml typechecker: we simply compile protocols in a restricted set of
modules with restricted interfaces that hide any unsafe, non wanted
feature.
Another goal of that specific environment is maintaining a stable OCaml
API for protocol development. Imagine that at some point, the OCaml
standard library changes (a function is added or removed, a type is
changed), then we will be able to upgrade to the new OCaml while still
remaining compatible with past protocols, by providing an adapter layer.
Here is a quick description of each file in this environment:
- Files ``array.mli``, ``buffer.mli``, ``bytes.mli``, ``format.mli``,
``int32.mli``, ``int64.mli``, ``list.mli``, ``map.mli``,
``pervasives.mli``, ``set.mli`` and ``string.mli`` are stripped down
interfaces to the OCaml standard library modules. The removed
elements are: effects on toplevel references or channels, unsafe
functions, functions that are known sources of bugs, and anything
deprecated.
- As we removed polymorphic comparison operators, ``compare.mli``
implements monomorphic operators for standard OCaml and Tezos types.
An example use is ``Compare.Int.(3 = 4)`` instead of plain OCaml
``(3 = 4)``.
- Files ``lwt*`` is the stripped down interface to Lwt, of which we
removed any non deterministic functions, since we only use Lwt for
asynchronous access to the storage.
- Files ``data_encoding.mli``, ``error_monad.mli``, ``mBytes.mli``,
``hash.mli``, ``base58.mli``, ``blake2B.mli``, ``ed25519.mli``,
``hex_encode.mli``, ``json.mli``, ``time.mli``, ``z.mli``,
``micheline.mli`` and files ``RPC_*`` are stripped down versions of
the Tezos standard library.
- Files ``tezos_data.mli``, ``context.mli``, ``fitness.mli`` and
``updater.mli`` are interfaces to the shells data definitions and
storage accessors that are accessible to the protocol.

2344
docs/whitedoc/michelson.rst Normal file

File diff suppressed because it is too large Load Diff

1558
docs/whitedoc/octopus.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 437 KiB

View File

@ -0,0 +1,59 @@
.. _the_big_picture:
Tezos Software Architecture
===========================
The diagram below shows a very coarse grained architecture of Tezos.
|Tezos architecture diagram|
The characteristic that makes Tezos unique is its self-amending
property. The part that amends itself is called the *economic protocol*
(the green eye of the octopus), sometimes abbreviated by protocol or
even proto in the source code. The rest of a Tezos node is what we call
the *shell* (the blue octopus).
The protocol is responsible for interpreting the transactions and other
administrative operations. It also has the responsibility to detect
erroneous blocks.
An important thing to notice is that the protocol always sees only one
block chain. In other words, a linear sequence of blocks since the
genesis. It does not know that it lives in an open network where nodes
can propose alternative heads.
Only the shell knows about the multiple heads. It is responsible for
choosing between the various chain proposals that come from the bakers
(the programs that cook new blocks) of the network. The shell has the
responsibility of selecting and downloading alternative chains, feed
them to the protocol, which in turn has the responsibility to check them
for errors, and give them an absolute score. The shell then simply
selects the valid head of highest absolute score. This part of the shell
is called the validator.
The rest of the shell includes the peer-to-peer layer, the disk storage
of blocks, the operations to allow the node to transmit the chain data
to new nodes and the versioned state of the ledger. Inbetween the
validator, the peer-to-peer layer and the storage sits a component
called the distributed database, that abstracts the fetching and
replication of new chain data to the validator.
Protocols are compiled using a tweaked OCaml compiler (green part on the
left of the picture) that does two things. First, it checks that the
protocols main module has the right type. A good analogy is to see
protocol as plug-ins, and in this case, it means that it respects the
common plugin interface. Then, it restricts the typing environment of
the protocols code so that it only calls authorized modules and
functions. Seeing protocols as plug-ins, it means that the code only
called primitives from the plug-in API. It is a form of statically
enforced sandboxing.
Finally, the RPC layer (in yellow on the right in the picture) is an
important part of the node. It is how the client, third party
applications and daemons can interact with the node and introspect its
state. This component uses the mainstream JSON format and HTTP protocol.
It uses in-house libraries ``ocplib-resto`` and ``ocplib-json-typed``
(via the module :ref:`Data_encoding <data_encoding>`). It
is fully inter-operable, and auto descriptive, using JSON schema.
.. |Tezos architecture diagram| image:: octopus.svg

85
scripts/ocamldot.py Executable file
View File

@ -0,0 +1,85 @@
#!/usr/bin/python
import re
import sys
import os
import argparse
from sets import Set
alldeps={}
allmodules={}
def sanitize(s):
s=re.sub('.*/','',s)
s=re.sub('[^0-9a-zA-Z]+', '_', s)
return s
def cleanName(s):
ml = os.path.basename(s)
(mod,_) = os.path.splitext(ml)
return mod.capitalize()
def mangle(f,modulename):
dictionary = {}
for line in open(f):
s=line.split();
for x in range(2, len(s)):
mod = cleanName(s[0])
dep = sanitize(s[x])
if mod in dictionary :
dictionary[mod].append(dep)
else :
dictionary[mod] = [dep]
allmodules.update({mod : modulename})
alldeps[modulename] = dictionary
def cleanup(alldeps):
# remove references to external libraries
for (name,dictionary) in alldeps.iteritems() :
for (mod,deps) in dictionary.iteritems() :
dictionary[mod] = [x for x in deps if x in allmodules]
alldeps[name] = dictionary
return alldeps
def print_graph(alldeps):
print("strict digraph G {")
print('graph [fontsize=10 fontname="Verdana"];')
print('node [shape=record fontsize=10 fontname="Verdana" compound=true];')
counter = 0
l = { x: i for i,x in enumerate(alldeps.keys())}
for (name,dictionary) in alldeps.iteritems() :
names = ['"%s"' % mod for mod in dictionary.keys()]
if len(names) > 0 :
print ('subgraph cluster_%i { label = "%s"; color=blue; node [style=filled];' % (l[name],name))
counter += 1
for (mod,deps) in dictionary.iteritems() :
for dep in deps :
if dep in dictionary :
print ('"%s" -> "%s";' % (mod,dep))
print "}"
# for (mod,deps) in dictionary.iteritems() :
# for dep in deps :
# if dep not in dictionary :
# print ('"%s" -> "%s" [ltail=cluster_%i lhead=cluster_%i];' % (mod,dep,l[name],l[allmodules[dep]]))
print "}"
def scan(directories):
ext = ".depends.ocamldep-output"
for directory in directories:
for root, dirs, files in os.walk(directory):
for f in files:
if f.endswith(ext):
mangle(os.path.join(root, f),f[:-len(ext)])
print_graph(cleanup(alldeps))
def main():
parser = argparse.ArgumentParser(description='OcamlDep Dependency Tree')
parser.add_argument('inputdirs', type=str, nargs='*', help="directories to scan")
args = parser.parse_args()
scan(args.inputdirs)
if __name__ == '__main__':
main()

View File

@ -95,7 +95,7 @@ val complete: ?alphabet:Alphabet.t -> string -> string list Lwt.t
(** {1 Low-level: distinct registering function for economic protocol} *)
(** See [src/environment/v1/base58.mli]} for an inlined
(** See [src/environment/v1/base58.mli] for an inlined
documentation. *)
module Make(C: sig type context end) : sig

View File

@ -25,7 +25,7 @@ val shift: t -> int -> t
val blit: t -> int -> t -> int -> int -> unit
(** [blit src ofs_src dst ofs_dst len] copy [len] bytes from [src]
starting at [ofs_src] into [dst] starting at [ofs_dst].] *)
starting at [ofs_src] into [dst] starting at [ofs_dst]. *)
val blit_from_string: string -> int -> t -> int -> int -> unit
(** See [blit] *)

View File

@ -34,7 +34,7 @@ val shift: t -> int -> t
val blit: t -> int -> t -> int -> int -> unit
(** [blit src ofs_src dst ofs_dst len] copy [len] bytes from [src]
starting at [ofs_src] into [dst] starting at [ofs_dst].] *)
starting at [ofs_src] into [dst] starting at [ofs_dst]. *)
val blit_from_string: string -> int -> t -> int -> int -> unit
(** See [blit] *)

View File

@ -33,7 +33,7 @@ val arg : doc:string -> parameter:string ->
('p option, 'ctx) arg
(** Create an argument that will contain the [~default] value if it is not provided.
@see arg *)
see arg *)
val default_arg : doc:string -> parameter:string ->
default:string ->
('p, 'ctx) parameter ->