3

How can we generate the protocol hash from a folder without a node? I know we can do the following:

tezos-protocol-compiler -hash-only path/to/dir/

But I want to know how I can compute this manually (so we can develop tools to do this). I assume we take a hash of the contents of the folder (or maybe tar the folder first) and then base58c encode it. If anyone has more details on this, please shed some light!

4

To compute the hash:

  1. Read the TEZOS_PROTOCOL JSON file, e.g. src/proto_003_PsddFKi3/lib_protocol/src/TEZOS_PROTOCOL. It's JSON like this:
{
    "hash": "PsddFKi32cMJ2qPjf43Qv5GDWLDPZb3T3bF6fLKiF5HtvHNU7aP",
    "modules": [
        "Misc",
        "Storage_description",
...
  1. For each module name, convert it to lowercase and append ".ml" and ".mli" to find possible filenames. Read all those files. The .ml will always exist, the .mli may not.
  2. Encode (in the given order) the names of the modules and the contents of the corresponding files using the protocol encoding.
  3. BLAKE2B it (size 32), base58-encode it (prefix bytes [2, 170]).

Note that you can get example binary encoded protocols for known protocols from the node:

curl -HAccept:application/octet-stream \
http://localhost:8732/protocols/PsddFKi32cMJ2qPjf43Qv5GDWLDPZb3T3bF6fLKiF5HtvHNU7aP \
> 003.bin

Below is a description of the protocol encoding, which I obtained from the RPC docs. The expected_env_version is V1 for now, which is encoded as two zero bytes.

 +-----------------------+----------+-------------------------+
  | Name                  | Size     | Contents                |
  +=======================+==========+=========================+
  | expected_env_version  | 2 bytes  | signed 16-bit integer   |
  +-----------------------+----------+-------------------------+
  | # bytes in next field | 4 bytes  | unsigned 30-bit integer |
  +-----------------------+----------+-------------------------+
  | components            | Variable | sequence of $component  |
  +-----------------------+----------+-------------------------+


  interface
  *********

  +-----------------------+----------+-------------------------+
  | Name                  | Size     | Contents                |
  +=======================+==========+=========================+
  | # bytes in next field | 4 bytes  | unsigned 30-bit integer |
  +-----------------------+----------+-------------------------+
  | Unnamed field 0       | Variable | bytes                   |
  +-----------------------+----------+-------------------------+


  component
  *********

  +---------------------------------+----------------------+-------------------------------------+
  | Name                            | Size                 | Contents                            |
  +=================================+======================+=====================================+
  | # bytes in next field           | 4 bytes              | unsigned 30-bit integer             |
  +---------------------------------+----------------------+-------------------------------------+
  | name                            | Variable             | bytes                               |
  +---------------------------------+----------------------+-------------------------------------+
  | ? presence of field "interface" | 1 byte               | boolean (0 for false, 255 for true) |
  +---------------------------------+----------------------+-------------------------------------+
  | interface                       | Determined from data | $interface                          |
  +---------------------------------+----------------------+-------------------------------------+
  | # bytes in next field           | 4 bytes              | unsigned 30-bit integer             |
  +---------------------------------+----------------------+-------------------------------------+
  | implementation                  | Variable             | bytes                               |
  +---------------------------------+----------------------+-------------------------------------+
3
  • Thanks Tom, you're the man! Might have to spend a decent amount of type trying to figure out the encoding, but you've given me more than enough to make a start and work it out. Thanks! Mar 5 '19 at 11:36
  • Thanks a lot! I wonder why files can't just be sorted in lexical order before packing, so that TEZOS_PROTOCOL file is not needed. Or there is some hidden sense?) Mar 6 '19 at 16:12
  • 1
    Here's an experiment: take the "Main" component at the end and move it to the front. The tezos-protocol-compiler will report that the hash is incorrect, so update the hash. Now, we get a different error: File "./main.ml", line 28, characters 25-65: Error: Unbound module Alpha_context. According to the docs, the module list "follows the linking order", and I think this is significant.
    – Tom
    Mar 6 '19 at 20:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.