# Testing Beacon Chain Withdrawals with Docker **Published by:** [Ladislaus](https://paragraph.com/@ladislaus/) **Published on:** 2023-02-01 **URL:** https://paragraph.com/@ladislaus/testing-beacon-chain-withdrawals-with-docker ## Content 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 testnetPreparing withdrawal credential changesFeel free to check out elementary guides on how to run testnet nodes with the help of Docker or Docker-Compose. Also, if you’re generally keen on running a production (or testnet) Ethereum node with Docker, check out the awesome 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 ETHIt’s a short-lived, public testnet particularly designed for brief operation testsDry-run prior to more established testnets like Sepolia & Goerli which will follow in February/March ´23Run a zhejiang testnet nodeAs an example client pair we’ll use Geth & Lighthouse on an Ubuntu instance & pre-installed docker-compose - feel free to adapt to different client pairs using this documentation.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 sudo5.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 elsewhere:Add network to your local metmaskReceive 33 zETH from a faucetGenerate validator keys (e.g. with Staking-CLI) using 0x00 credentials (for test purposes)Deposit via zhejiang launchpadLook out for your validator on a block explorerMove generated keys into project folder subdirectory /validator_keysImport 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 validatorProvide the consensus client 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 accordinglyNote 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:staking with centralized custodians means: not your keys, not your cryptoIf you want to test changing withdrawal credentials from 0x00 -> 0x01, check out these Docker instructions utilising a programm called ethdo by attestant.io. The official 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 timbeiko.eth @TimBeiko 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 10 12:13 PM • Feb 2, 2023 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 forkbeaconcha.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 ******** This post was supported by a grant from a CLR funding round held by EthStaker, mainly matched by the EF. ## Publication Information - [Ladislaus](https://paragraph.com/@ladislaus/): Publication homepage - [All Posts](https://paragraph.com/@ladislaus/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@ladislaus): Subscribe to updates - [Twitter](https://twitter.com/lvdaniels): Follow on Twitter