Skip to content

Commit

Permalink
docker: add support for persistent state builds with docker
Browse files Browse the repository at this point in the history
  • Loading branch information
d-sonuga committed Jan 23, 2025
1 parent 89a2db3 commit 2f1a7cf
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 2 deletions.
File renamed without changes.
58 changes: 58 additions & 0 deletions Dockerfile.persistent
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# --- Build stage ---
FROM ubuntu:24.04 AS build-stage

RUN apt-get update && apt-get install -y unzip curl build-essential openssl libssl-dev pkg-config && rm -rf /var/lib/apt/lists/*

RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

WORKDIR /opt/rusk
ENV RUSK_PROFILE_PATH=/opt/dusk/rusk/
ENV PATH="$PATH:/root/.cargo/bin"

RUN apt-get update && apt-get install -y clang && rm -rf /var/lib/apt/lists/*

COPY . .

ARG TARGETPLATFORM
# See also https://github.com/docker/buildx/issues/510
ENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}

# Generate keys and compile genesis contracts
RUN make keys
RUN make wasm

# Features to include in the build
# E.g., --build-arg CARGO_FEATURES="archive"
ARG NODE_TYPE="provisioner"

RUN case "$NODE_TYPE" in \
"provisioner") cargo build --release -p rusk ;; \
"archive") cargo build --release --features archive -p rusk ;; \
"prover") cargo build --release --no-default-features --features prover -p rusk ;; \
*) echo "Unrecognized node type: $NODE_TYPE. Expected one of 'provisioner', 'archive' and 'prover'"; exit 1 ;; \
esac

# --- Run stage ---
FROM ubuntu:24.04 AS run-stage

RUN apt-get update && apt-get install -y unzip curl net-tools libssl-dev && rm -rf /var/lib/apt/lists/*

WORKDIR /opt/dusk

ENV RUSK_PROFILE_PATH=/opt/dusk/rusk
ENV RUSK_RECOVERY_INPUT=/opt/dusk/conf/genesis.toml
ENV RUST_BACKTRACE=full
ENV NETWORK=mainnet

EXPOSE 9000/udp
EXPOSE 8080/tcp

# Copy only the necessary files from the build stage
COPY --from=build-stage /opt/rusk/target/release/rusk /opt/dusk/bin/rusk
COPY --from=build-stage /opt/rusk/scripts/persistent-docker-setup/setup.sh /opt/dusk/setup.sh
COPY --from=build-stage /opt/rusk/scripts/persistent-docker-setup/detect_ips.sh /opt/dusk/detect_ips.sh
COPY --from=build-stage /opt/rusk/scripts/persistent-docker-setup/conf /opt/dusk/conf

RUN chmod +x /opt/dusk/setup.sh /opt/dusk/detect_ips.sh

CMD [ "./setup.sh" ]
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,19 @@ make wasm for=transfer

## 🐳 Docker support

### Local Ephemeral Node

It's also possible to run a local ephemeral node with Docker.

To build the Docker image with archive:
```bash
docker build -t rusk .
docker build -f Dockerfile.ephemeral -t rusk .
```

To build the Docker image **without** archive:

```bash
docker build -t rusk --build-arg CARGO_FEATURES="" .
docker build -t -f Dockerfile.ephemeral rusk --build-arg CARGO_FEATURES="" .
```

To run Rusk inside a Docker container:
Expand All @@ -166,6 +168,26 @@ docker run -p 9000:9000/udp -p 8080:8080/tcp rusk

Port 9000 is used for Kadcast, port 8080 for the HTTP and GraphQL APIs.

### Persistent Node

To build the docker image for a provisioner
```bash
docker build -f Dockerfile.persistent -t rusk --build-arg NODE_TYPE=provisioner .
```

To build for an archiver or prover instead, build with NODE_TYPE=archive or NODE_TYPE=prover,
respectively.

To run:

```bash
docker run -it \
-v /path/to/consensus.keys:/opt/dusk/conf/consensus.keys
-v /path/to/rusk/profile:/opt/dusk/rusk \
-e NETWORK=testnet \
rusk
```

## License

The Rusk software is licensed under the [Mozilla Public License Version 2.0](./LICENSE).
56 changes: 56 additions & 0 deletions scripts/persistent-docker-setup/conf/rusk.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# log_type = 'coloured' (default)
# log_type = 'json'

# log_level = 'info' (default)
# log_filter = 'dusk_consensus=debug,node=debug,kadcast=debug'

[chain]
genesis_timestamp = ''
generation_timeout = '3s'
db_path = '/opt/dusk/rusk'
consensus_keys_path = '/opt/dusk/conf/consensus.keys'
min_gas_limit = 150_000
block_gas_limit = 3000000000

[databroker]
max_inv_entries = 100
max_ongoing_requests = 1000

[mempool]
max_queue_size = 5000
max_mempool_txn_count = 10000
idle_interval = '5m'
mempool_expiry = '30m'
mempool_download_redundancy = 5

[kadcast]
kadcast_id = 0x0
public_address = 'N/A'
listen_address = 'N/A'
bootstrapping_nodes = []
auto_propagate = false
channel_size = 10000
recursive_discovery = true

[kadcast.bucket]
node_ttl = '120s'
node_evict_after = '15s'
bucket_ttl = '10m'
min_peers = 20

[kadcast.network]
udp_recv_buffer_size = 5000000
# udp_send_backoff_timeout = '50us'
udp_send_retry_interval = '5ms'
udp_send_retry_count = 3
blocklist_refresh_interval = '10s'

[kadcast.fec.encoder]
min_repair_packets_per_block = 5
mtu = 1300
fec_redundancy = 0.15

[kadcast.fec.decoder]
cache_ttl = '1m'
cache_prune_every = '30s'
max_udp_len = 2097152
54 changes: 54 additions & 0 deletions scripts/persistent-docker-setup/detect_ips.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/bash

# Fetch IPv4 WAN address using ifconfig.me, fallback to ipinfo.io
PUBLIC_IP=$(curl -4 -s https://ifconfig.me)
if [ -z "$PUBLIC_IP" ]; then
PUBLIC_IP=$(curl -4 -s https://ipinfo.io/ip)
fi

# Validate IPv4 address
if [[ -z "$PUBLIC_IP" || ! "$PUBLIC_IP" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Error: Unable to retrieve a valid WAN IPv4 address"
exit 1
fi

runOnMac=false
int2ip() { printf ${2+-v} $2 "%d.%d.%d.%d" \
$(($1>>24)) $(($1>>16&255)) $(($1>>8&255)) $(($1&255)) ;}
ip2int() { local _a=(${1//./ }) ; printf ${2+-v} $2 "%u" $(( _a<<24 |
${_a[1]} << 16 | ${_a[2]} << 8 | ${_a[3]} )) ;}
while IFS=$' :\t\r\n' read a b c d; do
[ "$a" = "usage" ] && [ "$b" = "route" ] && runOnMac=true
if $runOnMac ;then
case $a in
gateway ) gWay=$b ;;
interface ) iFace=$b ;;
esac
else
[ "$a" = "0.0.0.0" ] && [ "$c" = "$a" ] && iFace=${d##* } gWay=$b
fi
done < <(/sbin/route -n 2>&1 || /sbin/route -n get 0.0.0.0/0)
ip2int $gWay gw
while read lhs rhs; do
[ "$lhs" ] && {
[ -z "${lhs#*:}" ] && iface=${lhs%:}
[ "$lhs" = "inet" ] && [ "$iface" = "$iFace" ] && {
mask=${rhs#*netmask }
mask=${mask%% *}
[ "$mask" ] && [ -z "${mask%0x*}" ] &&
printf -v mask %u $mask ||
ip2int $mask mask
ip2int ${rhs%% *} ip
(( ( ip & mask ) == ( gw & mask ) )) &&
int2ip $ip myIp && int2ip $mask netMask
}
}
done < <(/sbin/ifconfig)

echo "$PUBLIC_IP:9000"
if [ -z "$myIp" ]; then
echo "$PUBLIC_IP:9000"
else
echo "$myIp:9000"
fi

77 changes: 77 additions & 0 deletions scripts/persistent-docker-setup/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/bin/bash
set -e

echo "Starting node environment"

configure_network() {
local network=$1
local kadcast_id
local bootstrapping_nodes
local genesis_timestamp
local base_state
local prover_url

case "$network" in
mainnet)
kadcast_id="0x1"
bootstrapping_nodes="['165.232.91.113:9000', '64.226.105.70:9000', '137.184.232.115:9000']"
genesis_timestamp="'2025-01-07T12:00:00Z'"
base_state="https://nodes.dusk.network/genesis-state"
prover_url="https://provers.dusk.network"
;;
testnet)
kadcast_id="0x2"
bootstrapping_nodes="['134.122.62.88:9000','165.232.64.16:9000','137.184.118.43:9000']"
genesis_timestamp="'2024-12-23T17:00:00Z'"
base_state="https://testnet.nodes.dusk.network/genesis-state"
prover_url="https://testnet.provers.dusk.network"
;;
devnet)
kadcast_id="0x3"
bootstrapping_nodes="['128.199.32.54', '159.223.29.22', '143.198.225.158']"
genesis_timestamp="'2024-12-23T12:00:00Z'"
base_state="https://devnet.nodes.dusk.network/genesis-state"
prover_url="https://devnet.provers.dusk.network"
;;
*)
echo "Unknown network: $network. Defaulting to mainnet."
configure_network "mainnet"
return
;;
esac

# Create genesis.toml
cat > /opt/dusk/conf/genesis.toml <<EOF
base_state = "$base_state"
EOF

# Update the rusk.toml file with kadcast_id, bootstrapping_nodes & genesis_timestamp
sed -i "s/^kadcast_id =.*/kadcast_id = $kadcast_id/" /opt/dusk/conf/rusk.toml
sed -i "s/^bootstrapping_nodes =.*/bootstrapping_nodes = $bootstrapping_nodes/" /opt/dusk/conf/rusk.toml
sed -i "s/^genesis_timestamp =.*/genesis_timestamp = $genesis_timestamp/" /opt/dusk/conf/rusk.toml
}

configure_network "$NETWORK"

PUBLIC_IP=$(curl -4 -s https://ifconfig.me)
if [ -z "$PUBLIC_IP" ]; then
PUBLIC_IP=$(curl -4 -s https://ipinfo.io/ip)
fi

output=$(./detect_ips.sh)

export KADCAST_PUBLIC_ADDRESS=$(echo "$output" | sed -n '1p')
export KADCAST_LISTEN_ADDRESS=$(echo "$output" | sed -n '2p')

# Get consensus keys password
echo "Consensus keys password: "
read ckp
export DUSK_CONSENSUS_KEYS_PASS="$ckp"

echo "Selected network: $NETWORK"

/opt/dusk/bin/rusk recovery keys
/opt/dusk/bin/rusk recovery state

echo "Starting rusk"
/opt/dusk/bin/rusk --config /opt/dusk/conf/rusk.toml

0 comments on commit 2f1a7cf

Please sign in to comment.