diff --git a/docs/README.md b/docs/README.md index e1e81678..26d88234 100644 --- a/docs/README.md +++ b/docs/README.md @@ -15,6 +15,12 @@ This directory contains comprehensive documentation for setting up and operating - [Indexer Setup](./storagehub-indexer.md) - Indexer node configuration and operations - [Fisherman Setup](./storagehub-fisherman.md) - Fisherman node configuration and operations +### Snowbridge Relays +- [Beacon Relay](./snowbridge-beacon-relay.md) - Ethereum beacon chain → DataHaven +- [BEEFY Relay](./snowbridge-beefy-relay.md) - DataHaven BEEFY finality → Ethereum +- [Execution Relay](./snowbridge-execution-relay.md) - Ethereum messages → DataHaven +- [Solochain Relay](./snowbridge-solochain-relay.md) - DataHaven messages → Ethereum + ## Quick Reference ### Node Types Overview @@ -29,6 +35,15 @@ This directory contains comprehensive documentation for setting up and operating | **Indexer** | Blockchain data indexer | None | No | Yes (PostgreSQL) | | **Fisherman** | Storage provider monitor | 1 (BCSV ECDSA) | No | Yes (PostgreSQL) | +### Snowbridge Relays Overview + +| Relay | Direction | Keys Required | Persistent Storage | +|-------|-----------|---------------|-------------------| +| **Beacon Relay** | Ethereum → DataHaven | Substrate | Yes (datastore) | +| **BEEFY Relay** | DataHaven → Ethereum | Ethereum | No | +| **Execution Relay** | Ethereum → DataHaven | Substrate | Yes (datastore) | +| **Solochain Relay** | DataHaven → Ethereum | Ethereum + Substrate | Yes (datastore) | + ### Common CLI Flags All node types support standard Substrate flags: @@ -71,6 +86,8 @@ All node types support standard Substrate flags: - [Main Repository](https://github.com/Moonsong-Labs/datahaven) - [StorageHub Repository](https://github.com/Moonsong-Labs/storage-hub) +- [Snowbridge Repository](https://github.com/datahaven-xyz/snowbridge) (solochain branch) +- [Snowbridge Documentation](https://docs.snowbridge.network) - [E2E Testing Guide](../test/README.md) - [Docker Compose Guide](../operator/DOCKER-COMPOSE.md) - [Kubernetes Deployment](../deploy/charts/node/README.md) diff --git a/docs/snowbridge-beacon-relay.md b/docs/snowbridge-beacon-relay.md new file mode 100644 index 00000000..98ec9eae --- /dev/null +++ b/docs/snowbridge-beacon-relay.md @@ -0,0 +1,335 @@ +# Snowbridge Beacon Relay + +## Overview + +The Beacon Relay syncs Ethereum beacon chain (consensus layer) finality to the DataHaven blockchain. It monitors the Ethereum beacon chain and submits sync committee updates and finality proofs to the `EthereumBeaconClient` pallet on DataHaven. + +## Purpose + +- Relay Ethereum beacon chain finality to DataHaven +- Submit sync committee updates for light client verification +- Enable trustless verification of Ethereum state on DataHaven +- Support cross-chain message verification from Ethereum + +## Direction + +``` +Ethereum Beacon Chain → DataHaven +``` + +## Prerequisites + +- Docker with `linux/amd64` platform support +- Access to Ethereum consensus layer (beacon) endpoint +- Access to DataHaven node WebSocket endpoint +- Substrate account with balance for transaction fees +- Persistent storage for relay datastore + +## Key Requirements + +### Substrate Private Key + +The Beacon Relay requires a **Substrate private key** to sign and submit extrinsics to the DataHaven chain. + +| Key Type | Purpose | +|----------|---------| +| Substrate (sr25519/ecdsa) | Sign beacon update extrinsics on DataHaven | + +### Account Funding + +The relay account must be funded with HAVE tokens to pay for transaction fees when submitting beacon updates. + +**Recommended Balance**: 100+ HAVE for continuous operations + +## CLI Flags + +### Required Flags + +| Flag | Description | +|------|-------------| +| `--config ` | Path to the JSON configuration file | + +### Private Key Flags (One Required) + +| Flag | Description | +|------|-------------| +| `--substrate.private-key ` | Substrate private key URI directly | +| `--substrate.private-key-file ` | Path to file containing the private key | +| `--substrate.private-key-id ` | AWS Secrets Manager secret ID for the private key | + +## Configuration File + +### Structure + +```json +{ + "source": { + "beacon": { + "endpoint": "http://beacon-node:4000", + "stateEndpoint": "http://beacon-node:4000", + "spec": { + "syncCommitteeSize": 512, + "slotsInEpoch": 32, + "epochsPerSyncCommitteePeriod": 256, + "forkVersions": { + "deneb": 0, + "electra": 0 + } + }, + "datastore": { + "location": "/relay-data", + "maxEntries": 100 + } + } + }, + "sink": { + "parachain": { + "endpoint": "ws://datahaven-node:9944", + "maxWatchedExtrinsics": 8, + "headerRedundancy": 20 + }, + "updateSlotInterval": 30 + } +} +``` + +### Configuration Parameters + +#### Source (Beacon Chain) + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `source.beacon.endpoint` | Beacon chain HTTP API endpoint | `http://beacon-node:4000` | +| `source.beacon.stateEndpoint` | Beacon chain state endpoint (usually same as above) | `http://beacon-node:4000` | +| `source.beacon.spec.syncCommitteeSize` | Size of sync committee | `512` | +| `source.beacon.spec.slotsInEpoch` | Slots per epoch | `32` | +| `source.beacon.spec.epochsPerSyncCommitteePeriod` | Epochs per sync committee period | `256` | +| `source.beacon.spec.forkVersions` | Fork version configuration | `{"deneb": 0, "electra": 0}` | +| `source.beacon.datastore.location` | Path to persistent datastore | `/relay-data` | +| `source.beacon.datastore.maxEntries` | Maximum datastore entries | `100` | + +#### Sink (DataHaven) + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `sink.parachain.endpoint` | DataHaven WebSocket endpoint | `ws://datahaven-node:9944` | +| `sink.parachain.maxWatchedExtrinsics` | Max concurrent watched extrinsics | `8` | +| `sink.parachain.headerRedundancy` | Header redundancy factor | `20` | +| `sink.updateSlotInterval` | Slot interval for updates | `30` | + +## Initialization: Beacon Client Pallet + +Before starting the Beacon Relay, the `EthereumBeaconClient` pallet must be initialized with a checkpoint. + +### Generate Initial Checkpoint + +```bash +docker run --rm \ + -v $(pwd)/beacon-relay.json:/app/beacon-relay.json:ro \ + -v $(pwd)/checkpoint.json:/app/dump-initial-checkpoint.json \ + -v $(pwd)/datastore:/data \ + --platform linux/amd64 \ + datahavenxyz/snowbridge-relay:latest \ + generate-beacon-checkpoint --config beacon-relay.json --export-json +``` + +### Submit Checkpoint to DataHaven + +The checkpoint must be submitted via a sudo call to `EthereumBeaconClient.force_checkpoint`: + +```typescript +import { createClient } from 'polkadot-api'; +import { datahaven } from '@polkadot-api/descriptors'; + +const client = createClient(wsProvider); +const api = client.getTypedApi(datahaven); + +const forceCheckpointCall = api.tx.EthereumBeaconClient.force_checkpoint({ + update: checkpoint // Parsed from dump-initial-checkpoint.json +}); + +const tx = api.tx.Sudo.sudo({ + call: forceCheckpointCall.decodedCall +}); + +await tx.signAndSubmit(sudoSigner); +``` + +## Running the Relay + +### Docker Run + +```bash +docker run -d \ + --name snowbridge-beacon-relay \ + --platform linux/amd64 \ + --add-host host.docker.internal:host-gateway \ + --network datahaven-network \ + -v $(pwd)/beacon-relay.json:/configs/beacon-relay.json:ro \ + -v $(pwd)/relay-data:/relay-data \ + --pull always \ + datahavenxyz/snowbridge-relay:latest \ + run beacon \ + --config /configs/beacon-relay.json \ + --substrate.private-key "0x..." +``` + +### Docker Compose + +```yaml +version: '3.8' + +services: + beacon-relay: + image: datahavenxyz/snowbridge-relay:latest + container_name: snowbridge-beacon-relay + platform: linux/amd64 + restart: unless-stopped + volumes: + - ./configs/beacon-relay.json:/configs/beacon-relay.json:ro + - beacon-relay-data:/relay-data + command: + - "run" + - "beacon" + - "--config" + - "/configs/beacon-relay.json" + - "--substrate.private-key-file" + - "/secrets/substrate-key" + secrets: + - substrate-key + +volumes: + beacon-relay-data: + +secrets: + substrate-key: + file: ./secrets/beacon-relay-substrate-key +``` + +## Kubernetes Deployment + +```yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: dh-beacon-relay +spec: + serviceName: dh-beacon-relay + replicas: 1 + selector: + matchLabels: + app: dh-beacon-relay + template: + metadata: + labels: + app: dh-beacon-relay + spec: + containers: + - name: beacon-relay + image: datahavenxyz/snowbridge-relay:latest + imagePullPolicy: Always + args: + - "run" + - "beacon" + - "--config" + - "/configs/beacon-relay.json" + - "--substrate.private-key-file" + - "/secrets/dh-beacon-relay-substrate-key" + volumeMounts: + - name: config + mountPath: /configs + readOnly: true + - name: secrets + mountPath: /secrets + readOnly: true + - name: relay-data + mountPath: /relay-data + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + volumes: + - name: config + configMap: + name: beacon-relay-config + - name: secrets + secret: + secretName: dh-beacon-relay-substrate-key + volumeClaimTemplates: + - metadata: + name: relay-data + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 10Gi +``` + +## Monitoring + +### Health Checks + +The relay logs sync committee updates and beacon chain state: + +```bash +# View relay logs +docker logs -f snowbridge-beacon-relay + +# Check for successful updates +docker logs snowbridge-beacon-relay 2>&1 | grep -i "submitted\|update" +``` + +### Key Metrics to Monitor + +- Beacon chain slot lag +- Sync committee update frequency +- Transaction success rate +- Account balance (for fees) + +## Troubleshooting + +### Issue: Beacon Chain Not Ready + +**Symptoms**: Relay fails to start or continuously retries + +**Check**: +1. Beacon chain endpoint is accessible +2. Beacon chain has finalized blocks +3. Network connectivity between relay and beacon node + +```bash +# Test beacon chain connectivity +curl http://beacon-node:4000/eth/v1/beacon/states/head/finality_checkpoints +``` + +### Issue: Checkpoint Submission Failed + +**Check**: +1. Sudo account has sufficient balance +2. Checkpoint data is valid +3. DataHaven node is synced + +### Issue: Transaction Failures + +**Check**: +1. Relay account has sufficient HAVE balance +2. DataHaven node is accessible +3. No duplicate relayers submitting same updates + +## Security Considerations + +1. **Private Key Protection**: Store private keys securely (AWS Secrets Manager, Kubernetes secrets, or encrypted files) +2. **Network Security**: Restrict access to relay endpoints +3. **Access Control**: Use dedicated accounts with minimal required permissions +4. **Monitoring**: Set up alerts for relay failures + +## Related Documentation + +- [BEEFY Relay](./snowbridge-beefy-relay.md) +- [Execution Relay](./snowbridge-execution-relay.md) +- [Solochain Relay](./snowbridge-solochain-relay.md) +- [Snowbridge Documentation](https://docs.snowbridge.network) +- [DataHaven Snowbridge Repository](https://github.com/datahaven-xyz/snowbridge) diff --git a/docs/snowbridge-beefy-relay.md b/docs/snowbridge-beefy-relay.md new file mode 100644 index 00000000..05d51f73 --- /dev/null +++ b/docs/snowbridge-beefy-relay.md @@ -0,0 +1,353 @@ +# Snowbridge BEEFY Relay + +## Overview + +The BEEFY Relay submits DataHaven BEEFY (Bridge Efficiency Enabling Finality Yielder) finality proofs to the `BeefyClient` smart contract on Ethereum. This enables trustless verification of DataHaven state on Ethereum. + +## Purpose + +- Relay DataHaven BEEFY finality proofs to Ethereum +- Submit validator set commitments to BeefyClient contract +- Enable trustless verification of DataHaven state on Ethereum +- Support cross-chain message verification to Ethereum + +## Direction + +``` +DataHaven → Ethereum +``` + +## Prerequisites + +- Docker with `linux/amd64` platform support +- Access to DataHaven node WebSocket endpoint +- Access to Ethereum execution layer WebSocket endpoint +- Ethereum account with ETH for gas fees +- Deployed BeefyClient and Gateway contracts on Ethereum + +## Key Requirements + +### Ethereum Private Key + +The BEEFY Relay requires an **Ethereum private key** to sign and submit transactions to the BeefyClient contract. + +| Key Type | Purpose | +|----------|---------| +| Ethereum (secp256k1) | Sign Ethereum transactions to BeefyClient contract | + +### Account Funding + +The relay account must be funded with ETH to pay for gas when submitting BEEFY proofs. + +**Recommended Balance**: 0.5+ ETH for continuous operations (gas costs vary with network conditions) + +## CLI Flags + +### Required Flags + +| Flag | Description | +|------|-------------| +| `--config ` | Path to the JSON configuration file | + +### Private Key Flags (One Required) + +| Flag | Description | +|------|-------------| +| `--ethereum.private-key ` | Ethereum private key directly | +| `--ethereum.private-key-file ` | Path to file containing the private key | +| `--ethereum.private-key-id ` | AWS Secrets Manager secret ID for the private key | + +### Optional Flags + +| Flag | Description | Default | +|------|-------------|---------| +| `--on-demand` | Synchronize commitments on demand | `false` | + +## Configuration File + +### Structure + +```json +{ + "source": { + "polkadot": { + "endpoint": "ws://datahaven-node:9944" + } + }, + "sink": { + "ethereum": { + "endpoint": "ws://ethereum-node:8546", + "gas-limit": "" + }, + "descendants-until-final": 3, + "contracts": { + "BeefyClient": "0x4826533B4897376654Bb4d4AD88B7faFD0C98528", + "Gateway": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf" + } + }, + "on-demand-sync": { + "max-tokens": 5, + "refill-amount": 1, + "refill-period": 3600 + } +} +``` + +### Configuration Parameters + +#### Source (DataHaven) + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `source.polkadot.endpoint` | DataHaven WebSocket endpoint | `ws://datahaven-node:9944` | + +#### Sink (Ethereum) + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `sink.ethereum.endpoint` | Ethereum WebSocket endpoint | `ws://ethereum-node:8546` | +| `sink.ethereum.gas-limit` | Optional gas limit override | `""` (empty for auto) | +| `sink.descendants-until-final` | Blocks to wait for finality | `3` | +| `sink.contracts.BeefyClient` | BeefyClient contract address | `0x...` | +| `sink.contracts.Gateway` | Gateway contract address | `0x...` | + +#### On-Demand Sync (Rate Limiting) + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `on-demand-sync.max-tokens` | Maximum tokens for rate limiting | `5` | +| `on-demand-sync.refill-amount` | Tokens to refill per period | `1` | +| `on-demand-sync.refill-period` | Refill period in seconds | `3600` | + +## Prerequisites: BEEFY Protocol Ready + +Before starting the BEEFY Relay, the BEEFY protocol must be active on DataHaven. + +### Check BEEFY Status + +```bash +# Using curl with JSON-RPC +curl -s -H "Content-Type: application/json" \ + -d '{"id":1, "jsonrpc":"2.0", "method": "beefy_getFinalizedHead"}' \ + http://localhost:9944 + +# Should return a non-zero block hash when ready +``` + +### Automated Wait (Test Environment) + +The test framework automatically waits for BEEFY with a 60-second timeout: + +```typescript +const waitBeefyReady = async (pollIntervalMs: number, timeoutMs: number) => { + // Poll beefy_getFinalizedHead until it returns a non-zero hash +}; +``` + +## Running the Relay + +### Docker Run + +```bash +docker run -d \ + --name snowbridge-beefy-relay \ + --platform linux/amd64 \ + --add-host host.docker.internal:host-gateway \ + --network datahaven-network \ + -v $(pwd)/beefy-relay.json:/configs/beefy-relay.json:ro \ + --pull always \ + datahavenxyz/snowbridge-relay:latest \ + run beefy \ + --config /configs/beefy-relay.json \ + --ethereum.private-key "0x..." +``` + +### Docker Compose + +```yaml +version: '3.8' + +services: + beefy-relay: + image: datahavenxyz/snowbridge-relay:latest + container_name: snowbridge-beefy-relay + platform: linux/amd64 + restart: unless-stopped + volumes: + - ./configs/beefy-relay.json:/configs/beefy-relay.json:ro + command: + - "run" + - "beefy" + - "--config" + - "/configs/beefy-relay.json" + - "--ethereum.private-key-file" + - "/secrets/ethereum-key" + secrets: + - ethereum-key + +secrets: + ethereum-key: + file: ./secrets/beefy-relay-ethereum-key +``` + +## Kubernetes Deployment + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dh-beefy-relay +spec: + replicas: 1 + selector: + matchLabels: + app: dh-beefy-relay + template: + metadata: + labels: + app: dh-beefy-relay + spec: + containers: + - name: beefy-relay + image: datahavenxyz/snowbridge-relay:latest + imagePullPolicy: Always + args: + - "run" + - "beefy" + - "--config" + - "/configs/beefy-relay.json" + - "--ethereum.private-key-file" + - "/secrets/dh-beefy-relay-ethereum-key" + volumeMounts: + - name: config + mountPath: /configs + readOnly: true + - name: secrets + mountPath: /secrets + readOnly: true + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "250m" + volumes: + - name: config + configMap: + name: beefy-relay-config + - name: secrets + secret: + secretName: dh-beefy-relay-ethereum-key +``` + +Note: BEEFY Relay does **not** require persistent storage (no `volumeClaimTemplates`). + +## Contract Requirements + +### BeefyClient Contract + +The BeefyClient contract must be deployed on Ethereum and initialized with: +- Initial validator set +- Initial BEEFY authority set ID + +### Gateway Contract + +The Gateway contract coordinates cross-chain message passing and interacts with BeefyClient for verification. + +### Get Contract Addresses + +Contract addresses are typically stored in a deployments file after contract deployment: + +```typescript +const deployments = await parseDeploymentsFile(); +const beefyClientAddress = deployments.BeefyClient; +const gatewayAddress = deployments.Gateway; +``` + +## Monitoring + +### Health Checks + +```bash +# View relay logs +docker logs -f snowbridge-beefy-relay + +# Check for BEEFY proof submissions +docker logs snowbridge-beefy-relay 2>&1 | grep -i "submit\|proof\|commitment" +``` + +### Key Metrics to Monitor + +- BEEFY finality lag (DataHaven blocks behind) +- Ethereum transaction success rate +- Gas costs and account balance +- BeefyClient contract state + +### Ethereum Contract State + +```bash +# Check BeefyClient latest commitment (using cast from Foundry) +cast call $BEEFY_CLIENT "latestBeefyBlock()" --rpc-url $ETH_RPC_URL +``` + +## Troubleshooting + +### Issue: BEEFY Not Ready + +**Symptoms**: Relay fails to start with "BEEFY protocol not ready" + +**Check**: +1. DataHaven network has active validators +2. BEEFY pallet is enabled in runtime +3. Sufficient blocks have been produced for BEEFY finality + +```bash +# Check BEEFY finalized head +curl -s -H "Content-Type: application/json" \ + -d '{"id":1, "jsonrpc":"2.0", "method": "beefy_getFinalizedHead"}' \ + http://localhost:9944 +``` + +### Issue: Ethereum Transaction Failures + +**Check**: +1. Relay account has sufficient ETH for gas +2. BeefyClient contract is deployed and initialized +3. Gas price is appropriate for network conditions +4. No competing relayers submitting same proofs + +### Issue: Rate Limiting + +**Symptoms**: Relay slows down or stops submitting proofs + +**Check**: +1. `on-demand-sync` configuration is appropriate +2. Increase `max-tokens` if needed for higher throughput +3. Ensure `refill-period` matches expected submission frequency + +## Security Considerations + +1. **Private Key Protection**: Store Ethereum private keys securely +2. **Gas Management**: Monitor gas costs and set appropriate limits +3. **Access Control**: Use dedicated accounts with minimal ETH +4. **Monitoring**: Set up alerts for transaction failures and low balance + +## Economics + +### Gas Costs + +- BEEFY proof submission: ~0.0003 ETH per message (varies with gas price) +- Validator set updates: Higher gas cost (less frequent) + +### Incentives + +Relayers can earn incentives for successful proof submissions. See Snowbridge documentation for incentive structure. + +## Related Documentation + +- [Beacon Relay](./snowbridge-beacon-relay.md) +- [Execution Relay](./snowbridge-execution-relay.md) +- [Solochain Relay](./snowbridge-solochain-relay.md) +- [Snowbridge Documentation](https://docs.snowbridge.network) +- [DataHaven Snowbridge Repository](https://github.com/datahaven-xyz/snowbridge) diff --git a/docs/snowbridge-execution-relay.md b/docs/snowbridge-execution-relay.md new file mode 100644 index 00000000..de352366 --- /dev/null +++ b/docs/snowbridge-execution-relay.md @@ -0,0 +1,367 @@ +# Snowbridge Execution Relay + +## Overview + +The Execution Relay processes Ethereum execution layer events and delivers cross-chain messages to DataHaven. It monitors the Gateway contract on Ethereum and relays messages to the corresponding pallets on DataHaven. + +## Purpose + +- Relay Ethereum execution layer messages to DataHaven +- Monitor Gateway contract for outbound messages +- Submit message proofs to DataHaven for verification +- Enable cross-chain token transfers and message passing from Ethereum + +## Direction + +``` +Ethereum Execution Layer → DataHaven +``` + +## Prerequisites + +- Docker with `linux/amd64` platform support +- Access to Ethereum execution layer WebSocket endpoint +- Access to Ethereum consensus layer (beacon) HTTP endpoint +- Access to DataHaven node WebSocket endpoint +- Substrate account with balance for transaction fees +- Deployed Gateway contract on Ethereum +- Persistent storage for relay datastore + +## Key Requirements + +### Substrate Private Key + +The Execution Relay requires a **Substrate private key** to sign and submit extrinsics to DataHaven. + +| Key Type | Purpose | +|----------|---------| +| Substrate (sr25519/ecdsa) | Sign message delivery extrinsics on DataHaven | + +### Account Funding + +The relay account must be funded with HAVE tokens to pay for transaction fees. + +**Recommended Balance**: 100+ HAVE for continuous operations + +## CLI Flags + +### Required Flags + +| Flag | Description | +|------|-------------| +| `--config ` | Path to the JSON configuration file | + +### Private Key Flags (One Required) + +| Flag | Description | +|------|-------------| +| `--substrate.private-key ` | Substrate private key URI directly | +| `--substrate.private-key-file ` | Path to file containing the private key | +| `--substrate.private-key-id ` | AWS Secrets Manager secret ID for the private key | + +## Configuration File + +### Structure + +```json +{ + "source": { + "ethereum": { + "endpoint": "ws://ethereum-node:8546" + }, + "contracts": { + "Gateway": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf" + }, + "beacon": { + "endpoint": "http://beacon-node:4000", + "stateEndpoint": "http://beacon-node:4000", + "spec": { + "syncCommitteeSize": 512, + "slotsInEpoch": 32, + "epochsPerSyncCommitteePeriod": 256, + "forkVersions": { + "deneb": 0, + "electra": 0 + } + }, + "datastore": { + "location": "/relay-data", + "maxEntries": 100 + } + } + }, + "sink": { + "parachain": { + "endpoint": "ws://datahaven-node:9944", + "maxWatchedExtrinsics": 8, + "headerRedundancy": 20 + } + }, + "instantVerification": false, + "schedule": { + "id": null, + "totalRelayerCount": 1, + "sleepInterval": 1 + } +} +``` + +### Configuration Parameters + +#### Source (Ethereum) + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `source.ethereum.endpoint` | Ethereum execution layer WebSocket | `ws://ethereum-node:8546` | +| `source.contracts.Gateway` | Gateway contract address | `0x...` | + +#### Source (Beacon Chain) + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `source.beacon.endpoint` | Beacon chain HTTP API endpoint | `http://beacon-node:4000` | +| `source.beacon.stateEndpoint` | Beacon chain state endpoint | `http://beacon-node:4000` | +| `source.beacon.spec.*` | Beacon chain specification | See beacon spec parameters | +| `source.beacon.datastore.location` | Path to persistent datastore | `/relay-data` | +| `source.beacon.datastore.maxEntries` | Maximum datastore entries | `100` | + +#### Sink (DataHaven) + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `sink.parachain.endpoint` | DataHaven WebSocket endpoint | `ws://datahaven-node:9944` | +| `sink.parachain.maxWatchedExtrinsics` | Max concurrent watched extrinsics | `8` | +| `sink.parachain.headerRedundancy` | Header redundancy factor | `20` | + +#### Relay Settings + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `instantVerification` | Enable instant verification mode | `false` | +| `schedule.id` | Relayer instance ID (for multi-instance) | `null` or `0` | +| `schedule.totalRelayerCount` | Total number of relayer instances | `1` | +| `schedule.sleepInterval` | Seconds between message checks | `1` | + +## Multi-Instance Deployment + +For high-availability or load distribution, multiple Execution Relayers can be deployed: + +```json +{ + "schedule": { + "id": 0, + "totalRelayerCount": 3, + "sleepInterval": 1 + } +} +``` + +Each instance should have a unique `id` (0, 1, 2, ...) and the same `totalRelayerCount`. + +## Running the Relay + +### Docker Run + +```bash +docker run -d \ + --name snowbridge-execution-relay \ + --platform linux/amd64 \ + --add-host host.docker.internal:host-gateway \ + --network datahaven-network \ + -v $(pwd)/execution-relay.json:/configs/execution-relay.json:ro \ + -v $(pwd)/relay-data:/relay-data \ + --pull always \ + datahavenxyz/snowbridge-relay:latest \ + run execution \ + --config /configs/execution-relay.json \ + --substrate.private-key "0x..." +``` + +### Docker Compose + +```yaml +version: '3.8' + +services: + execution-relay: + image: datahavenxyz/snowbridge-relay:latest + container_name: snowbridge-execution-relay + platform: linux/amd64 + restart: unless-stopped + volumes: + - ./configs/execution-relay.json:/configs/execution-relay.json:ro + - execution-relay-data:/relay-data + command: + - "run" + - "execution" + - "--config" + - "/configs/execution-relay.json" + - "--substrate.private-key-file" + - "/secrets/substrate-key" + secrets: + - substrate-key + +volumes: + execution-relay-data: + +secrets: + substrate-key: + file: ./secrets/execution-relay-substrate-key +``` + +## Kubernetes Deployment + +```yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: dh-execution-relay +spec: + serviceName: dh-execution-relay + replicas: 1 + selector: + matchLabels: + app: dh-execution-relay + template: + metadata: + labels: + app: dh-execution-relay + spec: + containers: + - name: execution-relay + image: datahavenxyz/snowbridge-relay:latest + imagePullPolicy: Always + args: + - "run" + - "execution" + - "--config" + - "/configs/execution-relay.json" + - "--substrate.private-key-file" + - "/secrets/dh-execution-relay-substrate-key" + volumeMounts: + - name: config + mountPath: /configs + readOnly: true + - name: secrets + mountPath: /secrets + readOnly: true + - name: relay-data + mountPath: /relay-data + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + volumes: + - name: config + configMap: + name: execution-relay-config + - name: secrets + secret: + secretName: dh-execution-relay-substrate-key + volumeClaimTemplates: + - metadata: + name: relay-data + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 10Gi +``` + +## Message Flow + +### Ethereum → DataHaven Message Flow + +1. User calls Gateway contract on Ethereum +2. Gateway emits `OutboundMessageAccepted` event +3. Execution Relay monitors for Gateway events +4. Relay constructs message proof using beacon chain state +5. Relay submits proof to DataHaven via `EthereumInboundQueue` pallet +6. DataHaven verifies proof against beacon client state +7. Message is dispatched to target pallet + +### Supported Message Types + +- Token transfers (ERC-20 tokens to DataHaven) +- Arbitrary cross-chain messages +- Smart contract calls + +## Monitoring + +### Health Checks + +```bash +# View relay logs +docker logs -f snowbridge-execution-relay + +# Check for message processing +docker logs snowbridge-execution-relay 2>&1 | grep -i "message\|submit\|proof" +``` + +### Key Metrics to Monitor + +- Message queue depth +- Message delivery success rate +- Ethereum event processing lag +- Account balance (for fees) +- Beacon chain sync status + +## Troubleshooting + +### Issue: Messages Not Being Delivered + +**Check**: +1. Gateway contract address is correct +2. Ethereum endpoint is accessible +3. Beacon chain is synced +4. DataHaven node is accessible + +```bash +# Check Ethereum connectivity +curl -X POST -H "Content-Type: application/json" \ + --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ + http://ethereum-node:8545 +``` + +### Issue: Proof Verification Failures + +**Check**: +1. Beacon Relay is running and synced +2. `EthereumBeaconClient` pallet has recent updates +3. Beacon chain spec matches configuration + +### Issue: High Latency + +**Solutions**: +1. Reduce `sleepInterval` for faster message detection +2. Deploy multiple relay instances +3. Ensure low-latency connections to endpoints + +## Security Considerations + +1. **Private Key Protection**: Store Substrate private keys securely +2. **Network Security**: Use secure connections (WSS) when possible +3. **Access Control**: Use dedicated accounts with minimal permissions +4. **Monitoring**: Set up alerts for message delivery failures + +## Economics + +### Transaction Costs + +- Message delivery: ~0.012 DOT equivalent per message (varies with message size) +- Relayers earn incentives for successful deliveries + +### Incentive Structure + +Relayers can claim incentives from the protocol for successful message deliveries. See Snowbridge documentation for details. + +## Related Documentation + +- [Beacon Relay](./snowbridge-beacon-relay.md) +- [BEEFY Relay](./snowbridge-beefy-relay.md) +- [Solochain Relay](./snowbridge-solochain-relay.md) +- [Snowbridge Documentation](https://docs.snowbridge.network) +- [DataHaven Snowbridge Repository](https://github.com/datahaven-xyz/snowbridge) diff --git a/docs/snowbridge-solochain-relay.md b/docs/snowbridge-solochain-relay.md new file mode 100644 index 00000000..d77536ba --- /dev/null +++ b/docs/snowbridge-solochain-relay.md @@ -0,0 +1,418 @@ +# Snowbridge Solochain Relay + +## Overview + +The Solochain Relay handles DataHaven-specific operations, including relaying outbound messages from DataHaven to Ethereum and managing validator reward distributions. This relay is specific to the DataHaven solochain implementation of Snowbridge. + +## Purpose + +- Relay DataHaven outbound messages to Ethereum +- Submit messages to the Gateway contract on Ethereum +- Handle validator reward synchronization +- Enable cross-chain token transfers from DataHaven to Ethereum + +## Direction + +``` +DataHaven → Ethereum (with bidirectional monitoring) +``` + +## Prerequisites + +- Docker with `linux/amd64` platform support +- Access to DataHaven node WebSocket endpoint +- Access to Ethereum execution layer WebSocket endpoint +- Access to Ethereum consensus layer (beacon) HTTP endpoint +- Ethereum account with ETH for gas fees +- Substrate account for DataHaven operations +- Deployed BeefyClient, Gateway, and RewardsRegistry contracts on Ethereum +- Persistent storage for relay datastore + +## Key Requirements + +### Both Ethereum and Substrate Private Keys + +The Solochain Relay requires **both** an Ethereum private key and a Substrate private key. + +| Key Type | Purpose | +|----------|---------| +| Ethereum (secp256k1) | Sign Ethereum transactions to Gateway contract | +| Substrate (sr25519/ecdsa) | Sign DataHaven operations | + +### Account Funding + +| Account | Funding Required | +|---------|-----------------| +| Ethereum | 0.5+ ETH for gas fees | +| Substrate | 100+ HAVE for transaction fees | + +## CLI Flags + +### Required Flags + +| Flag | Description | +|------|-------------| +| `--config ` | Path to the JSON configuration file | + +### Ethereum Private Key Flags (One Required) + +| Flag | Description | +|------|-------------| +| `--ethereum.private-key ` | Ethereum private key directly | +| `--ethereum.private-key-file ` | Path to file containing the private key | +| `--ethereum.private-key-id ` | AWS Secrets Manager secret ID for the private key | + +### Substrate Private Key Flag + +| Flag | Description | +|------|-------------| +| `--substrate.private-key ` | Substrate private key URI | + +## Configuration File + +### Structure + +```json +{ + "source": { + "ethereum": { + "endpoint": "ws://ethereum-node:8546" + }, + "solochain": { + "endpoint": "ws://datahaven-node:9944" + }, + "contracts": { + "BeefyClient": "0x4826533B4897376654Bb4d4AD88B7faFD0C98528", + "Gateway": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf" + }, + "beacon": { + "endpoint": "http://beacon-node:4000", + "stateEndpoint": "http://beacon-node:4000", + "spec": { + "syncCommitteeSize": 512, + "slotsInEpoch": 32, + "epochsPerSyncCommitteePeriod": 256, + "forkVersions": { + "deneb": 0, + "electra": 0 + } + }, + "datastore": { + "location": "/relay-data", + "maxEntries": 100 + } + } + }, + "sink": { + "ethereum": { + "endpoint": "ws://ethereum-node:8546" + }, + "contracts": { + "Gateway": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf" + } + }, + "schedule": { + "id": 0, + "totalRelayerCount": 1, + "sleepInterval": 10 + }, + "reward-address": "0x4c5859f0F772848b2D91F1D83E2Fe57935348029", + "ofac": { + "enabled": false, + "apiKey": "" + } +} +``` + +### Configuration Parameters + +#### Source Configuration + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `source.ethereum.endpoint` | Ethereum WebSocket endpoint | `ws://ethereum-node:8546` | +| `source.solochain.endpoint` | DataHaven WebSocket endpoint | `ws://datahaven-node:9944` | +| `source.contracts.BeefyClient` | BeefyClient contract address | `0x...` | +| `source.contracts.Gateway` | Gateway contract address | `0x...` | +| `source.beacon.*` | Beacon chain configuration | See beacon spec | + +#### Sink Configuration + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `sink.ethereum.endpoint` | Ethereum WebSocket endpoint | `ws://ethereum-node:8546` | +| `sink.contracts.Gateway` | Gateway contract address | `0x...` | + +#### Schedule Configuration + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `schedule.id` | Relayer instance ID (for multi-instance) | `0` | +| `schedule.totalRelayerCount` | Total number of relayer instances | `1` | +| `schedule.sleepInterval` | Seconds between message checks | `10` | + +#### Rewards Configuration + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `reward-address` | RewardsRegistry contract address | `0x...` | + +#### OFAC Compliance (Optional) + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `ofac.enabled` | Enable OFAC sanctions screening | `false` | +| `ofac.apiKey` | API key for OFAC screening service | `""` | + +## Contract Requirements + +### Required Contracts + +1. **BeefyClient**: Verifies BEEFY finality proofs on Ethereum +2. **Gateway**: Handles cross-chain message passing +3. **RewardsRegistry**: Manages validator reward distribution + +### Get Contract Addresses + +```typescript +const deployments = await parseDeploymentsFile(); +const beefyClientAddress = deployments.BeefyClient; +const gatewayAddress = deployments.Gateway; +const rewardsRegistryAddress = deployments.RewardsRegistry; +``` + +## Running the Relay + +### Docker Run + +```bash +docker run -d \ + --name snowbridge-solochain-relay \ + --platform linux/amd64 \ + --add-host host.docker.internal:host-gateway \ + --network datahaven-network \ + -v $(pwd)/solochain-relay.json:/configs/solochain-relay.json:ro \ + -v $(pwd)/relay-data:/relay-data \ + --pull always \ + datahavenxyz/snowbridge-relay:latest \ + run solochain \ + --config /configs/solochain-relay.json \ + --ethereum.private-key "0x..." \ + --substrate.private-key "0x..." +``` + +### Docker Compose + +```yaml +version: '3.8' + +services: + solochain-relay: + image: datahavenxyz/snowbridge-relay:latest + container_name: snowbridge-solochain-relay + platform: linux/amd64 + restart: unless-stopped + volumes: + - ./configs/solochain-relay.json:/configs/solochain-relay.json:ro + - solochain-relay-data:/relay-data + command: + - "run" + - "solochain" + - "--config" + - "/configs/solochain-relay.json" + - "--ethereum.private-key-file" + - "/secrets/ethereum-key" + - "--substrate.private-key" + - "${SUBSTRATE_PRIVATE_KEY}" + secrets: + - ethereum-key + environment: + - SUBSTRATE_PRIVATE_KEY=${SUBSTRATE_PRIVATE_KEY} + +volumes: + solochain-relay-data: + +secrets: + ethereum-key: + file: ./secrets/solochain-relay-ethereum-key +``` + +## Kubernetes Deployment + +```yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: dh-solochain-relay +spec: + serviceName: dh-solochain-relay + replicas: 1 + selector: + matchLabels: + app: dh-solochain-relay + template: + metadata: + labels: + app: dh-solochain-relay + spec: + containers: + - name: solochain-relay + image: datahavenxyz/snowbridge-relay:latest + imagePullPolicy: Always + args: + - "run" + - "solochain" + - "--config" + - "/configs/solochain-relay.json" + - "--ethereum.private-key-file" + - "/secrets/dh-solochain-relay-ethereum-key" + - "--substrate.private-key" + - "$(SUBSTRATE_PRIVATE_KEY)" + env: + - name: SUBSTRATE_PRIVATE_KEY + valueFrom: + secretKeyRef: + name: dh-solochain-relay-substrate-key + key: private-key + volumeMounts: + - name: config + mountPath: /configs + readOnly: true + - name: secrets + mountPath: /secrets + readOnly: true + - name: relay-data + mountPath: /relay-data + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + volumes: + - name: config + configMap: + name: solochain-relay-config + - name: secrets + secret: + secretName: dh-solochain-relay-ethereum-key + volumeClaimTemplates: + - metadata: + name: relay-data + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 10Gi +``` + +## Message Flow + +### DataHaven → Ethereum Message Flow + +1. User submits outbound message on DataHaven +2. `EthereumOutboundQueue` pallet queues the message +3. Solochain Relay monitors for outbound messages +4. Relay constructs message proof using BEEFY finality +5. Relay submits proof to Gateway contract on Ethereum +6. Gateway verifies proof against BeefyClient +7. Message is executed on Ethereum + +### Reward Distribution Flow + +1. Validators earn rewards on DataHaven +2. Reward data is synchronized to RewardsRegistry contract +3. Operators can claim rewards on Ethereum + +## Multi-Instance Deployment + +For high-availability, deploy multiple Solochain Relayers: + +```json +{ + "schedule": { + "id": 0, + "totalRelayerCount": 2, + "sleepInterval": 10 + } +} +``` + +**Instance 0**: +```json +{ "schedule": { "id": 0, "totalRelayerCount": 2, "sleepInterval": 10 } } +``` + +**Instance 1**: +```json +{ "schedule": { "id": 1, "totalRelayerCount": 2, "sleepInterval": 10 } } +``` + +## Monitoring + +### Health Checks + +```bash +# View relay logs +docker logs -f snowbridge-solochain-relay + +# Check for message processing +docker logs snowbridge-solochain-relay 2>&1 | grep -i "message\|submit\|reward" +``` + +### Key Metrics to Monitor + +- Outbound message queue depth +- Message delivery success rate +- Reward synchronization status +- Ethereum and Substrate account balances +- BEEFY finality status + +## Troubleshooting + +### Issue: Messages Not Being Delivered + +**Check**: +1. BeefyClient has recent commitments (BEEFY Relay running) +2. Gateway contract address is correct +3. Both Ethereum and Substrate endpoints are accessible +4. Account balances are sufficient + +### Issue: Reward Synchronization Failures + +**Check**: +1. RewardsRegistry contract address is correct +2. Ethereum account has sufficient gas +3. Reward data is available on DataHaven + +### Issue: OFAC Screening Failures + +**Check**: +1. API key is valid (if OFAC enabled) +2. Network connectivity to OFAC service +3. Consider disabling OFAC for testing environments + +## Security Considerations + +1. **Private Key Protection**: Secure both Ethereum and Substrate keys +2. **Dual Account Management**: Monitor balances on both chains +3. **Network Security**: Use secure connections (WSS) when possible +4. **Access Control**: Use dedicated accounts with minimal permissions +5. **OFAC Compliance**: Enable OFAC screening for production if required + +## Dependencies + +The Solochain Relay depends on: +- **BEEFY Relay**: Must be running to provide finality proofs +- **Beacon Relay**: Must be running for Ethereum light client state + +Ensure both relays are operational before starting the Solochain Relay. + +## Related Documentation + +- [Beacon Relay](./snowbridge-beacon-relay.md) +- [BEEFY Relay](./snowbridge-beefy-relay.md) +- [Execution Relay](./snowbridge-execution-relay.md) +- [Snowbridge Documentation](https://docs.snowbridge.network) +- [DataHaven Snowbridge Repository](https://github.com/datahaven-xyz/snowbridge)