Skip to content

Commit

Permalink
Add wallet.sh (#1)
Browse files Browse the repository at this point in the history
* wip

* Add wallet.sh

* add testnet4 ci

* fix wallet name

* add regtest support

* Add ID mapping and fix rpcwallet
  • Loading branch information
gartnera authored Nov 26, 2024
1 parent cc20b4e commit e31315e
Show file tree
Hide file tree
Showing 7 changed files with 288 additions and 56 deletions.
39 changes: 38 additions & 1 deletion .github/workflows/build.yml → .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,41 @@ jobs:
with:
subject-name: ${{ env.IMAGE_BASE }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
push-to-registry: true
test:
runs-on: ubuntu-latest
needs: build
timeout-minutes: 45
env:
CONTAINER_NAME: testnet4
steps:
- run: |
docker pull ${{ needs.build.outputs.IMAGE }}
docker tag ${{ needs.build.outputs.IMAGE }} bitcoin-core-docker
- uses: actions/checkout@v4
- run: ./examples/${CONTAINER_NAME}.sh
- name: Wait for healthy
run: |
while ! docker exec -i ${CONTAINER_NAME} /opt/wallet-health.sh; do
if ! docker ps | grep ${CONTAINER_NAME}; then
echo "Container stopped?"
exit 1
fi
echo "waiting for ${CONTAINER_NAME} health"
echo "Last log: $(docker logs -n1 ${CONTAINER_NAME})"
sleep 15
done
- name: Restart container
run: |
docker restart ${CONTAINER_NAME}
- name: Wait for healthy after restart
run: |
while ! docker exec -i ${CONTAINER_NAME} /opt/wallet-health.sh; do
if ! docker ps | grep ${CONTAINER_NAME}; then
echo "Container stopped?"
exit 1
fi
echo "waiting for ${CONTAINER_NAME} health"
echo "Last log: $(docker logs -n1 ${CONTAINER_NAME})"
sleep 15
done
20 changes: 5 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
FROM debian:bullseye-slim

ARG UID=101
ARG GID=101

RUN groupadd --gid ${GID} bitcoin \
&& useradd --create-home --no-log-init -u ${UID} -g ${GID} bitcoin \
&& apt-get update -y \
&& apt-get install -y curl gosu \
RUN apt-get update -y \
&& apt-get install -y curl procps procps jq \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

ARG TARGETPLATFORM
ARG BITCOIN_VERSION=28.0
ENV BITCOIN_DATA=/home/bitcoin/.bitcoin
ENV PATH=/opt/bitcoin-${BITCOIN_VERSION}/bin:$PATH

RUN set -ex \
Expand All @@ -24,14 +18,10 @@ RUN set -ex \
&& rm *.tar.gz \
&& rm -rf /opt/bitcoin-${BITCOIN_VERSION}/bin/bitcoin-qt

COPY docker-entrypoint.sh /entrypoint.sh

VOLUME ["/home/bitcoin/.bitcoin"]

EXPOSE 8332 8333 18332 18333 18443 18444 38333 38332

ENTRYPOINT ["/entrypoint.sh"]
VOLUME ["/root/.bitcoin"]

RUN bitcoind -version | grep "Bitcoin Core version v${BITCOIN_VERSION}"

COPY wallet.sh wallet-health.sh /opt/

CMD ["bitcoind"]
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
# bitcoin-core-docker

This is a hard fork of [ruimarinho/docker-bitcoin-core](https://github.com/ruimarinho/docker-bitcoin-core) with support for new bitcoin core versions.
This is a hard fork of [ruimarinho/docker-bitcoin-core](https://github.com/ruimarinho/docker-bitcoin-core) with support for new bitcoin core versions.

## `wallet.sh`

We also include a script which can start a bitcoin rpc node with a wallet in watch only mode. We require this functionality for our [observer/signer nodes](https://github.com/zeta-chain/node).

This script is stored at `/opt/wallet.sh`.

You should set several environment variables when running this container:

| variable | description |
| -------- | ------- |
| `CHAIN` | `chain` config setting. Allowed values: main, test, testnet4, signet, regtest. |
| `RPC_USER` | `rpcuser` config setting. |
| `RPC_PASSWORD` | `rpcpassword` config setting. |
| `WALLET_NAME` | name of the wallet for the `createwallet` and `loadwallet` commands |
| `WALLET_ADDRESS` | address of the wallet |
| `NETWORK_HEIGHT_URL` | url which will return the current height of the network. Will use mempool.space if unset. |

ID mapping:

| chain | zetachain chain ID | port |
| -------- | ------- | --- |
| `main` | 8332 | 8332 |
| `testnet3` | 18332 | 18332 |
| `regtest` | 18444 | 18443 |
| `signet` | 18333 | 38332 |
| `testnet4` | 18334 | 48332 |
39 changes: 0 additions & 39 deletions docker-entrypoint.sh

This file was deleted.

10 changes: 10 additions & 0 deletions examples/testnet4.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

docker run -d \
--name testnet4 \
-e CHAIN=testnet4 \
-e RPC_USER=default \
-e RPC_PASSWORD=default \
-e WALLET_NAME=default \
-e WALLET_ADDRESS=tb1qfm8a8pxer0kmfa4xlk34e44xpr8g46ae0v04dw \
bitcoin-core-docker /opt/wallet.sh
18 changes: 18 additions & 0 deletions wallet-health.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

set -eo pipefail

wallet_name=default
if [[ -n $1 ]]; then
wallet_name=$1
fi

# this script checks if a wallet exists and is not scanning

echo "Getting wallet info"
wallet_info=$(bitcoin-cli -rpcwallet=${wallet_name} getwalletinfo)

if [[ $(echo "$wallet_info" | jq -r '.scanning') == "true" ]]; then
echo "Error: Wallet is currently scanning" >&2
exit 1
fi
189 changes: 189 additions & 0 deletions wallet.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
#!/bin/bash

# set default config
# this makes running bitcoin-cli interactively much easier

echo "
chain=${CHAIN}
rpcuser=${RPC_USER}
rpcpassword=${RPC_PASSWORD}
rpcallowip=0.0.0.0/0
[${CHAIN}]
rpcbind=0.0.0.0
">~/.bitcoin/bitcoin.conf

ensure_bitcoin_is_running() {
process_check=`ps aux | grep -v grep | grep bitcoind`
if [[ -z "${process_check}" ]]; then
echo "Bitcoind seems to have crashed, we are going to ensure no lock exists on the process and restart the daemon."
remove_lock_if_exists
start_bitcoind_daemon
fi
}

check_bitcoin_is_running() {
process_check=`ps aux | grep -v grep | grep bitcoind`
echo "${process_check}"
}

remove_lock_if_exists() {
if [ -f "~/.bitcoin/bitcoind.pid" ]; then
rm -rf ~/.bitcoin/bitcoind.pid || echo "Failed to delete PID"
else
echo "PID Doesn't Exist"
fi

if [ -f "~/.bitcoin/${CHAIN}/.lock" ]; then
rm -rf ~/.bitcoin/${CHAIN}/.lock || echo "Failed to delete data lock"
else
echo "Failed to delete data lock"
fi
}

start_bitcoind_daemon() {
start_bitcoind -daemon
}

start_bitcoind() {
bitcoind \
-pid=${HOME}/.bitcoin/bitcoind.pid \
-listen=1 \
-server=1 \
-txindex=1 \
-deprecatedrpc=create_bdb \
-deprecatedrpc=warnings \
$@
}

stop_bitcoind_daemon() {
bitcoin_pid=$(pgrep bitcoind)
echo "Kill bitcoind with kill -SIGTERM"
kill -SIGTERM "$bitcoin_pid"
echo "bitcoind PID: ${bitcoin_pid}"
while kill -0 "$bitcoin_pid" 2> /dev/null; do
echo "Waiting for bitcoind process to stop."
check_bitcoin_is_running
sleep 1
done
}

wait_for_daemon_active() {
while true; do
check_bitcoin_is_running
if bitcoin-cli getblockchaininfo ; then
return
fi
echo "Waiting for bitcoind to start..."
sleep 5
done
}

get_current_height() {
if [[ -z $NETWORK_HEIGHT_URL ]]; then
case $CHAIN in
"main")
NETWORK_HEIGHT_URL=https://mempool.space/api/blocks/tip/height
;;
"testnet3")
NETWORK_HEIGHT_URL=https://mempool.space/testnet/api/blocks/tip/height
;;
"testnet4")
NETWORK_HEIGHT_URL=https://mempool.space/testnet4/api/blocks/tip/height
;;
"signet")
NETWORK_HEIGHT_URL=https://mempool.space/signet/api/blocks/tip/height
;;
"regtest")
echo 0
return
;;
*)
echo "Unsupported chain: $CHAIN" >&2
return 1
;;
esac
fi
curl -s ${NETWORK_HEIGHT_URL}
}

wait_for_network_sync() {
echo "Wait until network is completely synced."
while true
do
network_current_block=`get_current_height || echo "No height was observed. Waiting for external network to return check height."`
node_current_block=`bitcoin-cli getblockchaininfo | jq -r '.blocks' || echo "No height was observed. Waiting for local network to return height."`
if [[ "${node_current_block}" -ge "${network_current_block}" ]]; then
echo "Bitcoin node is now synced, the local height is greater than or equal to the external height."
break
else
echo "Node height: ${node_current_block} Network Height: ${network_current_block} - Network Still Syncing"
fi
sleep 30
done
}

load_wallet() {
bitcoin-cli -named createwallet wallet_name=${WALLET_NAME} disable_private_keys=true load_on_startup=true descriptors=false || echo "wallet exists"
sleep 5
bitcoin-cli loadwallet ${WALLET_NAME} || echo "wallet already loaded"
sleep 5
bitcoin-cli -rpcwallet="${WALLET_NAME}" importaddress "${WALLET_ADDRESS}" "${WALLET_NAME}" true || echo "importaddress failed"
}

snapshot_restore() {
if [ "$SNAPSHOT_RESTORE" != "true" ]; then
return
fi

if [ -f ~/.bitcoin/extracted ]; then
echo "Snapshot already extracted. Skipping download and extraction."
return
fi

echo "Use restore from snapshot: $SNAPSHOT_RESTORE"

mkdir -p ~/.bitcoin/ || echo "already exists."
cd ~/.bitcoin/
rm -rf ~/.bitcoin/{$CHAIN}

curl -L "${SNAPSHOT_URL}" | tar -xzf -
touch ~/.bitcoin/extracted

echo "Snapshot Restored. Verify the data and folder structure."
echo "Bitcoin network snapshot restart process is complete."
}


echo "Remove Lock if Exists"
remove_lock_if_exists

echo "Check snapshot restore."
snapshot_restore

echo "Start Bitcoind Daemon"
start_bitcoind_daemon

echo "Wait for bitcoind to be active."
wait_for_daemon_active

echo "Wait for network sync."
wait_for_network_sync

echo "Ensure bitcoind is running."
ensure_bitcoin_is_running

echo "Wait for daemon active."
wait_for_daemon_active

echo "Load Wallet"
load_wallet

echo "Stop the daemon to start the non daemon forground process."
stop_bitcoind_daemon

echo "Check bitcoind is running."
check_bitcoin_is_running

echo "Start bitcoind foreground process"
start_bitcoind

0 comments on commit e31315e

Please sign in to comment.