Set up a dockerized test network for bitcoind with a defined supply of bitcoin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"This notebook demonstrates how the docker Python package can be used to automatically set up a test environment with a defined state. It assumes that\n", | |
"* you have the docker package installed (if not, run pip install docker)\n", | |
"* you have a container image called bitcoin-alpine that contains a bitcoind in regtest mode and has exposed port 18332" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"#\n", | |
"# First we import the package and start two containers - alice and bob\n", | |
"#\n", | |
"import docker\n", | |
"client = docker.client.from_env()\n", | |
"alice = client.containers.run(\"bitcoin-alpine:latest\", auto_remove=True, detach=True, ports={\"18332\" : \"18332\"})\n", | |
"bob = client.containers.run(\"bitcoin-alpine:latest\", auto_remove=True, detach=True)\n", | |
"#\n", | |
"# Give them some time to come up\n", | |
"# \n", | |
"import time\n", | |
"time.sleep(3)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"#\n", | |
"# A utility function to get the IP address of a container on the bridge network\n", | |
"# \n", | |
"def get_ip(container, network_name=\"bridge\"):\n", | |
" nw = client.networks.get(network_name)\n", | |
" ip = [_.attrs['NetworkSettings']['Networks']['bridge']['IPAddress'] for _ in nw.containers if _.id == container.id][0]\n", | |
" return ip" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"'172.17.0.3'" | |
] | |
}, | |
"execution_count": 3, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"bob_ip = get_ip(bob)\n", | |
"bob_ip" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"ExecResult(exit_code=0, output=b'')" | |
] | |
}, | |
"execution_count": 4, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"#\n", | |
"# Ask alice to connect to bob\n", | |
"# \n", | |
"alice.exec_run(\"bitcoin-cli --rpcuser=user --rpcpassword=password -regtest addnode \" + bob_ip + \" add\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"#\n", | |
"# Now generate a few blocks\n", | |
"#\n", | |
"alice.exec_run(\"bitcoin-cli --rpcuser=user --rpcpassword=password -regtest generate 101\");" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"#\n", | |
"# Set up an account Alice with address mkvAYmgqrEFEsJ9zGBi9Z87gP5rGNAu2mx\n", | |
"# The private key for this address is (as WIF)\n", | |
"# cQowgjRpUocje98dhJrondLbHNmgJgAFKdUJjCTtd3VeMfWeaHh7\n", | |
"#\n", | |
"alice.exec_run(\"bitcoin-cli --rpcuser=user --rpcpassword=password -regtest importprivkey cQowgjRpUocje98dhJrondLbHNmgJgAFKdUJjCTtd3VeMfWeaHh7\")\n", | |
"#\n", | |
"# and verify\n", | |
"# \n", | |
"check=alice.exec_run(\"bitcoin-cli --rpcuser=user --rpcpassword=password -regtest dumpprivkey mkvAYmgqrEFEsJ9zGBi9Z87gP5rGNAu2mx\")\n", | |
"assert(check.output == b'cQowgjRpUocje98dhJrondLbHNmgJgAFKdUJjCTtd3VeMfWeaHh7\\n')" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"#\n", | |
"# Finally transfer 30 bitcoin to this address\n", | |
"#\n", | |
"alice.exec_run(\"bitcoin-cli --rpcuser=user --rpcpassword=password -regtest sendtoaddress mkvAYmgqrEFEsJ9zGBi9Z87gP5rGNAu2mx 30.0\")\n", | |
"#\n", | |
"# and mine 6 additional blocks\n", | |
"# \n", | |
"alice.exec_run(\"bitcoin-cli --rpcuser=user --rpcpassword=password -regtest generate 6\");\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"ExecResult(exit_code=0, output=b'[\\n {\\n \"address\": \"mkvAYmgqrEFEsJ9zGBi9Z87gP5rGNAu2mx\",\\n \"account\": \"\",\\n \"amount\": 30.00000000,\\n \"confirmations\": 6,\\n \"label\": \"\",\\n \"txids\": [\\n \"67981d12268ec0f6503ba8776a0d1724511ded5088c7a7bd2dc917dcebdc5ab4\"\\n ]\\n }\\n]\\n')" | |
] | |
}, | |
"execution_count": 8, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"#\n", | |
"# Let us check that this worked\n", | |
"# \n", | |
"time.sleep(1)\n", | |
"alice.exec_run(\"bitcoin-cli --rpcuser=user --rpcpassword=password -regtest listreceivedbyaddress\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"#\n", | |
"# Clean up again\n", | |
"#\n", | |
"alice.stop()\n", | |
"bob.stop()" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.6.2" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment