DEV Community

Cover image for How to run your own Beacon Chain
Afri
Afri

Posted on • Updated on

How to run your own Beacon Chain

This article is for educational purposes only. A beacon chain is a future Ethereum 2.0 relay connecting shard chains. There's literally no value in running a beacon chain currently as there are no shards yet and there's no other functionality on the beacon chain available. But it's new technology, and who's not excited about playing around with it?


To bootstrap a new, custom beacon chain, we would need to cover the following topics:

  1. The deposit contract ceremony
  2. The beacon chain transition specification
  3. The genesis event
  4. Bootstrapping the actual network

Before we start, we need to understand that the beacon chain, which we will also call eth2 chain for now, cannot live without a legacy Ethereum chain which we will call eth1 chain. There will be a transition from eth1 to eth2 defined by an interface, the so called deposit contract.

The deposit contract ceremony

The deposit contract is a tool that allows gathering Ether deposits on the eth1 chain to enable validators proposing blocks on the eth2 chain later. How this will work in detail, will be covered later. For now, we need to understand that we need the deposit contract before doing anything else.

An example of the deposit contract is available as validator_registration.vy in the eth2.0-specs repository written in the Vyper contract language. The main function of interest of that fairly simple contract is -- surprise -- deposit(). But we'll cover that later.

We need three things now:

  1. The compiled bytecode of the contract
  2. The ABI of the contract
  3. And an eth1 testnet to deploy it to

To compile the contract, we need to install Vyper locally or use an Vyper Online Compiler. The online-compiler comes in pretty handy in some cases, but for such an important piece of infrastructure, we'll use the native compiler locally. It's simple as that:

❯ vyper validator_registration.vy
0x740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009857600080fd5b6101406000601f818352015b600061014051602081106100b757600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e357600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012157600080fd5b60c05190506101405160016060518183018060405190131561014257600080fd5b809190121561015057600080fd5b905090506020811061016157600080fd5b600260c052602060c02001555b81516001018083528114156100a4575b50506110a256600436101561000d57610f17565b600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05260001561020e575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600881811b90509050610180526101805160ff6101a051168181830110156100f657600080fd5b80820190509050610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff88160081c905090506101a0525b81516001018083528114156100cb575b505060186008602082066101e0016020828401111561016157600080fd5b60208061020082610180600060045af15050818152809050905090508051602001806102a08284600060045af161019757600080fd5b50506102a051806102c001818260206001820306601f820103905003368237505060206102805260406102a0510160206001820306601f8201039050610260525b6000610260511115156101ea57610206565b60206102605103610280015160206102605103610260526101d8565b610160515650005b63c5f2892f60005114156104a257341561022757600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156102c95760006101a0516020811061026a57600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af16102bb57600080fd5b60c051905061016052610337565b6000610160516020826101c00101526020810190506101a051602081106102ef57600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161032d57600080fd5b60c0519050610160525b61018080516002808061034957600080fd5b8204905090508152505b8151600101808352811415610248575b505060006101605160208261046001015260208101905061014051610160516101805163806732896102e0526001546103005261030051600658016100a9565b506103605260006103c0525b6103605160206001820306601f82010390506103c0511015156103d1576103ea565b6103c05161038001526103c0516020016103c0526103af565b61018052610160526101405261036060088060208461046001018260208501600060045af150508051820191505060006018602082066103e0016020828401111561043457600080fd5b60208061040082610140600060045af150508181528090509050905060188060208461046001018260208501600060045af150508051820191505080610460526104609050602060c0825160208401600060025af161049257600080fd5b60c051905060005260206000f350005b63621fd130600051141561057f5734156104bb57600080fd5b6380673289610140526001546101605261016051600658016100a9565b506101c0526000610220525b6101c05160206001820306601f8201039050610220511015156105065761051f565b610220516101e0015261022051602001610220526104e4565b6101c08051602001806102808284600060045af161053c57600080fd5b505061028051806102a001818260206001820306601f82010390500336823750506020610260526040610280510160206001820306601f8201039050610260f350005b63228951186000511415610f165760506004356004016101403760306004356004013511156105ad57600080fd5b60406024356004016101c03760206024356004013511156105cd57600080fd5b60806044356004016102203760606044356004013511156105ed57600080fd5b63ffffffff600154106105ff57600080fd5b34633b9aca00808061061057600080fd5b8204905090506102c052633b9aca006102c051101561062e57600080fd5b6030610140511461063e57600080fd5b60206101c0511461064e57600080fd5b6060610220511461065e57600080fd5b610140610340525b6103405151602061034051016103405261034061034051101561068857610666565b6380673289610360526102c0516103805261038051600658016100a9565b506103e0526000610440525b6103e05160206001820306601f8201039050610440511015156106d4576106ed565b61044051610400015261044051602001610440526106b2565b610320610340525b6103405152602061034051036103405261014061034051101515610718576106f5565b6103e08051602001806102e08284600060045af161073557600080fd5b5050610140610460525b610460515160206104605101610460526104606104605110156107615761073f565b6380673289610480526001546104a0526104a051600658016100a9565b50610500526000610560525b6105005160206001820306601f8201039050610560511015156107ac576107c5565b610560516105200152610560516020016105605261078a565b610440610460525b61046051526020610460510361046052610140610460511015156107f0576107cd565b6105008051602001806105808284600060045af161080d57600080fd5b505060a06105e0526105e051610620526101408051602001806105e051610620018284600060045af161083f57600080fd5b50506105e05161062001518060206105e051610620010101818260206001820306601f820103905003368237505060206105e051610620015160206001820306601f82010390506105e05101016105e0526105e051610640526101c08051602001806105e051610620018284600060045af16108ba57600080fd5b50506105e05161062001518060206105e051610620010101818260206001820306601f820103905003368237505060206105e051610620015160206001820306601f82010390506105e05101016105e0526105e051610660526102e08051602001806105e051610620018284600060045af161093557600080fd5b50506105e05161062001518060206105e051610620010101818260206001820306601f820103905003368237505060206105e051610620015160206001820306601f82010390506105e05101016105e0526105e051610680526102208051602001806105e051610620018284600060045af16109b057600080fd5b50506105e05161062001518060206105e051610620010101818260206001820306601f820103905003368237505060206105e051610620015160206001820306601f82010390506105e05101016105e0526105e0516106a0526105808051602001806105e051610620018284600060045af1610a2b57600080fd5b50506105e05161062001518060206105e051610620010101818260206001820306601f820103905003368237505060206105e051610620015160206001820306601f82010390506105e05101016105e0527f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c56105e051610620a160006106c052600061014060308060208461078001018260208501600060045af150508051820191505060006010602082066107000160208284011115610aeb57600080fd5b602080610720826106c0600060045af150508181528090509050905060108060208461078001018260208501600060045af150508051820191505080610780526107809050602060c0825160208401600060025af1610b4957600080fd5b60c05190506106e0526000600060406020820661082001610220518284011115610b7257600080fd5b6060806108408260206020880688030161022001600060045af1505081815280905090509050602060c0825160208401600060025af1610bb157600080fd5b60c0519050602082610a20010152602081019050600060406020602082066108e001610220518284011115610be557600080fd5b6060806109008260206020880688030161022001600060045af15050818152809050905090506020806020846109a001018260208501600060045af15050805182019150506106c0516020826109a0010152602081019050806109a0526109a09050602060c0825160208401600060025af1610c6057600080fd5b60c0519050602082610a2001015260208101905080610a2052610a209050602060c0825160208401600060025af1610c9757600080fd5b60c051905061080052600060006106e051602082610ac00101526020810190506101c0602080602084610ac001018260208501600060045af150508051820191505080610ac052610ac09050602060c0825160208401600060025af1610cfc57600080fd5b60c0519050602082610c4001015260208101905060006102e0600880602084610bc001018260208501600060045af15050805182019150506000601860208206610b400160208284011115610d5057600080fd5b602080610b60826106c0600060045af1505081815280905090509050601880602084610bc001018260208501600060045af150508051820191505061080051602082610bc001015260208101905080610bc052610bc09050602060c0825160208401600060025af1610dc157600080fd5b60c0519050602082610c4001015260208101905080610c4052610c409050602060c0825160208401600060025af1610df857600080fd5b60c0519050610aa052606435610aa05114610e1257600080fd5b600180546001818183011015610e2757600080fd5b80820190509050815550600154610cc052610ce060006020818352015b60016001610cc051161415610e7957610aa051610ce05160208110610e6857600080fd5b600060c052602060c0200155610f12565b6000610ce05160208110610e8c57600080fd5b600060c052602060c0200154602082610d00010152602081019050610aa051602082610d0001015260208101905080610d0052610d009050602060c0825160208401600060025af1610edd57600080fd5b60c0519050610aa052610cc0805160028080610ef857600080fd5b8204905090508152505b8151600101808352811415610e44575b5050005b5b60006000fd5b6101856110a2036101856000396101856110a2036000f3
Enter fullscreen mode Exit fullscreen mode

This is our compiled bytecode which can be deployed later. Now we need the ABI:

❯ vyper -f abi validator_registration.vy
[{"name": "DepositEvent", "inputs": [{"type": "bytes", "name": "pubkey", "indexed": false}, {"type": "bytes", "name": "withdrawal_credentials", "indexed": false}, {"type": "bytes", "name": "amount", "indexed": false}, {"type": "bytes", "name": "signature", "indexed": false}, {"type": "bytes", "name": "index", "indexed": false}], "anonymous": false, "type": "event"}, {"outputs": [], "inputs": [], "constant": false, "payable": false, "type": "constructor"}, {"name": "get_deposit_root", "outputs": [{"type": "bytes32", "name": ""}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 112305}, {"name": "get_deposit_count", "outputs": [{"type": "bytes", "name": ""}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 14558}, {"name": "deposit", "outputs": [], "inputs": [{"type": "bytes", "name": "pubkey"}, {"type": "bytes", "name": "withdrawal_credentials"}, {"type": "bytes", "name": "signature"}, {"type": "bytes32", "name": "deposit_data_root"}], "constant": false, "payable": true, "type": "function", "gas": 1331065}]
Enter fullscreen mode Exit fullscreen mode

The ABI will allow us later to interact with the deposit contract once it is deployed. As testnet, we will use the Görli Testnet. We will go on straight deploying the bytecode from above and have a contract address: 0xaA888248144Bc5d584a7f400839d0D912F21C39A.

That's it, for a testnet at least. For a mainnet, this process will involve an actual ceremony to determine social consensus on the contract code and the official instance to use.

For the sake of easing eth2 clients with eth1 synchronization, we also note down two values:

  • The deposit contract deploy block: 2355031
  • The deposit contract deploy date: 1584316800 (March/16, 2020)

The beacon chain transition specification

Now that we have an instance of the deposit contract deployed to a public eth1 network, we'll start configuring our eth2 network transitions. For that, we can template our future network on the existing specification for the official Ethereum 2.0 mainnet, namely mainnet.yaml.

We'll take that specification and modify it slightly to ease running a testnet with just a couple of validators:

  • DEPOSIT_CONTRACT_ADDRESS: 0xaA888248144Bc5d584a7f400839d0D912F21C39A - We deployed this contract in the previous step.
  • GENESIS_FORK_VERSION: 0x00000539 - We just change this to something that's not 0x0 to distinguish our network from mainnet.
  • BLS_WITHDRAWAL_PREFIX: 0x05 - We change this to something that's not 0x0 to not conflict with mainnet.
  • MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 16 - We want to be able to bootstrap the network with as little as 16 validators.
  • MIN_GENESIS_TIME: 1584316800 - This is our day we deployed the deposit contract, the genesis cannot happen before (Mar/16, 2020).
  • MIN_DEPOSIT_AMOUNT: 100000000 - We reduce the minimum deposit amount to 0.1 GöETH.
  • MAX_EFFECTIVE_BALANCE: 3200000000 - We reduce the maximum effective balance to 3.2 GöETH.
  • EJECTION_BALANCE: 1600000000 - We reduce the ejection balance to 1.6 GöETH.
  • EFFECTIVE_BALANCE_INCREMENT: 100000000 - We reduce the effective balance increment to 0.1 GöETH.
  • ETH1_FOLLOW_DISTANCE: 16 - We change the eth1 follow distance to 16.
  • MIN_GENESIS_DELAY: 3600 - We reduce the minimum genesis delay to one hour.

That's it, we just fully configured our eth2 network. I'll call this network Schlesi because it's a subway station close to Görli and it will be easier to reference it by a name. I compiled all configurations we did so far in a Gist on Github which can be feeded to clients later.

The genesis event

After fully configuring the network, we still don't have a network, yet. What's missing is the genesis state. The genesis is determined by a certain starting condition which is defined in the clients and by our previous network specification. It mainly breaks down to the following criteria:

  • The minimum number of active validator deposits: We configured 16 and the genesis event will not happen before the deposit contract registered 16 valid deposits.
  • The minimum genesis time: We configured March/16 2020 and the genesis event will not be happening before that date.
  • The minimum genesis delay: We configured to delay the genesis state by at least one hour. The genesis will not happen before we don't have 16 validator deposits and one hour passed.

Once these conditions are met, an eth2 client will be able to extract the genesis state from the eth1 chain and validators can start proposing blocks.

The Lighthouse client not only comes with beacon chain and a validator client, but also with a command line tool lcli that assists us in generating keypairs for validators and sending the required validator deposit directly to the deposit contract on the eth1 chain.

First, we instruct our lighthouse node how to configure the new testnet:

lcli --spec mainnet new-testnet \ # template new testnet on mainnet
--deposit-contract-address 0xaA888248144Bc5d584a7f400839d0D912F21C39A \
--deposit-contract-deploy-block 2355031 \
--effective-balance-increment 100000000 \
--ejection-balance 1600000000 \
--eth1-follow-distance 16 \
--genesis-fork-version 0x00000539 \
--max-effective-balance 3200000000 \
--min-deposit-amount 100000000 \
--min-genesis-active-validator-count 16 \
--min-genesis-delay 3600 \
--min-genesis-time 1584316800 \
--testnet-dir ~/.lighthouse/schlesi
Enter fullscreen mode Exit fullscreen mode

These are the values we defined in the previous step and have now been written to our testnet directory ~/.lighthouse/schlesi for further use by the Lighthouse client. To run a beacon node, simply point it to the config:

lighthouse bn \ # lighthouse beacon node
--testnet-dir ~/.lighthouse/schlesi \
--spec mainnet \
--eth1-endpoint http://127.0.0.1:8545 \
--http
Enter fullscreen mode Exit fullscreen mode

Now, our beacon node monitors our local Görli node on localhost port :8545 and waits that something happens on the deposit contract.

We can use lighthouse now to make validator deposits:

lighthouse account validator new \
--testnet-dir ~/.lighthouse/schlesi \
--spec mainnet \
--send-deposits \
--eth1-endpoint http://127.0.0.1:8545 \
--password ./password.txt \
--deposit-value 3200000000 random 
Enter fullscreen mode Exit fullscreen mode

This will do the following things:

  1. It reads our testnet spec in ~/.lighthouse/schlesi mainly to know about the deposit contract.
  2. It generates a keypair for a validator in ~/.lighthouse/validators.
  3. It generates a transaction and broadcasts it to the eth1 network using your local node. Important to note here, is that you have enough testnet Ether on the first account of your local Görli node (eth.accounts[0]) and that you provide a valid password to unlock that account.

This does not work with Parity Ethereum, so we used Geth instead. Also, to have both, HTTP-RPC APIs exposed and being able to unlock the accounts, one would have to pass the --allow-insecure-unlock flag to the Görli node. Please, use this with caution!

Once this was done, the node will give positive feedback:

Mar 18 13:53:48.174 INFO Validator deposit successful            validator_voting_pubkey: 0x82ad6def329bf94f06dae46b3222a3cb9baf2a68e1bf6e1dadaac5bb47dfe6690e2c3222b6256e17a4ec1bdbec6dbd65, eth1_tx_hash: 0x13cb9c913d946b222cb595f4bb42bd3e7d11e985d1d4dc3c50faacdc8e42e053
Enter fullscreen mode Exit fullscreen mode

This is how a deposit transaction to our contract looks like. Repeat this step 16 times to meet the minimum genesis deposit threshold. The beacon chain closely monitoring the deposit contract notices the met threshold:

Mar 18 13:55:42.991 INFO Minimum genesis deposit count met       block_number: 2366961, deposit_count: 16, service: beacon
Mar 18 13:55:57.647 INFO Deposit contract genesis complete       validator_count: 16, eth1_block_height: 2366961, service: beacon
Mar 18 13:55:57.680 INFO Beacon chain initialized                head_slot: 0, head_block: 0xd0ad…1b0d, head_state: 0xdadf…c6bc, service: beacon
Enter fullscreen mode Exit fullscreen mode

The genesis state can be extracted from the eth1 contract using lcli:

lcli eth1-genesis \
--testnet-dir ~/.lighthouse/schlesi \
--eth1-endpoint http://127.0.0.1:8545
Enter fullscreen mode Exit fullscreen mode

Bootstrapping the actual network

Now that the genesis event happened, we need two last things to bootstrap the actual network:

  1. Validators proposing new blocks
  2. Bootnode records allowing for other nodes to connect

Fortunately, both is available in Lighthouse. To run your 16 validators configured locally, simply run:

lighthouse vc --allow-unsynced
Enter fullscreen mode Exit fullscreen mode

The --allow-unsynced option is required as we do not have any other peers yet and simply allow the validator to start proposing blocks right away.

Mar 18 13:57:20.871 WARN Ethereum 2.0 is pre-release. This software is experimental.
Mar 18 13:57:20.876 INFO Starting validator client               datadir: "/home/user/.lighthouse/validators", beacon_node: http://localhost:5052/
Mar 18 13:57:20.893 INFO Connected to beacon node                version: Lighthouse/v0.1.0-unstable/x86_64-linux
Mar 18 13:57:20.900 INFO Starting node prior to genesis          seconds_to_wait: 3759
Enter fullscreen mode Exit fullscreen mode

The validator node now waits at least one hour before proposing blocks as defined in our MIN_GENESIS_DELAY.

Meanwhile, we can launch more beacon nodes and start wiring them. To connect them, we take the Ethereum Node Record (ENR) from each of the nodes and add them to our testnet configuration. The ENR looks as follows:

Mar 18 13:55:57.692 INFO ENR Initialised                         seq: 1, enr: enr:-Iu4QN6QRhX7abcUZ6E5eV9-AIUSXpNBSytiSNwG0FGWWifEevi98EDGhoPVt3e82j9KC2H7DiLtDGnj03MMrs707fEBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQL4Lu3nwG5diXILEh3LiAauCrNgtoTJxGZQER33BTDMKoN0Y3CCIyiDdWRwgiMo, service: network
Enter fullscreen mode Exit fullscreen mode

Our testnet configuration in ~/.lighthouse/schlesi contains a boot_enr.yaml file which we use to collect ENR of known peers to ease discovery. We simply add all known ENR of our beacon-bootnodes to that file which allows the network to have a first point of entry when adding new beacon nodes. The file could look like that:

- "enr:-Iu4QGCUN3RjOLZCab4LLqlOqnnOB9BspIE30Nj5gQGoY00ZXCIW2PCXuGqDLHEPZJK9NO8SFZlKzFF-5rSbTyPqksoBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQJmy_5ZkaIFozyMd3gPygG1lVLQONuTL4C1j_smkZ9WmoN0Y3CCIyiDdWRwgiMo"
- "enr:-Iu4QCKxIZVqkBMGHOxfeDvY8Yp0V0uq2MQ8wFS2tQGMfQ1YVuER_WeyVmqKawz6H4JE1OVeN52_kJUdZmkuvpyETjMBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQNsaKrbnhjMgAcpHREHrZiCA7sXyEOokOck_1oc3zZMG4N0Y3CCJRyDdWRwgiUc"
- "enr:-Iu4QN6QRhX7abcUZ6E5eV9-AIUSXpNBSytiSNwG0FGWWifEevi98EDGhoPVt3e82j9KC2H7DiLtDGnj03MMrs707fEBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQL4Lu3nwG5diXILEh3LiAauCrNgtoTJxGZQER33BTDMKoN0Y3CCIyiDdWRwgiMo"
Enter fullscreen mode Exit fullscreen mode

That's it. We have our own, custom beacon chain now running on Lighthouse.

Mar 21 16:38:26.000 INFO Synced                                  slot: 425, epoch: 13, finalized_epoch: 11, finalized_root: 0x41fc…1ac0, peers: 3, service: slot_notifier
Mar 21 16:38:32.226 INFO Block from local validator              block_slot: 426, block_root: 0xa2ef…e552, service: http
Mar 21 16:38:38.000 INFO Synced                                  slot: 426, epoch: 13, finalized_epoch: 11, finalized_root: 0x41fc…1ac0, peers: 3, service: slot_notifier
Mar 21 16:38:44.218 INFO Block from local validator              block_slot: 427, block_root: 0x563c…b946, service: http
Mar 21 16:38:48.018 INFO Attestation from local validator        slot: 427, index: 0, source: 12, target: 12, service: http
Mar 21 16:38:50.000 INFO Synced                                  slot: 427, epoch: 13, finalized_epoch: 11, finalized_root: 0x41fc…1ac0, peers: 3, service: slot_notifier
Mar 21 16:38:56.249 INFO Block from local validator              block_slot: 428, block_root: 0x8229…eb17, service: http
Mar 21 16:39:02.000 INFO Synced                                  slot: 428, epoch: 13, finalized_epoch: 11, finalized_root: 0x41fc…1ac0, peers: 3, service: slot_notifier
Mar 21 16:39:08.237 INFO Block from local validator              block_slot: 429, block_root: 0x4793…633b, service: http
Mar 21 16:39:12.012 INFO Attestation from local validator        slot: 429, index: 0, source: 12, target: 12, service: http
Mar 21 16:39:14.002 INFO Synced                                  slot: 429, epoch: 13, finalized_epoch: 11, finalized_root: 0x41fc…1ac0, peers: 3, service: slot_notifier
Mar 21 16:39:20.232 INFO Block from local validator              block_slot: 430, block_root: 0xabc4…4fb4, service: http
Enter fullscreen mode Exit fullscreen mode

It's important to note, that this network is permissionless. Everyone with 3.2 Görli ETH can generate a validator keypair and make a deposit to the Schlesi validator registration contract. Everyone can be part running validator nodes or beacon chain nodes by simply connecting to the provided ENR. Why don't you give it a try?

Soon, hopefully, we will be able to add other clients to our network, such as Prysm, Nimbus, Teku, or Trinity. The multi-client testnet phase is soon to be upon us. 🙏

Latest comments (1)

Collapse
 
thorstenhirsch profile image
Thorsten Hirsch

Do you know if all this stuff runs on ARM? Is a Raspberry Pi 2 powerful enough?