Skip to content
56 changes: 44 additions & 12 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
# How to Run

## Using `just`

[`just`](https://github.com/casey/just) is a command runner (similar to `make`) that helps execute project tasks.

Install just with:
- `cargo install just`, if you have cargo package manager,
- `brew install just`, if you're on Mac OS and have `brew` package manager installed,
- `sudo apt install just`, if you're using a Linux distribution.

### Run prerequisites

It's only needed once after checkout or when dependencies change:
- `just build`
- `just npm-install`

### Run full workflow example
- `just run-authorize-and-store papi` - for PAPI,
- `just run-authorize-and-store pjs` - for PJS.

#### Run individual commands for manual testing
- `just setup-services papi` - Setup all services (IPFS, zombienet, reconnect, PAPI descriptors),
- `just ipfs-init` - Initialize IPFS (if needed),
- `just ipfs-start` - Start IPFS daemon,
- `just bulletin-solo-zombienet-start` - Start zombienet,
- `just ipfs-connect` - Connect to IPFS nodes,
- `just ipfs-reconnect-start` - Start IPFS reconnect script,
- `just papi-generate` - Generate PAPI descriptors,
- `just run-example papi` - Run example with PAPI or PJS,
- `just teardown-services` - Stop all services

## Manually


```shell
cd polkadot-bulletin-chain # make you are inside the project directory for the following steps
```

## Download Zombienet
### Download Zombienet

```shell
OS="$(uname -s)"
Expand All @@ -29,7 +61,7 @@ wget "https://github.com/paritytech/zombienet/releases/download/v1.3.133/${zb_bi
chmod +x "${zb_bin}"
```

## Run Kubo
### Run Kubo

#### Execute Locally

Expand All @@ -51,7 +83,7 @@ docker run -d --name ipfs-node -v ipfs-data:/data/ipfs -p 4001:4001 -p 8080:8080
docker logs -f ipfs-node
```

## Run Bulletin Solochain with `--ipfs-server`
### Run Bulletin Solochain with `--ipfs-server`

```shell
# Bulletin Solochain
Expand Down Expand Up @@ -86,9 +118,9 @@ docker exec -it ipfs-node ipfs swarm connect /ip4/172.17.0.1/tcp/12347/ws/p2p/12
./scripts/ipfs-reconnect-solo.sh
```

## Run Bulletin (Westend) Parachain with `--ipfs-server`
### Run Bulletin (Westend) Parachain with `--ipfs-server`

### Prerequisites
#### Prerequisites

```shell
mkdir -p ~/local_bridge_testing/bin
Expand All @@ -114,7 +146,7 @@ cp target/release/polkadot-parachain ~/local_bridge_testing/bin
# polkadot-parachain 1.20.2-165ba47dc91 or higher
```

### Launch Parachain
#### Launch Parachain

```shell
# Bulletin Parachain (Westend)
Expand All @@ -124,7 +156,7 @@ POLKADOT_BINARY_PATH=~/local_bridge_testing/bin/polkadot \
./$(ls zombienet-*-*) -p native spawn ./zombienet/bulletin-westend-local.toml
```

### Connect IPFS Nodes
#### Connect IPFS Nodes

```shell
# Uses Kubo
Expand All @@ -147,19 +179,19 @@ docker exec -it ipfs-node ipfs swarm connect /ip4/172.17.0.1/tcp/12347/ws/p2p/12
./scripts/ipfs-reconnect-westend.sh
```

## Trigger Authorize, Store and IPFS Get
### Trigger Authorize, Store and IPFS Get

### Example for Simple Authorizing and Store
#### Example for Simple Authorizing and Store

#### Using Legacy @polkadot/api (PJS)
##### Using Legacy @polkadot/api (PJS)
```
cd examples
npm install

node authorize_and_store.js
```

#### Using Modern PAPI (Polkadot API)
##### Using Modern PAPI (Polkadot API)
```bash
cd examples
npm install
Expand All @@ -175,7 +207,7 @@ npm run papi:update
node authorize_and_store_papi.js
```

### Example for Multipart / Chunked Content / Big Files
#### Example for Multipart / Chunked Content / Big Files

The code stores one file, splits it into chunks, and then uploads those chunks to Bulletin.

Expand Down
194 changes: 153 additions & 41 deletions examples/justfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Polkadot Bulletin Chain - Just Commands
# Install just: brew install just
# Run `just --list` to see all available commands
#
# See README.md for usage instructions.

# PID file locations
PID_DIR := "/tmp/bulletin-pids"

# Default recipe - run the complete PAPI workflow test
default: authorize-and-store
default: run-authorize-and-store

# Build the bulletin chain node in release mode
build:
Expand All @@ -13,80 +16,191 @@ build:
npm-install:
npm install

# Test the complete workflow (builds, starts services, runs example, shuts down services)
# Parameters: api=[papi|pjs] - choose between Polkadot API (papi) or Polkadot JS (pjs)
authorize-and-store api="papi": build npm-install
# Initialize IPFS if not already initialized
ipfs-init:
#!/usr/bin/env bash
set -e

API_TYPE="{{ api }}"

if [[ "$API_TYPE" != "papi" && "$API_TYPE" != "pjs" ]]; then
echo "❌ Error: api parameter must be 'papi' or 'pjs'"
if [ -f "../kubo/ipfs" ]; then
IPFS_CMD="../kubo/ipfs"
elif command -v ipfs &> /dev/null; then
IPFS_CMD="ipfs"
else
echo "❌ Error: IPFS not found."
exit 1
fi

echo "🚀 Starting $API_TYPE workflow test..."
echo ""

# Check if IPFS is available
if ! command -v ipfs &> /dev/null; then
echo "❌ IPFS not found. Using local kubo binary..."
IPFS_CMD="./kubo/ipfs"
if [ ! -f "$IPFS_CMD" ]; then
echo "❌ Error: Neither system IPFS nor ./kubo/ipfs found."
echo "Please install IPFS or download kubo to ./kubo/"
exit 1
fi
else
IPFS_CMD="ipfs"
fi
echo "🔧 Using IPFS command: $IPFS_CMD"

# Initialize IPFS if needed
if [ ! -d ~/.ipfs ]; then
echo "📦 Initializing IPFS..."
$IPFS_CMD init
else
echo "✅ IPFS already initialized"
fi

# Start IPFS daemon in background
ipfs-start:
#!/usr/bin/env bash
set -e

mkdir -p {{ PID_DIR }}

if [ -f "../kubo/ipfs" ]; then
IPFS_CMD="../kubo/ipfs"
elif command -v ipfs &> /dev/null; then
IPFS_CMD="ipfs"
else
echo "❌ Error: IPFS not found."
exit 1
fi

# Start IPFS daemon in background
echo "🔧 Using IPFS command: $IPFS_CMD"
echo "📡 Starting IPFS daemon..."
$IPFS_CMD daemon > /tmp/ipfs-daemon.log 2>&1 &
IPFS_PID=$!
echo $IPFS_PID > {{ PID_DIR }}/ipfs.pid
echo " IPFS PID: $IPFS_PID"
echo " Log: /tmp/ipfs-daemon.log"
sleep 2

# Connect to IPFS nodes
ipfs-connect:
#!/usr/bin/env bash
set -e

if [ -f "../kubo/ipfs" ]; then
IPFS_CMD="../kubo/ipfs"
elif command -v ipfs &> /dev/null; then
IPFS_CMD="ipfs"
else
echo "❌ Error: IPFS not found."
exit 1
fi

echo "🔧 Using IPFS command: $IPFS_CMD"
echo "🔗 Connecting IPFS nodes..."
$IPFS_CMD swarm connect /ip4/127.0.0.1/tcp/12347/ws/p2p/12D3KooWRkZhiRhsqmrQ28rt73K7V3aCBpqKrLGSXmZ99PTcTZby || true
$IPFS_CMD swarm connect /ip4/127.0.0.1/tcp/10001/ws/p2p/12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm || true

# Start start solo chain with zombienet in background
bulletin-solo-zombienet-start:
#!/usr/bin/env bash
set -e

mkdir -p {{ PID_DIR }}

# Start zombienet in background
echo "⚡ Starting Bulletin chain with zombienet..."
POLKADOT_BULLETIN_BINARY_PATH=../target/release/polkadot-bulletin-chain ./$(ls zombienet-*-*) -p native spawn ./zombienet/bulletin-polkadot-local.toml > /tmp/zombienet.log 2>&1 &
POLKADOT_BULLETIN_BINARY_PATH=../target/release/polkadot-bulletin-chain ../$(ls ../zombienet-*-*) -p native spawn ../zombienet/bulletin-polkadot-local.toml > /tmp/zombienet.log 2>&1 &
ZOMBIENET_PID=$!
echo $ZOMBIENET_PID > {{ PID_DIR }}/zombienet.pid
echo " Zombienet PID: $ZOMBIENET_PID"
echo " Log: /tmp/zombienet.log"
echo " Waiting for chain to start (15 seconds)..."
sleep 15

# Start IPFS reconnect script in background
ipfs-reconnect-start:
#!/usr/bin/env bash
set -e

mkdir -p {{ PID_DIR }}

# Start IPFS reconnect script in background
echo "🔄 Starting IPFS reconnect script..."
./scripts/ipfs-reconnect-solo.sh > /tmp/ipfs-reconnect.log 2>&1 &
RECONNECT_PID=$!
echo $RECONNECT_PID > {{ PID_DIR }}/ipfs-reconnect.pid
echo " Reconnect PID: $RECONNECT_PID"
echo " Log: /tmp/ipfs-reconnect.log"
sleep 2

# Generate PAPI descriptors
papi-generate:
#!/usr/bin/env bash
set -e

echo "🔧 Generating PAPI descriptors..."
npm run papi:generate

# Setup all services needed for testing (IPFS, zombienet, IPFS reconnect, PAPI)
# Parameters: api=[papi|pjs] - choose between Polkadot API (papi) or Polkadot JS (pjs)
setup-services api="papi":
#!/usr/bin/env bash
set -e

API_TYPE="{{ api }}"

echo "🔧 Setting up services for $API_TYPE..."

# Generate PAPI descriptors (only for papi)
# Initialize IPFS
just ipfs-init

# Start services
just ipfs-start
just bulletin-solo-zombienet-start
just ipfs-connect
just ipfs-reconnect-start

# Generate PAPI descriptors if needed
if [ "$API_TYPE" == "papi" ]; then
echo "🔧 Generating PAPI descriptors..."
npm run papi:generate
just papi-generate
fi

echo "✅ Services setup complete"

# Stop all running services (IPFS, zombienet, reconnect script)
teardown-services:
#!/usr/bin/env bash

echo "🧹 Stopping all services..."

# Stop services by reading PIDs from files
if [ -d {{ PID_DIR }} ]; then
for pidfile in {{ PID_DIR }}/*.pid; do
if [ -f "$pidfile" ]; then
PID=$(cat "$pidfile")
SERVICE=$(basename "$pidfile" .pid)
if kill $PID 2>/dev/null; then
echo " ✓ Stopped $SERVICE (PID: $PID)"
else
echo " ⚠ $SERVICE (PID: $PID) not running or already stopped"
fi
rm "$pidfile"
fi
done
rmdir {{ PID_DIR }} 2>/dev/null || true
else
echo " No running services found"
fi

echo "✅ Services stopped"

# Test the complete workflow (builds, starts services, runs example, shuts down services)
# Parameters: api=[papi|pjs] - choose between Polkadot API (papi) or Polkadot JS (pjs)
run-authorize-and-store api="papi": build npm-install
#!/usr/bin/env bash
set -e

API_TYPE="{{ api }}"

if [[ "$API_TYPE" != "papi" && "$API_TYPE" != "pjs" ]]; then
echo "❌ Error: api parameter must be 'papi' or 'pjs'"
exit 1
fi

# Determine which example to run
echo "🚀 Starting $API_TYPE workflow test..."
echo ""

# Setup all services
just setup-services $API_TYPE

# Run the example
if [ "$API_TYPE" == "papi" ]; then
EXAMPLE_FILE="authorize_and_store_papi.js"
else
EXAMPLE_FILE="authorize_and_store.js"
fi

# Run the example
echo ""
echo "🎯 Running $EXAMPLE_FILE example..."
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
node $EXAMPLE_FILE
EXAMPLE_EXIT=$?

Expand All @@ -105,8 +219,6 @@ authorize-and-store api="papi": build npm-install
echo " /tmp/ipfs-reconnect.log"

# Clean up background processes
echo "🧹 Cleaning up background processes..."
kill $IPFS_PID $ZOMBIENET_PID $RECONNECT_PID 2>/dev/null || true

just teardown-services

exit $EXAMPLE_EXIT