# Testing Beacon Chain Withdrawals with Docker

By [Ladislaus](https://paragraph.com/@ladislaus) · 2023-02-01

---

This guide will provide you with **a minimal instruction** **set** if you intend to test:

*   Spinning up a **zhejiang** testnet node using Geth&Lighthouse with **Docker(-Compose)**
    
*   Exiting/withdrawing a validator on zhejiang testnet
    
*   Preparing withdrawal credential changes
    

Feel free to check out elementary guides on [how to run testnet nodes](https://mirror.xyz/ladislaus.eth/O5bW3rDnKITHlCXE9K_0IwiEwDrc6qw-y3MpX0EUcew) with the help of Docker or [Docker-Compose](https://mirror.xyz/ladislaus.eth/ah5UOhcstfmnk5rzTBQ-e26XudUqmxr3flnkLqlEDYE).

Also, if you’re generally keen on running a production (or testnet) Ethereum node with Docker, check out the awesome [eth-docker.net](https://eth-docker.net/) project.

* * *

Why run on zhejiang?
--------------------

*   Very fast node initialisation time (i.e. no extended sync periods + takes less than 2GBs of disk space)
    
*   Easy to obtain testnet ETH
    
*   It’s a short-lived, public testnet particularly designed for brief operation tests
    
*   Dry-run prior to more established testnets like Sepolia & Goerli which will follow in February/March ´23
    

Run a zhejiang testnet node
---------------------------

As an example client pair we’ll use Geth & Lighthouse on an [Ubuntu instance & pre-installed docker-compose](https://eth-docker.net/Usage/Prerequisites) - feel free to adapt to different client pairs using [this documentation](https://notes.ethereum.org/@launchpad/zhejiang#Which-versionbranch-do-I-use).

### 1.

**Navigate in a terminal/CLI to your user’s /home directory. Create a project directory with subfolders**

    $ mkdir -p zhejiang/{geth,lighthouse-bn,lighthouse-vc,JWT,validator_keys}; cd zhejiang
    

### 2.

**Retrieve configuration files for the zhejiang genesis from a repository maintained by the Ethereum Foundation**

    $ git clone https://github.com/ethpandaops/withdrawals-testnet.git
    

### 3.

**Generate a JasonWebToken (JWT) so that the execution and consensus client can communicate securely**

    $ openssl rand -hex 32 | tr -d "\n" > "$(pwd)/JWT/jwtsecret"
    

### 4.

**Provide Geth with the testnet genesis configuration**

    $ docker run -it -v $(pwd)/geth:/root/.ethereum -v $(pwd)/withdrawals-testnet/zhejiang-testnet/custom_config_data/genesis.json:/genesis.json ethpandaops/geth:master --datadir /root/.ethereum init genesis.json
    

> Depending on your Docker configuration every Docker command should be preceded by `sudo`

### 5.

**Copy & paste the below attached Docker-Compose code in a newly created file to be named “docker-compose.yaml” located in the project directory** `/zhejiang` 👇

    version: "3.4"
    
    services:
        consensus:
            image: sigp/lighthouse:capella
            container_name: beacon
            tty: true
            restart: on-failure
            volumes:
                - ./lighthouse-bn:/root/.lighthouse
                - ./JWT:/JWT
                - ./withdrawals-testnet/zhejiang-testnet/custom_config_data:/zhejiang
            ports:
                - 127.0.0.1:5052:5052 # consensus http
                - 9000:9000/tcp # consensus p2p, open to internet
                - 9000:9000/udp # consensus p2p, open to internet
            command: >
              lighthouse
              --testnet-dir zhejiang
              beacon_node
              --datadir /root/.lighthouse
              --eth1
              --http
              --http-allow-sync-stalled
              --http-address 0.0.0.0
              --enr-udp-port 9000
              --enr-tcp-port 9000
              --discovery-port 9000
              --validator-monitor-auto
              --execution-endpoints http://geth:8551
              --execution-jwt /JWT/jwtsecret
              --boot-nodes="enr:-Iq4QMCTfIMXnow27baRUb35Q8iiFHSIDBJh6hQM5Axohhf4b6Kr_cOCu0htQ5WvVqKvFgY28893DHAg8gnBAXsAVqmGAX53x8JggmlkgnY0gmlwhLKAlv6Jc2VjcDI1NmsxoQK6S-Cii_KmfFdUJL2TANL3ksaKUnNXvTCv1tLwXs0QgIN1ZHCCIyk,enr:-Ly4QOS00hvPDddEcCpwA1cMykWNdJUK50AjbRgbLZ9FLPyBa78i0NwsQZLSV67elpJU71L1Pt9yqVmE1C6XeSI-LV8Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpDuKNezAAAAckYFAAAAAAAAgmlkgnY0gmlwhEDhTgGJc2VjcDI1NmsxoQIgMUMFvJGlr8dI1TEQy-K78u2TJE2rWvah9nGqLQCEGohzeW5jbmV0cwCDdGNwgiMog3VkcIIjKA,enr:-MK4QMlRAwM7E8YBo6fqP7M2IWrjFHP35uC4pWIttUioZWOiaTl5zgZF2OwSxswTQwpiVCnj4n56bhy4NJVHSe682VWGAYYDHkp4h2F0dG5ldHOIAAAAAAAAAACEZXRoMpDuKNezAAAAckYFAAAAAAAAgmlkgnY0gmlwhJK-7tSJc2VjcDI1NmsxoQLDq7LlsXIXAoJXPt7rqf6CES1Q40xPw2yW0RQ-Ly5S1YhzeW5jbmV0cwCDdGNwgiMog3VkcIIjKA,enr:-MS4QCgiQisRxtzXKlBqq_LN1CRUSGIpDKO4e2hLQsffp0BrC3A7-8F6kxHYtATnzcrsVOr8gnwmBnHYTFvE9UmT-0EHh2F0dG5ldHOIAAAAAAAAAACEZXRoMpDuKNezAAAAckYFAAAAAAAAgmlkgnY0gmlwhKXoVKCJc2VjcDI1NmsxoQK6J-uvOXMf44iIlilx1uPWGRrrTntjLEFR2u-lHcHofIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo,enr:-LK4QOQd-elgl_-dcSoUyHDbxBFNgQ687lzcKJiSBtpCyPQ0DinWSd2PKdJ4FHMkVLWD-oOquXPKSMtyoKpI0-Wo_38Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpDuKNezAAAAckYFAAAAAAAAgmlkgnY0gmlwhES3DaqJc2VjcDI1NmsxoQNIf37JZx-Lc8pnfDwURcHUqLbIEZ1RoxjZuBRtEODseYN0Y3CCIyiDdWRwgiMo,enr:-KG4QLNORYXUK76RPDI4rIVAqX__zSkc5AqMcwAketVzN9YNE8FHSu1im3qJTIeuwqI5JN5SPVsiX7L9nWXgWLRUf6sDhGV0aDKQ7ijXswAAAHJGBQAAAAAAAIJpZIJ2NIJpcIShI5NiiXNlY3AyNTZrMaECpA_KefrVAueFWiLLDZKQPPVOxMuxGogPrI474FaS-x2DdGNwgiMog3VkcIIjKA"
    
        validator:
            image: sigp/lighthouse:capella
            container_name: vc
            tty: true
            restart: on-failure
            volumes:
                - ./lighthouse-vc:/root/.lighthouse
                - ./withdrawals-testnet/zhejiang-testnet/custom_config_data:/zhejiang
            depends_on:
                - consensus
            command: >
              lighthouse
              --testnet-dir zhejiang
              validator
              --beacon-nodes http://beacon:5052
              --suggested-fee-recipient 0x0000000000000000000000000000000000000000
    
        execution:
            image: ethpandaops/geth:master
            container_name: geth
            tty: true
            restart: on-failure
            volumes:
                - ./geth:/root/.ethereum
                - ./JWT:/JWT
            ports:
                - 127.0.0.1:8551:8551 # engine rpc
                - 30303:30303/tcp # execution p2p, open to internet
                - 30303:30303/udp # execution p2p, open to internet
                - 8545:8545
            command: >
              --datadir /root/.ethereum
              --http
              --http.addr 0.0.0.0
              --http.vhosts *
              --http.corsdomain *
              --http.api engine,eth,web3,net,debug
              --http.port 8545
              --authrpc.jwtsecret /JWT/jwtsecret
              --authrpc.addr 0.0.0.0
              --authrpc.port 8551
              --authrpc.vhosts *
              --networkid 1337803
              --syncmode full
              --bootnodes "enode://691c66d0ce351633b2ef8b4e4ef7db9966915ca0937415bd2b408df22923f274873b4d4438929e029a13a680140223dcf701cabe22df7d8870044321022dfefa@64.225.78.1:30303,enode://89347b9461727ee1849256d78e84d5c86cc3b4c6c5347650093982b726d71f3d08027e280b399b7b6604ceeda863283dcfe1a01e93728b4883114e9f8c7cc8ef@146.190.238.212:30303,enode://c2892072efe247f21ed7ebea6637ade38512a0ae7c5cffa1bf0786d5e3be1e7f40ff71252a21b36aa9de54e49edbcfc6962a98032adadfa29c8524262e484ad3@165.232.84.160:30303,enode://71e862580d3177a99e9837bd9e9c13c83bde63d3dba1d5cea18e89eb2a17786bbd47a8e7ae690e4d29763b55c205af13965efcaf6105d58e118a5a8ed2b0f6d0@68.183.13.170:30303,enode://2f6cf7f774e4507e7c1b70815f9c0ccd6515ee1170c991ce3137002c6ba9c671af38920f5b8ab8a215b62b3b50388030548f1d826cb6c2b30c0f59472804a045@161.35.147.98:30303"
    

### 6.

**Start the Docker-Compose environment**

    $ docker-compose up
    

Eventually, stop the docker-compose environment: `$ docker-compose stop`

For stopping _only_ the **beacon** or **execution** or **validator** client services use:

    $ docker-compose stop execution/consensus/validator
    

* * *

Interlude: Becoming a validator (out of scope)
----------------------------------------------

Steps 1-4 are [well-documented](https://github.com/eth-educators/ethstaker-guides/blob/main/zhejiang.md#trying-the-zhejiang-testnet) elsewhere:

1.  [Add network to your local metmask](https://zhejiang.ethpandaops.io/)
    
2.  Receive 33 zETH from a [faucet](https://faucet.zhejiang.ethpandaops.io/)
    
3.  Generate validator keys (e.g. with Staking-CLI) using 0x00 credentials (for test purposes)
    
4.  Deposit via [zhejiang launchpad](https://zhejiang.launchpad.ethereum.org/en/)
    
5.  Look out for your validator on a [block explorer](https://zhejiang.beaconcha.in/)
    
6.  Move generated keys into project folder subdirectory `/validator_keys`
    
7.  Import validator key(s) to Lighthouse
    
    👉 based of the project directory `/zhejiang` prompt:
    

    $ docker run -it -v $(pwd)/lighthouse-vc:/root/.lighthouse -v $(pwd)/validator_keys:/validator_keys -v  $(pwd)/withdrawals-testnet/zhejiang-testnet/custom_config_data:/zhejiang sigp/lighthouse:capella lighthouse --testnet-dir zhejiang account validator import --directory /validator_keys
    

* * *

Testing withdrawing / exiting a validator
-----------------------------------------

[Provide the consensus client](https://lighthouse-book.sigmaprime.io/voluntary-exit.html#voluntary-exits) with the necessary information in order to be released from consensus duties.

While your validator client is running in the background prompt:

    $ docker-compose run --rm --no-deps -v $(pwd)/lighthouse-vc:/root/.lighthouse -v $(pwd)/withdrawals-testnet/zhejiang-testnet/custom_config_data:/zhejiang consensus lighthouse --testnet-dir zhejiang account validator exit --beacon-node http://beacon:5052  --keystore /root/.lighthouse/custom/validators/<0x_yourvalidatorkey>/voting-keystore.json
    

_Edit the validator key directory and voting-keystore.json filename accordingly_

> Note for mainnet: node operators have to keep on running their node until the validator reaches its assigned exit epoch (s. block explorer) - if it is shutdown too early, the validator will incur penalties.

* * *

Addendum: Testing withdrawal credential change
----------------------------------------------

…also known as “BLS to Execution” operation. This operation comprises of a message broadcast to the network which will lead to a change from the BLS withdrawal credentials (_0x00_) to a regular Ethereum address (_0x01_) of your choice.

> Note: currently around ~60% or ~300,000 mainnet validators have BLS credentials and need to make a one-time change to a regular Ethereum address in order to fully or partially withdraw their stake or rewards.

Find out **how to identify withdrawal credentials** by entering a validator index on [beaconcha.in](https://beaconcha.in/):

![staking with centralized custodians means: not your keys, not your crypto](https://storage.googleapis.com/papyrus_images/4616f8d1b640f38374b6e4c9f851de20ee73f30d46dfb499f813299aff3c2694.png)

staking with centralized custodians means: not your keys, not your crypto

* * *

**If you want to test changing withdrawal credentials from 0x00 -> 0x01, check out** [**these Docker instructions**](https://notes.ethereum.org/@launchpad/withdrawals-guide#BLS-to-execution-with-ethdo) **utilising a programm called** `ethdo` [by attestant.io](https://github.com/wealdtech/ethdo/blob/master/docs/changingwithdrawalcredentials.md).

The official [Staking-Deposit-CLI](https://github.com/ethereum/staking-deposit-cli) by the EF will be updated and include similar functionality shortly.

👉 Broadcasting of your BLS-to-execution key change will NOT happen before the (Zhejiang) Shanghai/Capella fork scheduled for the **07th of February 3 p.m. UTC**

[![User Avatar](https://storage.googleapis.com/papyrus_images/3811a0627444336ef4209cf8181f5c7b78c55436a60b5a44bff09a8c057b4358.jpg)](https://twitter.com/TimBeiko)

[timbeiko.eth](https://twitter.com/TimBeiko)

[@TimBeiko](https://twitter.com/TimBeiko)

[![Twitter Logo](https://paragraph.com/editor/twitter/logo.png)](https://twitter.com/TimBeiko/status/1621210105479061505)

There were some config issues in launching the network, but the devops and client teams are looking into it. The Shapella fork is planned for Tuesday 3pm UTC ![👀](https://abs-0.twimg.com/emoji/v2/72x72/1f440.png)

 [![Like Icon](https://paragraph.com/editor/twitter/heart.png) 10](https://twitter.com/TimBeiko/status/1621210105479061505)[

12:13 PM • Feb 2, 2023

](https://twitter.com/TimBeiko/status/1621210105479061505)

Up until then the generated message is just stored in a local pool. Once Shanghai/Capella is triggered, the BLS-to-execution messages will be automatically broadcasted/gossiped over the network to your peers.

As soon as a node holding your BLS-to-execution message proposes a block, the message will be _executed_.

> Note for mainnet:
> 
> *   _Be aware that changing withdrawal credentials involves providing withdrawal private keys. Thus,\*\*\*never\*_ **trust\*** instructions from a random stranger writing blogposts on mirror.xyz or elsewhere - instead: follow official announcements from client teams and developers\*
>     
> *   BLS-to-execution messages cannot be broadcasted until after the Shanghai/Capella hard fork
>     
> *   beaconcha.in have announced they will provide a web interface for dragging & dropping a signed credential-change.json file and submit it to the network
>     

* * *

\*\*\*\*

_Please keep in mind this is a testnet guide that may contain mistakes and that takes shortcuts which come with trade-offs. It could quickly become outdated as it’s subject to ever evolving network and client changes._

\*\*\*\*

_featured image CC BY-NC 2.0 by_ [_Matthew Warner_](https://www.flickr.com/photos/realmattwarner/33903269335/in/photolist-TDV7Nt-rGxoSa-BM2VmQ-dUt8ka-s1BTSq-7VpYYK-BUj17w-rHKBj2-rKmyCe-pf8bVc-BPkkZk-pf719g-7q5ah6-Bo7eYg-5EsMmD-5Ex4gU-Bo7yrZ-7G6GN5-7q6Ggm-TstYkt-dnGgGH-afoT1Y-s2MCQV-2eDtNY6-7q6CBJ-AZ76Su-rGqGgU-fahzQS-9rx31Q-rMPgRL-rLjLgz-rYZZpz-rE9mH9-rKuHn5-rZMgzS-rLdkS5-s263RP-rKu1yQ-4VnwNf-7q6Lro-36jUTc-BuuDw9-88pXRz-36pvCd-s3KKFM-s3HEqX-r3cjR6-s34W7M-s21wQq-rHroXp)

\*\*\*\*\*\*\*\*

_This post was supported by a grant from a CLR funding round held by EthStaker, mainly matched by the EF._

---

*Originally published on [Ladislaus](https://paragraph.com/@ladislaus/testing-beacon-chain-withdrawals-with-docker)*
