A high-performance relay node for Octus Bridge that validates cross-chain transfer events across Everscale, EVM-compatible networks, and Solana. The relay operates as a full Everscale node, observes bridge contracts, verifies event data, and signs or rejects events on behalf of a registered staker.
- Overview
- Features
- System Requirements
- Project Structure
- Getting Started
- Configuration
- CLI Reference
- Architecture
- Monitoring
- Development
- Changelog
- License
Octus Bridge Relay is the off-chain component that participates in the Octus Bridge consensus. Each relay instance:
- Synchronizes an embedded Everscale node and indexes bridge contract state.
- Subscribes to connector and event-configuration contracts on Everscale.
- Monitors configured EVM chains and Solana for inbound transfer events.
- Validates event payloads according to bridge ABI rules.
- Signs valid events or sends rejection messages back to the bridge.
Running the relay as a dedicated Everscale node ensures low-latency event observation and coordinated voting within a single masterchain block.
- Multi-chain support — Everscale, any configured EVM network, and Solana
- Embedded Everscale node — Built on
ton-indexerandeverscale-networkfor direct chain access - Encrypted keystore — ETH and TON keys stored with ChaCha20-Poly1305 encryption
- Prometheus metrics — Built-in exporter for operational visibility
- Flexible deployment — Native systemd service or Docker container
- Hot reload — Logger and metrics settings reload on
SIGHUP - Staking integration — Optional participation in relay elections (Everscale/Venom builds)
| Resource | Minimum |
|---|---|
| CPU | 8 cores @ 2 GHz |
| RAM | 16 GB |
| Storage | 200 GB fast SSD |
| Network | 100 Mbit/s |
Deployment scripts are tested on Ubuntu 20.04. Other distributions may require minor script adjustments.
octusbridge-relay/
├── Cargo.toml # Rust package manifest (v2.3.6)
├── Cargo.lock # Dependency lockfile
├── Dockerfile # Multi-stage Docker build
├── LICENSE
├── README.md
│
├── contracts/ # On-chain contract artifacts
│ └── evm/
│ ├── StakingRelayVerifier.sol
│ └── StakingRelayVerifier.abi
│
├── deploy/ # Deployment artifacts
│ ├── config/
│ │ └── config.yaml # Default relay configuration template
│ ├── debian/ # Debian package maintainer scripts
│ └── systemd/
│ ├── relay.native.service
│ └── relay.docker.service
│
├── scripts/ # Operational helper scripts (Ubuntu)
│ ├── setup.sh # Install relay (native or docker)
│ ├── generate.sh # Generate encrypted keystore
│ ├── export.sh # Export keys from keystore
│ └── update.sh # Update relay binary / image
│
└── src/
├── main.rs # CLI entry point (run, generate, export)
├── lib.rs # Library root
│
├── config/ # Application configuration
│ ├── mod.rs # AppConfig, BridgeConfig, NodeConfig
│ ├── eth_config.rs # EVM network settings
│ ├── sol_config.rs # Solana network settings
│ ├── stored_keys.rs # Encrypted keystore format
│ └── verification_state.rs
│
├── engine/ # Core relay engine
│ ├── mod.rs # Engine orchestration and metrics
│ ├── bridge/ # Bridge contract observer and event processor
│ ├── eth_subscriber/ # EVM chain log polling and verification
│ ├── sol_subscriber/ # Solana event polling
│ ├── ton_subscriber/ # Everscale contract state subscription
│ ├── keystore/ # ETH / TON key management and signing
│ ├── staking/ # Relay elections and round participation
│ ├── ton_meta/ # TON token metadata client (TON builds)
│ └── contracts/ # Bridge smart-contract bindings
│ ├── mod.rs # Contract facades and shared logic
│ ├── models.rs # ABI data types
│ ├── tests.rs # Contract integration tests
│ ├── core/ # Bridge and connector contracts
│ ├── events/ # Cross-chain event contracts
│ ├── configurations/ # Event configuration contracts
│ ├── staking/ # Staking, elections, relay rounds
│ └── tokens/ # Token root and wallet contracts
│
├── storage/ # Persistent and runtime state
│ ├── mod.rs # RocksDB-backed event storage
│ └── tables.rs # Database table definitions
│
└── utils/ # Shared utilities
├── eth_address.rs
├── existing_contract.rs
├── memory_cache.rs
├── pending_messages_queue.rs
├── retry.rs
├── serde_helpers.rs
├── shard_utils.rs
├── tristate.rs
└── tx_context.rs
After running setup.sh, the following paths are used on the host:
| Path | Purpose |
|---|---|
/etc/relay/config.yaml |
Relay configuration |
/etc/relay/keys.json |
Encrypted keystore |
/etc/relay/adnl-keys.json |
Temporary ADNL node keys |
/etc/relay/ton-global.config.json |
Everscale global network config |
/var/db/relay |
Everscale node database |
/var/db/relay-events |
Persistent event storage |
Choose one deployment method:
Native (recommended for production — lower overhead, better performance):
./scripts/setup.sh -t nativeDocker (simpler setup, higher resource overhead):
./scripts/setup.sh -t dockerThis creates a relay systemd service. Configuration and keys are placed under /etc/relay; the Everscale node database is stored at /var/db/relay.
Do not start the service yet.
Set required variables in the systemd unit at /etc/systemd/system/relay.service (recommended — keeps secrets out of the config file):
[Service]
Environment=RELAY_MASTER_KEY=your-master-key
Environment=RELAY_STAKER_ADDRESS=your-staker-address
Environment=ETH_MAINNET_URL=https://your-eth-rpc-endpoint
Environment=POLYGON_URL=https://your-polygon-rpc-endpointAlternatively, replace ${VAR} placeholders directly in /etc/relay/config.yaml.
./scripts/generate.sh -t native # or -t dockerAdd the -i flag to import existing seed phrases instead of generating new ones.
The script outputs unencrypted key material. Record it securely and back up /etc/relay.
Register the relay's ETH address and Everscale public key at octusbridge.io/relayers/create. Start the relay (step 5) during the linking process so it can confirm ownership on-chain.
- Initial sync takes approximately 40 minutes.
- Send at least 0.05 ETH to the relay's ETH address for ownership confirmation.
- Gas thresholds are configurable in
config.yamlif network fees are elevated.
sudo systemctl enable relay
sudo systemctl start relay
# Verify startup — look for "initialized relay" in logs
sudo journalctl -fu relayEnsure UDP port 30000 (default ADNL port) is open in your firewall.
For Docker deployments, pass all environment variables to the container (e.g. -e RELAY_MASTER_KEY) and update the unit file if you change the exposed port.
Environment variable substitution is supported throughout the config file using ${VAR} syntax.
See deploy/config/config.yaml for the canonical template. Key sections:
| Section | Description |
|---|---|
master_password |
Keystore encryption password |
staker_address |
Registered staker address |
bridge_settings |
Bridge contract, keys, EVM/Solana networks |
node_settings |
Everscale node DB path, ADNL port, RocksDB options |
storage |
Persistent event database path |
metrics_settings |
Prometheus exporter bind address and path |
Full example configuration
---
master_password: "${RELAY_MASTER_KEY}"
staker_address: "${RELAY_STAKER_ADDRESS}"
bridge_settings:
keys_path: "/etc/relay/keys.json"
bridge_address: "0:1d51fb47566d0d283ebbf83c641c01ebebaad6c3cec55895b0074b802036094e"
ignore_elections: false
shard_split_depth: 10
token_meta_base_url: "https://ton-tokens-api.meta"
sol_network:
endpoints: ["https://api.mainnet-beta.solana.com"]
poll_interval_sec: 30
evm_networks:
- chain_id: 1
endpoint: "${ETH_MAINNET_URL}"
get_timeout_sec: 10
blocks_processing_timeout_sec: 120
pool_size: 10
poll_interval_sec: 60
max_block_range: 1000
- chain_id: 56
endpoint: https://bsc-dataseed1.binance.org
get_timeout_sec: 10
pool_size: 10
poll_interval_sec: 60
max_block_range: 1000
- chain_id: 250
endpoint: https://rpc.ftm.tools
get_timeout_sec: 10
pool_size: 10
poll_interval_sec: 60
max_block_range: 1000
- chain_id: 137
endpoint: "${POLYGON_URL}"
get_timeout_sec: 10
pool_size: 10
poll_interval_sec: 60
max_block_range: 1000
- chain_id: 2001
endpoint: https://rpc-mainnet-cardano-evm.c1.milkomeda.com
get_timeout_sec: 10
pool_size: 10
poll_interval_sec: 60
maximum_failed_responses_time_sec: 604800
max_block_range: 1000
- chain_id: 43114
endpoint: https://api.avax.network/ext/bc/C/rpc
get_timeout_sec: 10
pool_size: 10
poll_interval_sec: 60
maximum_failed_responses_time_sec: 604800
max_block_range: 1000
- chain_id: 8217
endpoint: https://klaytn.blockpi.network/v1/rpc/public
get_timeout_sec: 10
pool_size: 10
poll_interval_sec: 60
maximum_failed_responses_time_sec: 604800
max_block_range: 5000
node_settings:
db_path: "/var/db/relay"
adnl_port: 30000
temp_keys_path: "/etc/relay/adnl-keys.json"
db_options:
rocksdb_lru_capacity: "2 GB"
cells_cache_size: "4 GB"
adnl_options:
force_use_priority_channels: false
storage:
persistent_db_path: "/var/db/relay-events"
metrics_settings:
listen_address: "127.0.0.1:10000"
metrics_path: "/metrics"
collection_interval_sec: 10The relay binary exposes three subcommands:
# Start the relay node
relay run --config /etc/relay/config.yaml --global-config /etc/relay/ton-global.config.json
# Generate a new encrypted keystore
relay generate /etc/relay/keys.json --config /etc/relay/config.yaml
relay generate /etc/relay/keys.json -i # import from existing seed phrases
# Export keys from keystore (JSON output)
relay export /etc/relay/keys.json --config /etc/relay/config.yamlThe scripts/ directory wraps these commands for systemd-managed deployments.
flowchart TB
subgraph Relay["Octus Bridge Relay"]
Engine["Engine"]
TonNode["Everscale Node<br/>(ton-indexer)"]
TonSub["TON Subscriber"]
EthSub["ETH Subscribers"]
SolSub["Solana Subscriber"]
Bridge["Bridge Processor"]
KS["Keystore"]
Store["Persistent Storage"]
end
TonChain["Everscale Network"] <--> TonNode
TonNode --> TonSub
TonSub --> Bridge
EthChains["EVM Networks"] --> EthSub
EthSub --> Bridge
SolChain["Solana"] --> SolSub
SolSub --> Bridge
Bridge --> KS
Bridge --> Store
Bridge --> TonNode
Engine --> TonSub & EthSub & SolSub & Bridge
- Synchronize the Everscale node and download blockchain state.
- Scan bridge contract state for connectors, active configurations, and pending events.
- Subscribe to the bridge contract and listen for new connector deployments.
- Subscribe to each active event-configuration contract.
- Start EVM and Solana subscribers for inbound event verification.
Everscale → EVM — The relay validates data packing correctness (on-chain contracts handle additional checks). Optional token metadata verification is available for TON (contract flag 0x01). Valid events are ABI-encoded and signed with the relay's ETH key; invalid events trigger a rejection message.
| Everscale type | EVM mapping |
|---|---|
bytes, string, uintX, intX, bool, fixedbytes |
Same |
fixedarray, array, tuple |
Same, recursively mapped |
| Other | Unsupported |
EVM → Everscale — The relay fully verifies event parameters, locates the source transaction on the target EVM network, converts data to a TVM cell, and sends a confirmation or rejection message.
Use the eth-ton-abi-converter tool to convert ABI definitions.
| EVM type | Everscale mapping |
|---|---|
address |
bytes (20 bytes) |
bytes |
bytes or cell (*) |
string, intX, uintX, bool |
Same |
fixedbytes1 |
Context flags (**) |
fixedbytesX |
Same |
array, fixedarray, tuple |
Same, recursively mapped or cell (***) |
| Other | Unsupported |
Context flags (set via a bytes1 element):
| Flag | Effect |
|---|---|
0x01 |
Place tuples in a new cell (***) |
0x02 |
Interpret bytes as encoded TVM cell (*) |
0x04 |
Insert default cell on error when 0x02 is set (*) |
0x08 |
Verify token root for token wallet |
Flags cannot be changed inside array elements — doing so produces inconsistent ABI items.
Earlier relay versions depended on shared light nodes or GraphQL endpoints, which caused reliability issues and delayed event observation. Embedding a full Everscale node allows relays to observe and vote on events within the same masterchain block, with a Rust implementation that is more resource-efficient than the C++ reference node.
The relay exposes Prometheus metrics (configured via metrics_settings). Default endpoint:
http://127.0.0.1:10000/metrics
Sample metrics output
eth_subscriber_last_processed_block{staker="0:7a97...",chain_id="1"} 13875962
eth_subscriber_pending_confirmation_count{staker="0:7a97...",chain_id="1"} 0
ton_subscriber_ready{staker="0:7a97..."} 1
ton_subscriber_mc_block_seqno{staker="0:7a97..."} 13426600
bridge_pending_eth_ton_event_count{staker="0:7a97..."} 0
bridge_pending_ton_eth_event_count{staker="0:7a97..."} 0
bridge_total_active_eth_ton_event_configurations{staker="0:7a97..."} 86
staking_current_relay_round{staker="0:7a97..."} 13
staking_elected{staker="0:7a97...",round_num="13"} 1
Send SIGHUP to reload logger and metrics exporter settings without restarting the process.
# Requires Rust 1.56+ and LLVM/Clang
cargo build --release
# Everscale/Venom build (default feature set)
cargo build --release --features venom
# TON network build
cargo build --release --features ton| Feature | Description |
|---|---|
venom |
Everscale/Venom network (default in .deb packages) |
ton |
TON network with double-broadcast and token metadata |
disable-staking |
Disable staking and elections (enabled by ton feature) |
double-broadcast |
Duplicate message broadcast via JRPC (enabled by ton feature) |
relay run -c deploy/config/config.yaml -g /path/to/ton-global.config.json./scripts/update.sh -t native # or -t docker- TON network relay support with ABI 2.3
- Token root verification for TVM networks
- Optional double-broadcast via JRPC for TON builds
- TON token metadata verification for TON→ETH events
Features
- Close expired Solana events
- Improve Solana metrics
Bugfixes
- Fixed clearing Solana events from pending buffer
Features
- Improved shard states GC
Bugfixes
- Fixed Solana events parsing
Features
- Fully reworked bridge with Solana
Bugfixes
- Stability fixes
Features
- Improved logger
- Added support for configuration feature flags
- Extend rejection info
Bugfixes
- Fixed transport issues
Bugfixes
- Fixed errors with SOL events during scanning all events
- Increased default polling interval
Features
- Add Solana
Bugfixes
- Fixed outgoing RLDP transfers
Features
- Replace
tiny-adnlwitheverscale-network - Optimize DB layout
Features
- Backport transport fixes
Features
- Added archives assembly
- Added new account model support
Bugfixes
- Fixed ADNL channels
Bugfixes
- Fixed memory leaks (new peers queue was read at a fixed rate)
Features
- Added packets compression support (enabled by default)
- Various optimizations
Features
- Updated ABI version to 2.2
- Fixed memory leaks (shard states were slowly filling with loaded storage cells)
Features
- ADNL security improvements
Features
- Optimized DB structure
Features
- Improved ETH events verification
- Updated events ABI
- Added
ton_subscriber_shard_client_time_diff,ton_subscriber_mc_block_seqno, andton_subscriber_shard_client_mc_block_seqnometrics
Features
- Use jemalloc by default
Bugfixes
- Fixed blocks GC memory issues
Features
- Hot reload for metrics exporter and logger settings (SIGHUP signal)
- Blocks and states garbage collection
- Additional EVM RPC timing controls
- Improved database layout and increased data locality
Bugfixes
- Fixed exported metrics format
- Fixed event confirmation counters
- Fixed time diff metrics
- Reduced blocks range for
eth_getLogs - Ignore descending blocks for ETH RPC
Features
- Added setup scripts for fast deployment
Bugfixes
- Fixed bridge contracts interaction logic according to new changes
Initial release.
See LICENSE.