Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 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
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
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/

8 changes: 8 additions & 0 deletions faucet/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
PRIVATE_KEY=0x5eda872ee2da7bc9d7e0af4507f7d5060aed54d43fd1a72e1283622400c7cb85
# private key for generated address 0x3c34b12c13988FFf7288e0366F108821ebE162Fd
#PRIVATE_KEY=0x564e8313a1e480509ee863d2a4cae3fad93bdf9847aaeffd661e711a25fa7fed
# for address ending in fba
RPC_URL=http://node-1.test.ipc.space:8545
FAUCET_AMOUNT=10
RATE_LIMIT_WINDOW=86400000
RATE_LIMIT_MAX=3
Copy link

Choose a reason for hiding this comment

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

Bug: Sensitive Credentials Exposed in Repository

A .env file containing actual private keys has been committed to the repository. The file includes PRIVATE_KEY=0x5eda872ee2da7bc9d7e0af4507f7d5060aed54d43fd1a72e1283622400c7cb85 and a commented alternative key. Environment files with credentials should never be committed to version control - they should be in .gitignore and users should create them from a template (like .env.example). This exposes private keys that could control real accounts with funds.

Fix in Cursor Fix in Web

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'}`)
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()



13 changes: 13 additions & 0 deletions faucet/scripts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "ipc-faucet-scripts",
"version": "1.0.0",
"type": "module",
"private": true,
"dependencies": {
"ethers": "^6.11.1",
"dotenv": "^16.4.5"
}
}



Loading