Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c88b37e
Initial commit of subnet deployment management script
phutchins Oct 17, 2025
0122f9d
Adding info command
phutchins Oct 17, 2025
6162aab
fix: resolve libp2p binding issue on cloud VMs
phutchins Oct 17, 2025
8d83981
feat: add configurable `listen-ip` option to P2P configuration
phutchins Oct 17, 2025
0d61d66
fix: update subnet configuration and add documentation for parent fin…
phutchins Oct 18, 2025
f2ede72
feat: add watch-finality command for real-time monitoring of parent f…
phutchins Oct 18, 2025
e23e442
feat: introduce watch-blocks command for real-time block production m…
phutchins Oct 18, 2025
6665dd8
feat: add advanced performance tuning guide and apply tuning script
phutchins Oct 18, 2025
2be6670
feat: implement fix for bottom-up checkpoint broadcasting error
phutchins Oct 18, 2025
3919bee
feat: introduce live monitoring dashboard for IPC subnets
phutchins Oct 20, 2025
dfbdc46
feat: add bottom-up checkpointing settings and functionality
phutchins Oct 20, 2025
d0f8db8
feat: add consensus recovery guide and diagnostic tools for IPC subne…
phutchins Oct 21, 2025
8e1d815
feat: add scripts for SSH tunnel management and Anvil connectivity te…
phutchins Oct 22, 2025
ae7cc74
feat: add debug script and documentation for relayer error diagnosis
phutchins Oct 23, 2025
dda41cc
feat: add systemd installation fix documentation and script improvements
phutchins Oct 23, 2025
1f6cedb
feat: update subnet configuration and enhance debugging capabilities
phutchins Oct 24, 2025
2c876e6
feat: enhance IPC subnet manager with binary update functionality and…
phutchins Oct 24, 2025
21f4947
feat: enhance subnet health reporting with Ethereum address conversion
phutchins Oct 29, 2025
ae3825f
feat: add gas estimation script for IPC subnet management
phutchins Oct 29, 2025
875321e
fix: add newline at the end of estimate-gas.sh for consistency
phutchins Oct 31, 2025
c5c44d4
feat: add ELK stack for IPC validator log aggregation
phutchins Nov 2, 2025
afb706d
feat: implement local deployment mode for IPC subnet manager
phutchins Nov 13, 2025
d25c6fb
feat: implement automatic subnet deployment in IPC subnet manager
phutchins Nov 13, 2025
e08fe61
fix: update subnet configuration and improve genesis creation process
phutchins Nov 14, 2025
f064635
refactor: streamline metrics fetching in dashboard script
phutchins Nov 14, 2025
cf59481
refactor: simplify chain ID retrieval in health.sh
phutchins Nov 14, 2025
760cb2b
Updates for local
phutchins Nov 19, 2025
943f4c6
refactor: update subnet configuration and improve health check functi…
phutchins Jan 12, 2026
08837e8
refactor: enhance Logstash configuration for IPC logs
phutchins Jan 12, 2026
ea7629b
refactor: calculate expected peers dynamically in dashboard script
phutchins Jan 12, 2026
e6bb384
refactor: enhance mempool metrics fetching in dashboard script
phutchins Jan 12, 2026
c2f03fe
refactor: improve finality log extraction in monitor script
phutchins Jan 12, 2026
c6c53a5
refactor: dynamically derive transaction address in set_federated_pow…
phutchins Jan 12, 2026
53ee237
refactor: update bottom-up checkpointing default behavior in IpcSettings
phutchins Jan 12, 2026
405d033
chore: update environment configuration for IPC faucet
phutchins Jan 12, 2026
6396550
refactor: enhance clear-mempool script with parameter support and dyn…
phutchins Jan 12, 2026
7d24e91
refactor: enhance ELK manager script with new delete-old-indices command
phutchins Jan 12, 2026
4b98cf4
refactor: update ELK manager script to support configurable IPC subne…
phutchins Jan 12, 2026
3a9ff71
Merge branch 'main' into subnet-management-script
phutchins Jan 14, 2026
5387e13
fix: align comment formatting in P2pConfig initialization
phutchins Jan 14, 2026
d64330c
fix: use is_none_or instead of map_or for bottomup_enabled
phutchins Jan 14, 2026
f7a9658
fix: resolve SSH connection issues in local mode for IPC manager
phutchins Jan 15, 2026
f5af77b
feat: implement comprehensive local mode fixes for IPC manager
phutchins Jan 15, 2026
0274add
docs: add detailed explanations for Chain ID and Subnet ID in IPC man…
phutchins Jan 15, 2026
0e6d322
feat: implement unique chain ID configuration for IPC subnets
phutchins Jan 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ target/
node_modules/
.DS_Store

# Environment files with credentials
.env
.env.local

# we migrated from npm to pnpm.
package-lock.json
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

All notable changes to this project will be documented in this file.

## [Unreleased]

### 🚀 Features

- *(cli)* Add configurable `listen-ip` option to P2P configuration - Allows advanced users to specify a specific IP address for binding services. Defaults to `0.0.0.0` (all interfaces) for maximum compatibility with cloud environments.

### 🐛 Bug Fixes

- *(cli)* Fix libp2p binding issue on cloud VMs (GCP, AWS, Azure) - `ipc-cli node init` now correctly uses `0.0.0.0` (or configurable `listen-ip`) for `listen_addr` and the public IP for `external_addresses`. This fixes parent finality voting and top-down message execution on cloud-deployed subnets where public IPs are not directly bound to network interfaces. Existing deployments can reinitialize or manually update `~/.ipc-node/fendermint/config/default.toml` to set `listen_addr = "/ip4/0.0.0.0/tcp/26655"` and add `external_addresses = ["/ip4/<PUBLIC_IP>/tcp/26655"]`.

## [axon-r08] - 2024-12-31

### 🚀 Features
Expand Down
Empty file added calculate_chain_id.py
Empty file.
Empty file added check_supply_source.sh
Empty file.
72 changes: 65 additions & 7 deletions docs/ipc/node-init.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,26 +126,84 @@ key:

P2P networking configuration for peer discovery and communication.

| Field | Type | Required? | Description |
| ------------- | -------- | --------- | --------------------------------------------- |
| `external-ip` | `string` | No | External IP address for peer connections |
| `ports` | `object` | No | Port configuration for different P2P services |
| `peers` | `object` | No | Peer configuration sources |
| Field | Type | Required? | Description |
| ------------- | -------- | --------- | ------------------------------------------------------------------------ |
| `external-ip` | `string` | No | External IP address for peer connections (defaults to `127.0.0.1`) |
| `listen-ip` | `string` | No | IP address to bind services to (defaults to `0.0.0.0`) |
| `ports` | `object` | No | Port configuration for different P2P services |
| `peers` | `object` | No | Peer configuration sources |

**Example:**
#### Understanding Network Configuration

The `external-ip` and `listen-ip` fields serve distinct purposes in P2P networking:

- **External IP** (`external-ip`): The public IP address that OTHER nodes use to connect to you. This is what you advertise to peers.
- **Listen IP** (`listen-ip`): Where YOUR node binds/listens for incoming connections. Defaults to `0.0.0.0` (all interfaces) for maximum compatibility.

**Cloud Deployment (GCP, AWS, Azure) - Default Configuration:**

When deploying on cloud providers, you only need to specify your VM's **public IP** for `external-ip`:

```yaml
p2p:
external-ip: "34.73.187.192" # Your VM's public IP
# listen-ip defaults to "0.0.0.0" - no need to specify
ports:
cometbft: 26656
resolver: 26655
```

This configuration will:
- Bind services to `0.0.0.0` (listens on all network interfaces) by default
- Advertise your public IP to peers for incoming connections
- Work correctly with cloud networking where public IPs are not directly bound to interfaces

**Cloud Deployment with Specific Private IP (Advanced):**

If you need to bind to a specific private IP instead of all interfaces:

```yaml
p2p:
external-ip: "34.73.187.192" # Your VM's public IP
listen-ip: "10.128.0.5" # Your VM's private IP (optional)
ports:
cometbft: 26656
resolver: 26655
```

This is useful for:
- Multi-network VMs where you want to control which interface listens
- Security policies requiring binding to specific IPs
- Advanced network configurations with multiple interfaces

**Local Development:**

For local testing, use localhost:

```yaml
p2p:
external-ip: "127.0.0.1" # Localhost (default)
ports:
cometbft: 26656
resolver: 26655
```

**With Peer Discovery:**

```yaml
p2p:
external-ip: "192.168.1.100"
ports:
cometbft: 26656
resolver: 26657
resolver: 26655
peers:
peer-files:
- "/path/to/peer1.json"
- "/path/to/peer2.json"
```

> **Note:** The node automatically handles the distinction between listen addresses (what to bind to) and external addresses (what to advertise). By default, services bind to `0.0.0.0` (all interfaces) and advertise the `external-ip` to peers. For most use cases, you only need to specify `external-ip`. The `listen-ip` option is available for advanced configurations where you need to control the specific interface for binding.

---

### cometbft-overrides
Expand Down
42 changes: 42 additions & 0 deletions faucet/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Dependencies
node_modules/
frontend/node_modules/
backend/node_modules/

# Build output (frontend will be built in Docker)
frontend/dist/

# Development files
.env
.env.local
.env.*.local

# Git
.git/
.gitignore

# IDE
.vscode/
.idea/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

# Logs
logs/
*.log
npm-debug.log*

# Documentation
README.md
docs/

# Testing
*.test.js
*.spec.js
test/
coverage/

22 changes: 22 additions & 0 deletions faucet/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# IPC Faucet Configuration
# Copy this file to .env and fill in your actual values
# NEVER commit .env to version control

# Private key for the faucet wallet (without 0x prefix or with it)
# This account will distribute funds to requesters
# Example: PRIVATE_KEY=0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE

# RPC URL for the IPC subnet
# Example: http://localhost:8545 for local development
# Example: http://node-1.test.ipc.space:8545 for test network
RPC_URL=http://localhost:8545

# Amount to send per faucet request (in native token units)
FAUCET_AMOUNT=10

# Rate limiting window in milliseconds (86400000 = 24 hours)
RATE_LIMIT_WINDOW=86400000

# Maximum number of requests per address within the rate limit window
RATE_LIMIT_MAX=3
174 changes: 174 additions & 0 deletions faucet/scripts/check-pending-txs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#!/usr/bin/env node

/**
* Check Pending Transactions for IPC Faucet
*
* Helps diagnose stuck transactions
*/

import { ethers } from 'ethers'
import dotenv from 'dotenv'
import { fileURLToPath } from 'url'
import { dirname, join } from 'path'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

// Load environment variables from parent directory
dotenv.config({ path: join(__dirname, '..', '.env') })

const RPC_URL = process.env.RPC_URL || 'http://node-1.test.ipc.space:8545'
const PRIVATE_KEY = process.env.PRIVATE_KEY

async function checkPendingTransactions() {
try {
if (!PRIVATE_KEY) {
console.error('❌ Error: PRIVATE_KEY not found in .env file')
process.exit(1)
}

console.log('\n🔍 Checking for pending transactions...\n')
console.log(`RPC: ${RPC_URL}\n`)

const provider = new ethers.JsonRpcProvider(RPC_URL)
const wallet = new ethers.Wallet(PRIVATE_KEY, provider)

console.log(`Wallet Address: ${wallet.address}\n`)

// Get current nonce from network (includes pending)
const pendingNonce = await provider.getTransactionCount(wallet.address, 'pending')

// Get confirmed nonce
const confirmedNonce = await provider.getTransactionCount(wallet.address, 'latest')

// Get balance
const balance = await provider.getBalance(wallet.address)
const balanceFIL = ethers.formatEther(balance)

console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
console.log('📊 Wallet Status')
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
console.log(`Balance: ${balanceFIL} tFIL`)
console.log(`Confirmed Nonce: ${confirmedNonce}`)
console.log(`Pending Nonce: ${pendingNonce}`)
console.log(`Stuck Transactions: ${pendingNonce - confirmedNonce}`)
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')

if (pendingNonce === confirmedNonce) {
console.log('✅ No pending transactions!\n')
return
}

console.log('⚠️ Pending transactions detected!\n')
console.log('Checking transaction details...\n')

// Try to get pending transactions
try {
// Note: Not all RPC endpoints support this method
const pendingBlock = await provider.send('eth_getBlockByNumber', ['pending', true])

if (pendingBlock && pendingBlock.transactions) {
const myPendingTxs = pendingBlock.transactions.filter(
tx => tx.from && tx.from.toLowerCase() === wallet.address.toLowerCase()
)

if (myPendingTxs.length > 0) {
console.log(`Found ${myPendingTxs.length} pending transaction(s):\n`)

myPendingTxs.forEach((tx, index) => {
console.log(`Transaction ${index + 1}:`)
console.log(` Hash: ${tx.hash}`)
console.log(` To: ${tx.to}`)
console.log(` Value: ${ethers.formatEther(tx.value)} tFIL`)
console.log(` Nonce: ${parseInt(tx.nonce)}`)
console.log(` Gas Price: ${tx.gasPrice ? ethers.formatUnits(tx.gasPrice, 'gwei') : 'N/A'} Gwei`)
console.log('')
})
}
}
} catch (error) {
console.log('ℹ️ Could not fetch pending transaction details (RPC may not support this)\n')
}

// Check recent confirmed transactions
console.log('📜 Recent confirmed transactions:\n')

try {
const latestBlock = await provider.getBlockNumber()
const fromBlock = Math.max(0, latestBlock - 20) // Check last 20 blocks

let foundTxs = 0
for (let i = latestBlock; i >= fromBlock && foundTxs < 5; i--) {
const block = await provider.getBlock(i, true)
if (block && block.transactions) {
for (const tx of block.transactions) {
if (tx.from && tx.from.toLowerCase() === wallet.address.toLowerCase()) {
const receipt = await provider.getTransactionReceipt(tx.hash)
console.log(`Block ${i}:`)
console.log(` Hash: ${tx.hash}`)
console.log(` To: ${tx.to}`)
console.log(` Value: ${ethers.formatEther(tx.value || 0)} tFIL`)
console.log(` Nonce: ${parseInt(tx.nonce)}`)
console.log(` Status: ${receipt.status === 1 ? '✅ Success' : '❌ Failed'}`)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null reference when accessing transaction receipt status

Low Severity

The getTransactionReceipt call can return null in ethers.js v6, but the code accesses receipt.status directly without a null check. If the receipt is unavailable (due to timing issues or RPC inconsistencies), this will throw a TypeError: Cannot read properties of null (reading 'status'). The error is caught by the outer try-catch, but results in a misleading "Could not fetch recent transactions" message instead of properly handling the null receipt case.

Fix in Cursor Fix in Web

console.log('')
foundTxs++
if (foundTxs >= 5) break
}
}
}
}

if (foundTxs === 0) {
console.log(' No recent transactions found\n')
}
} catch (error) {
console.log(' Could not fetch recent transactions\n')
}

// Provide solutions
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
console.log('💡 Solutions to Clear Stuck Transactions')
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')

console.log('Option 1: Wait for transactions to be mined')
console.log(' - Transactions may just need more time\n')

console.log('Option 2: Speed up with higher gas (if RPC supports)')
console.log(' - Use node scripts/speed-up-tx.js\n')

console.log('Option 3: Cancel stuck transactions')
console.log(' - Send 0 value tx to yourself with same nonce')
console.log(' - Use node scripts/cancel-tx.js <nonce>\n')

console.log('Option 4: Check gas price settings')
console.log(' - Ensure faucet is using adequate gas price')
console.log(' - Check network congestion\n')

// Get network gas info
try {
const feeData = await provider.getFeeData()
console.log('Current Network Gas Prices:')
if (feeData.gasPrice) {
console.log(` Gas Price: ${ethers.formatUnits(feeData.gasPrice, 'gwei')} Gwei`)
}
if (feeData.maxFeePerGas) {
console.log(` Max Fee: ${ethers.formatUnits(feeData.maxFeePerGas, 'gwei')} Gwei`)
}
if (feeData.maxPriorityFeePerGas) {
console.log(` Max Priority Fee: ${ethers.formatUnits(feeData.maxPriorityFeePerGas, 'gwei')} Gwei`)
}
console.log('')
} catch (error) {
console.log(' Could not fetch gas prices\n')
}

} catch (error) {
console.error('❌ Error:', error.message)
process.exit(1)
}
}

checkPendingTransactions()



Loading
Loading