How to submit a Tezos Protocol Proposal
Any Tezos baker can submit a proposal. As per the rules of Tezos on-chain governance, any proposal approved by a 80% supermajority of the bakers will become the chain’s next protocol.
However, there is a convention in Tezos where proposals have been named after cities, in alphabetical order.
Every proposal is identified by its hash. Since the Babylon proposal in 2019, every proposal hash has been a vanity hash, where the first few letters of the hash match the city name of the protocol.
This guide explains how to make a simple change to an existing proposal and create such a vanity hash. It assumes some familiarity with the command line interface, git, the pull request workflow, source code editing, and building software from source.
Write your Proposal
A simple protocol change consists of minting new Tez and allocating them to an address: this is typically done to reward an ecosystem participant for a positive contribution, in software or otherwise.
Below we explain how to perform such a change.
There are other easy-ish protocol changes you can submit to governance. See for example How to Change the Liquidity Baking Asset Pair by Sophia Gold.
All Tezos proposals that ever were on Tezos mainnet are stored in the Octez repository, specifically in the src/proto_*/lib_protocol
folders. See for example the Lima protocol.
Below we will assume that the protocol is already snapshotted. “Snapshotting” a protocol is the process where a Tezos protocol moves from the main development folder (src/proto_alpha
) to go to its own folder (src/proto_016_PtMumbai
) for safekeeping. The snapshotting process itself is out of scope for this guide.
Specifically, we will modify the Mumbai protocol, located in src/proto_016_PtMumbai
.
Clone the repository:
git clone https://gitlab.com/tezos/tezos.git
cd tezos
Inside the protocol folder src/proto_016_PtMumbai/lib_protocol
, the init_storage.ml
file contains a helper function called invoice_contract
that you must uncomment. In OCaml, comments start with (*
and end with *)
.
Delete these 2 lines before the function:
(*
To add invoices, you can use a helper function like this one:
and the one line after the invoice_contract
function:
*)
Now that the invoice_contract
function is uncommented, you may call it in the prepare_first_block
function.
This function acts differently based on the previous_protocol
. For example, on mainnet, the Mumbai protocol comes after Lima, therefore you must target the case statement that deals with upgrades from Lima.
Instead of just returning the context with return (ctxt, []))
, our function must invoke the just uncommentedinvoice_contract
function, passing as parameters the amount in mutez (one millionth of a tez) and the public key hash (starting with tz
) of the address to credit.
Add the following at the end of the case statement. This example mints and credits 100,000 tez to the address tz3RDC3…VB1CxD9:
invoice_contract
ctxt
~address:"tz3RDC3Jdn4j15J7bBHZd29EUee9gVB1CxD9"
~amount_mutez:100_000_000_000L
>>= fun (ctxt, balance_updates) -> return (ctxt, balance_updates))
For more examples, you can browse the commits associated with the invoices included in past proposals:
- Kathmandu: 3,000 tez to one address
- Lima: 25,000 tez to two addresses.
Compile
After changing the protocol code, check that it still compiles by building from source.
See the OpenTezos guide on how to build Octez from source for more details.
After a succesful compilation, you should see binaries such as octez-node
and octez-protocol-compiler
in your working directory.
Did it compile without error? Good. Otherwise, make sure that it works with the master branch, and understand which of your modifications caused the breakage. Don’t hesitate to reach out to the community for help.
Create a Vanity Hash
Creating a vanity hash consists of editing a commented random string inside the protocol proposal and hashing it over and over, until the resulting hash starts with the string that you expect.
We present 2 methods: local and cloud. The cloud method will find hashes faster but is more complex to setup.
Download your protocol binary
Your modifications will change the protocol hash. Calculate the new hash with the octez-protocol-compiler
command:
$ ./octez-protocol-compiler -hash-only src/proto_016_*/lib_protocol
Psm5KsjAm73vQsdMpBfkTm9YmBjx3DHznR3HHhbnpLkpjCkf2WX
To find a better hash, let’s first download your protocol in binary format.
In the file src/proto_016_PtMumbai/lib_protocol/TEZOS_PROTOCOL
, replace the original protocol with the new hash you just calculated. Compile again with make
. Then run Octez in private mode:
./octez-node run --synchronisation-threshold 0 --connections 0 --rpc-addr localhost
Download your new protocol with the curl
command and store it in the mumbai_v
file:
curl -H "Accept: application/octet-stream" http://localhost:8732/protocols/Psm5KsjAm73vQsdMpBfkTm9YmBjx3DHznR3HHhbnpLkpjCkf2WX > mumbai_v
Calculate the hash locally
This method will calculate the hash on your computer.
You will find a 4-character hash such as PtMumb
in a minute. However, be advised that 6-character hashes such as PtMumbai
will take several hours on a single computer. For faster searches, please use the cloud method below.
Download and unpack the tz-proto-vanity binary.
Then run:
./tz-proto-vanity mumbai_v PtMumb
After some time you will see results:
$ ./tz-proto-vanity mumbai_v PtMumb
Looking for vanity hash PtMumb for mumbai_v using 8 threads and vanity set {"PtMumb"}
Current hash: Psm5KsjAm73vQsdMpBfkTm9YmBjx3DHznR3HHhbnpLkpjCkf2WX
┌────────────────────────────────────────────
2│ (* Vanity nonce: 7631808252943472 *)
│ └> PtMumbFt3sHAYrrnmoR7CMvCTbynQ6oFm7R6zcNCnLUWouAQhx9
│ found in: 9s (393982 attempts)
│ found so far: 1 (6.67/minute)
│ elapsed: 9s/9s
│ total found: 1 (6.67/minute)
└────────────────────────────────────────────
The vanity nonce is 7631808252943472. See the section “Submit your proposal” below for instructions how to put it in your code and submit.
Calculate the hash in a Kubernetes cluster
For faster results, it is possible to leverage the cloud.
It works like this:
- create a file bucket (Amazon S3 or equivalent) with your protocol in it
- launch a Kubernetes cluster with several powerful machines
- install the
tezos-proto-cruncher
helm chart - wait
- when the cluster finds results, it saves them in the same bucket.
You will need:
- a file bucket (S3 or compatible) to store your hashes,
- a Kubernetes cluster with as many machines as you like.
We use DigitalOcean as an example.
Create a bucket named tezos-proto-cruncher
. For our example, we follow this DigitalOcean Spaces guide.
Then transfer the proto binary file to the bucket using the DigitalOcean Spaces web interface, or an utility such as s3cmd
:
$ s3cmd put mumbai_v s3://tezos-proto-cruncher
Prepare a values file
Create a file called mumbai_v.yaml
with the following content:
s3AccessKeyId: DO00Y...
s3SecretAccessKey: '/5CFZV...'
bucketEndpointUrl: 'ams3.digitaloceanspaces.com'
bucketRegion: 'ams'
bucketName: "tezos-proto-cruncher"
protoName: "mumbai_v"
vanityString: "PtMumbai"
Where:
s3*
: the S3-compatible credentialsbucketEndpointUrl
: the endpoint of your S3-compatible service (for DigitalOcean, see this tutorial)bucketRegion
: the region of the bucket (for exampleams
)bucketName
: name of your bucket (so the s3 url iss3://<name>
)protoName
: the name of the file containing your protovanityString
: the string you want your proto to start with
Create a cluster
Go to your cloud platform of choice and create a k8s cluster.
The proto-cruncher is configured as a kubernetes daemon set which means it runs on every virtual machine of your cluster.
So, you can pick the appropriate number of machines based on how fast you need the hashes.
In our example, we use a DigitalOcean k8s cluster. See quick start.
Install the chart
You need the kubectl and helm utilities. For more details, see tezos-k8s prerequisites.
helm repo add oxheadalpha https://oxheadalpha.github.io/tezos-helm-charts/
helm install -f /path/to/mumbai_v.yaml cruncher oxheadalpha/tezos-proto-cruncher --namespace cruncher --create-namespace
That’s it! All vCPUS of all the nodes of your cluster are now searching for a vanity hash.
Go to bed, the next morning you should see a few results in your bucket. If not, get bigger VMs.
The results consist of files named after the protocol hash. The content of the file is the vanity nonce. For example: (* Vanity nonce: 3300821025205842 *)
.
Submit your Proposal
Copy and paste the nonce into the source code main.ml
file, replacing the original vanity hash. Make sure to not introduce any new space or newline.
Then check that the octez-protocol-compiler
command gives you the expected hash:
$ ./octez-protocol-compiler -hash-only src/proto_016_*/lib_protocol
PtMumbaiveNjgvoAng9E3AtNqtBtCQWqpXJdPEdAanAYCZbCgey
Compile your protocol again.
It is always recommended to test your protocol thoroughly before injection. The Octez documentation explains how to. When unsure, do not hesitate to ask for help.
You are now ready to inject your proposal. To do so, you need access to your baker key and a public node.
Submit the command:
octez-client submit proposals for <YOUR_BAKER_ADDRESS> PtMumbaiveNjgvoAng9E3AtNqtBtCQWqpXJdPEdAanAYCZbCgey
Your proposal is now injected. Commit your changes and push them to a public repo, where other bakers and developers can examine them.
Wrap up
Uninstall your chart with the command:
helm uninstall cruncher --namespace cruncher
Then delete your cluster, if applicable.