DEV Community

Cover image for Building an Anchor Output Fee Bumping Service - Part 3: Setup & Implementation
Susan Githaiga
Susan Githaiga

Posted on

Building an Anchor Output Fee Bumping Service - Part 3: Setup & Implementation

Part 3 of my anchor outputs learning series - getting the service running and seeing it in action


Quick Recap

Part 1: The problem - commitment transactions with outdated fees get stuck

Part 2: The solution - anchor outputs let you boost fees later using CPFP

Part 3 (this one): Actually building a service that does this


What We're Building

A service that:

  1. Monitors the Bitcoin mempool for commitment transactions
  2. Detects anchor outputs (330 sat outputs)
  3. Calculates CPFP fee requirements
  4. Provides a REST API to estimate and request fee bumps

Important: We're using Bitcoin regtest network for this.

GitHub Repository: lightning-anchor-fee-outputs


System Requirements

Before you start:

  • Node.js 18 or higher
  • Docker Desktop (for Bitcoin Core and LND)

Operating Systems: Works on macOS, Linux, and Windows (with WSL2)


Setup Instructions

Step 1: Clone and Install

git clone https://github.com/SusanGithaigaN/lightning-anchor-fee-outputs.git
cd lightning-anchor-fee-service
npm install
Enter fullscreen mode Exit fullscreen mode

Step 2: Start Docker Services

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

This starts:

  • Bitcoin Core (regtest network)
  • LND (Lightning node)
  • PostgreSQL
  • Redis

Lightning Network Anchor Outputs

Step 3: Setup Bitcoin Regtest

i) Create Bitcoin wallet

docker compose exec bitcoin bitcoin-cli -regtest -rpcuser=bitcoinrpc -rpcpassword=changeme createwallet "mywallet"
Enter fullscreen mode Exit fullscreen mode

Create lightning wallet

ii) Mine 101 blocks

docker compose exec bitcoin bitcoin-cli -regtest -rpcuser=bitcoinrpc -rpcpassword=changeme -generate 101
Enter fullscreen mode Exit fullscreen mode

Mine 101 blocks

If you already created the LND wallet before (you'll get this error), just verify it's working:

docker compose exec lnd lncli --network=regtest getinfo
Enter fullscreen mode Exit fullscreen mode

Step 4: Setup LND Wallet

docker compose exec lnd lncli --network=regtest create
Enter fullscreen mode Exit fullscreen mode

Follow the prompts:

  1. Enter a password
  2. Select n to create a new seed
  3. Write down the 24 words (optional for regtest)
  4. Press Enter for cipher passphrase

Step 5: Start the Service

npm run dev
Enter fullscreen mode Exit fullscreen mode

You should see:

Server running on port 3000
Connected to Bitcoin Core
Enter fullscreen mode Exit fullscreen mode

Testing the Service

Test 1: Health Check

curl http://localhost:3000/health
Enter fullscreen mode Exit fullscreen mode

Expected: {"status":"ok"}

Test 2: Bitcoin Connection

curl http://localhost:3000/api/v1/bitcoin/info
Enter fullscreen mode Exit fullscreen mode

You should see: Chain info showing regtest network with 101 blocks.

Test 3: LND Connection

curl http://localhost:3000/api/v1/lightning/info
Enter fullscreen mode Exit fullscreen mode

You should see: Node info with anchor outputs feature enabled (check for "anchors-zero-fee-htlc-tx").

Node info with anchor outputs

Test 4: Start Monitoring

curl -X POST http://localhost:3000/api/v1/monitor/start \
  -H "Content-Type: application/json" \
  -d '{"intervalMs": 3000}'
Enter fullscreen mode Exit fullscreen mode

Expected: {"success":true,"message":"Monitoring started","intervalMs":3000}

Monitoring

Test 5: Create Test Transaction

# Get a new address
ADDR=$(docker compose exec bitcoin bitcoin-cli -regtest -rpcuser=bitcoinrpc -rpcpassword=changeme getnewaddress)

# Send 330 sats (creates anchor-like output)
TXID=$(docker compose exec bitcoin bitcoin-cli -regtest -rpcuser=bitcoinrpc -rpcpassword=changeme sendtoaddress $ADDR 0.00000330)

echo "Transaction ID: $TXID"
Enter fullscreen mode Exit fullscreen mode

Create Test Transaction

Test 6: Check Monitor Status

Wait 5 seconds, then:

curl http://localhost:3000/api/v1/monitor/status
Enter fullscreen mode Exit fullscreen mode

You should see: Your transaction being tracked with detected anchor output.

Example response:

{"success":true,"data":{"isMonitoring":true,"trackedCount":1,"transactions":[{"txid":"b3f593509ba7efa9eabeedd159bcc158980917f4804f6a1be8163708c5542c5b","hex":"02000000000101c1de4dab5c406faad339b4e7ed3998a2c9286ee8d7e08eecc4cdd56cb1f98d980000000000fdffffff0243f8029500000000160014ba6345572da5d28ea9830dfc0476826c4bb10c8b4a010000000000001600142935034b935612bc85089f89fca385ba9a78791e0247304402205abef31db372537d0f3ab2f4b5240dbdc6dd7367fe64384e1e58669f4a1a686e022049e7e8d418d18b8328070dad0251b6aefc6b0023b6ed914f34797a40111a9df5012103bb47542f3fe2dd313e221de0620dd733f0766e00d52eb90e222c06aa090aec9e30010000","fee":0,"size":141,"feeRate":0,"anchorOutputs":[{"vout":1,"value":330,"scriptPubKey":"00142935034b935612bc85089f89fca385ba9a78791e"}]}]}}
Enter fullscreen mode Exit fullscreen mode

Test 7: Estimate Fee Bump

curl -X POST http://localhost:3000/api/v1/feebump/estimate \
  -H "Content-Type: application/json" \
  -d "{\"txid\": \"$TXID\", \"targetFeeRate\": 10}"
Enter fullscreen mode Exit fullscreen mode

You should see: Fee calculations showing that 10 sats/vbyte is NOT feasible with just the 330 sat anchor alone. This proves the limitation.

Expected result: "feasible": false

This means you'd need to add ~2,180 sats from your own wallet to bump to 10 sats/vbyte.

Example result

susan@susan-githaiga:~/development/projects/lightning-anchor-fee-outputs$ curl -X POST http://localhost:3000/api/v1/feebump/estimate \uts$ curl -X POST http://localhost:3000/api/v1/feebump/estimate \
  -H "Content-Type: application/json" \
  -d "{\"txid\": \"$TXID\", \"targetFeeRate\": 10}"
{"success":true,"data":{"txid":"b3f593509ba7efa9eabeedd159bcc158980917f4804f6a1be8163708c5542c5b","parentSize":141,"parentFee":0,"parentFeeRate":0,"childSize":110,"totalSize":251,"targetFeeRate":10,"totalFeeNeeded":2510,"childFeeNeeded":2510,"anchorValue":330,"feasible":false}}
Enter fullscreen mode Exit fullscreen mode

Test with a lower fee rate (should be feasible):

curl -X POST http://localhost:3000/api/v1/feebump/estimate \
  -H "Content-Type: application/json" \
  -d "{\"txid\": \"$TXID\", \"targetFeeRate\": 1}"
Enter fullscreen mode Exit fullscreen mode

Result

susan@susan-githaiga:~/development/projects/lightning-anchor-fee-outputs$ # Test with 1 sat/vbyte (should be feasible)ts$ # Test with 1 sat/vbyte (should be feasible)
curl -X POST http://localhost:3000/api/v1/feebump/estimate \
  -H "Content-Type: application/json" \
  -d "{\"txid\": \"$TXID\", \"targetFeeRate\": 1}"
{"success":true,"data":{"txid":"b3f593509ba7efa9eabeedd159bcc158980917f4804f6a1be8163708c5542c5b","parentSize":141,"parentFee":0,"parentFeeRate":0,"childSize":110,"totalSize":251,"targetFeeRate":1,"totalFeeNeeded":251,"childFeeNeeded":251,"anchorValue":330,"feasible":true}}
Enter fullscreen mode Exit fullscreen mode

This should show "feasible": true because 251 vbytes × 1 sat/vbyte = only 251 sats needed


Understanding the Results

When you check the monitor status, look for:

trackedCount: 1 - Service detected your transaction

value: 330 - Confirmed it's an anchor output

anchorOutputs array - Shows which outputs are anchors

When you estimate fees:

feasible: true - Can bump with just the anchor

feasible: false - Need additional inputs from wallet

Key insight: 330 sats can only bump to about 10-20 sats/vbyte maximum.


Troubleshooting

Port conflicts?

sudo systemctl stop redis-server postgresql
docker compose restart
Enter fullscreen mode Exit fullscreen mode

Services not starting?

docker compose logs bitcoin
docker compose logs lnd
Enter fullscreen mode Exit fullscreen mode

Monitor not detecting transactions?

Make sure the transaction is in mempool (not confirmed yet). Don't mine blocks immediately after sending!


What We Built

Here's what the service does:

1. Bitcoin Integration

  • Connects to Bitcoin Core via RPC
  • Monitors mempool every 3-10 seconds
  • Fetches transaction details

2. Anchor Detection

  • Scans all transaction outputs
  • Identifies 330 satoshi outputs
  • Tracks them as potential anchors

3. Fee Estimation

  • Calculates parent transaction size
  • Estimates child transaction size (~110 vbytes)
  • Computes package fee rate
  • Determines if anchor alone is sufficient

4. REST API

  • Start/stop monitoring
  • Check status and tracked transactions
  • Estimate fee bump requirements
  • Bitcoin and Lightning info endpoints

Key Learnings

1. The 330 Sat Limitation is Real

Anchor outputs can only bump fees to ~10-20 sats/vbyte. For higher rates, you need additional UTXOs from your wallet.

Example:

  • Target: 50 sats/vbyte
  • Parent + Child: 330 vbytes
  • Total fee needed: 16,500 sats
  • Anchor provides: 330 sats
  • Need to add: 16,170 sats from wallet

2. Regtest Makes Testing Easy

  • Free Bitcoin (just mine blocks)
  • Instant blocks (no waiting)
  • No risk of losing real money
  • Perfect for learning and development

3. Monitoring is the Easy Part

Detecting 330 sat outputs in the mempool is straightforward. The hard part comes next: signing and broadcasting CPFP transactions.

4. Production Needs Reserve Funds

Real implementations maintain a pool of UTXOs specifically for fee bumping. You can't rely on the anchor alone.

5. Docker Simplifies Setup

Bitcoin Core and LND in Docker means:

  • No system pollution
  • Easy cleanup
  • Consistent environment
  • Works everywhere

What's Next

Current Status: ✅ Monitoring and estimation work

Still Missing: ❌ Actual transaction signing and broadcasting

Part 4 will cover:

  • Wallet integration for additional inputs
  • Building and signing CPFP transactions
  • Broadcasting to Bitcoin mainnet network
  • Testing with real Lightning channels
  • Accepting Lightning payments for the service

Future improvements:

  • Automatic fee bumping (no manual trigger)
  • Multiple channel support
  • Reserve fund management
  • Web dashboard
  • Mainnet deployment

Resources


If you have any questions or suggestions, drop them in the comments

Top comments (0)