diff --git a/docker/dev.sh b/docker/dev.sh index e1d55b2..14e5571 100755 --- a/docker/dev.sh +++ b/docker/dev.sh @@ -86,18 +86,165 @@ is_lnd4_ready() { docker exec lnbits-lnd-4-1 lncli --network=regtest --rpcserver=lnd-4:10009 getinfo &>/dev/null 2>&1 } +lnd4_has_channels() { + local channel_count=$(docker exec lnbits-lnd-4-1 lncli --network=regtest --rpcserver=lnd-4:10009 listchannels 2>/dev/null | grep -c '"chan_id"' || echo "0") + [[ "$channel_count" -gt 0 ]] +} + +lnd4_has_active_channels() { + docker exec lnbits-lnd-4-1 lncli --network=regtest --rpcserver=lnd-4:10009 listchannels 2>/dev/null | grep -q '"active": true' +} + is_lightning_pub_ready() { docker logs lamassu-lightning-pub 2>&1 | grep -q "LightningPub listening" } get_lnd4_balance() { - docker exec lnbits-lnd-4-1 lncli --network=regtest walletbalance 2>/dev/null | grep -oP '"total_balance":\s*"\K[0-9]+' || echo "0" + docker exec lnbits-lnd-4-1 lncli --network=regtest --rpcserver=lnd-4:10009 walletbalance 2>/dev/null | grep -oP '"total_balance":\s*"\K[0-9]+' || echo "0" +} + +get_lnd4_channel_balance() { + docker exec lnbits-lnd-4-1 lncli --network=regtest --rpcserver=lnd-4:10009 channelbalance 2>/dev/null | grep -oP '"local_balance"[^}]*"sat":\s*"\K[0-9]+' || echo "0" } ############################################################################# # Regtest Management ############################################################################# +is_lnd1_ready() { + # Check if lnd-1 is fully ready (can make RPC calls) + docker exec lnbits-lnd-1-1 lncli --network=regtest --rpcserver=lnd-1:10009 getinfo &>/dev/null 2>&1 +} + +wait_for_lnd1() { + log "Waiting for lnd-1 to be ready..." + local attempts=0 + while ! is_lnd1_ready && [[ $attempts -lt 30 ]]; do + sleep 2 + attempts=$((attempts + 1)) + done + is_lnd1_ready +} + +ensure_lnd4_channel() { + # Ensure lnd-4 has a channel so it can create invoices + # Also ensure lnd-3 has a channel so it can pay invoices (for funding) + # Opens channels from lnd-1 (hub) to both lnd-3 and lnd-4 + + if lnd4_has_active_channels; then + log "lnd-4 has active channels" + return 0 + fi + + log "Setting up Lightning channels for ATM..." + + # Wait for lnd-1 to be ready (it's the funding hub) + if ! wait_for_lnd1; then + error "lnd-1 failed to start" + return 1 + fi + success "lnd-1 is ready" + + # Give lnd-1 a moment to fully initialize (getinfo succeeds before all subsystems ready) + sleep 5 + + # Check if lnd-1 has funds, if not fund it + local lnd1_balance=$(docker exec lnbits-lnd-1-1 lncli --network=regtest --rpcserver=lnd-1:10009 walletbalance 2>/dev/null | grep -oP '"confirmed_balance":\s*"\K[0-9]+' | head -1 || echo "0") + lnd1_balance="${lnd1_balance:-0}" + if [[ "$lnd1_balance" -lt 100000000 ]]; then + log "Funding lnd-1 with mining rewards..." + local lnd1_addr=$(docker exec lnbits-lnd-1-1 lncli --network=regtest --rpcserver=lnd-1:10009 newaddress p2wkh 2>/dev/null | grep -oP '"address":\s*"\K[^"]+') + docker exec lnbits-bitcoind-1 bitcoin-cli -regtest generatetoaddress 110 "$lnd1_addr" &>/dev/null + sleep 3 + success "lnd-1 funded" + fi + + # Get pubkeys + local lnd4_pubkey=$(docker exec lnbits-lnd-4-1 lncli --network=regtest --rpcserver=lnd-4:10009 getinfo 2>/dev/null | grep -oP '"identity_pubkey":\s*"\K[^"]+') + local lnd3_pubkey=$(docker exec lnbits-lnd-3-1 lncli --network=regtest --rpcserver=lnd-3:10009 getinfo 2>/dev/null | grep -oP '"identity_pubkey":\s*"\K[^"]+') + + if [[ -z "$lnd4_pubkey" ]] || [[ -z "$lnd3_pubkey" ]]; then + error "Could not get LND pubkeys" + return 1 + fi + + # Connect lnd-1 to lnd-3 and lnd-4 + log "Connecting nodes..." + docker exec lnbits-lnd-1-1 lncli --network=regtest --rpcserver=lnd-1:10009 \ + connect "${lnd3_pubkey}@lnd-3:9735" &>/dev/null || true + docker exec lnbits-lnd-1-1 lncli --network=regtest --rpcserver=lnd-1:10009 \ + connect "${lnd4_pubkey}@lnd-4:9735" &>/dev/null || true + + # Retry loop for opening channels (server may still be initializing) + local result3="" result4="" attempts=0 + while [[ $attempts -lt 5 ]]; do + # Open channel to lnd-3: 10M sats, push 5M so lnd-3 has sending capacity + if [[ -z "$result3" ]] || echo "$result3" | grep -q "still in the process of starting"; then + result3=$(docker exec lnbits-lnd-1-1 lncli --network=regtest --rpcserver=lnd-1:10009 \ + openchannel --node_key="$lnd3_pubkey" --local_amt=10000000 --push_amt=5000000 2>&1) + fi + + # Open channel to lnd-4: 10M sats, push 5M so lnd-4 has receiving capacity + if [[ -z "$result4" ]] || echo "$result4" | grep -q "still in the process of starting"; then + result4=$(docker exec lnbits-lnd-1-1 lncli --network=regtest --rpcserver=lnd-1:10009 \ + openchannel --node_key="$lnd4_pubkey" --local_amt=10000000 --push_amt=5000000 2>&1) + fi + + # Check if both succeeded + if echo "$result3" | grep -q "funding_txid" && echo "$result4" | grep -q "funding_txid"; then + break + fi + + attempts=$((attempts + 1)) + if [[ $attempts -lt 5 ]]; then + log "Waiting for LND to be fully ready... (attempt $attempts/5)" + sleep 5 + fi + done + + log "Opening channel lnd-1 -> lnd-3..." + log "Opening channel lnd-1 -> lnd-4..." + + local channels_opened=false + if echo "$result3" | grep -q "funding_txid" || echo "$result4" | grep -q "funding_txid"; then + channels_opened=true + fi + + if [[ "$channels_opened" == "true" ]]; then + log "Mining blocks to confirm channels..." + + # Mine 10 blocks to confirm channels and allow graph propagation + local addr=$(docker exec lnbits-bitcoind-1 bitcoin-cli -regtest getnewaddress 2>/dev/null) + docker exec lnbits-bitcoind-1 bitcoin-cli -regtest generatetoaddress 10 "$addr" &>/dev/null + + # Wait for channels to become active + local attempts=0 + while ! lnd4_has_active_channels && [[ $attempts -lt 20 ]]; do + sleep 2 + attempts=$((attempts + 1)) + done + + if lnd4_has_active_channels; then + # Wait a bit more for graph propagation + log "Waiting for network graph to sync..." + sleep 10 + # Mine a few more blocks to trigger announcements + docker exec lnbits-bitcoind-1 bitcoin-cli -regtest generatetoaddress 6 "$addr" &>/dev/null + sleep 5 + success "Channels active - lnd-3 and lnd-4 ready" + return 0 + else + warn "Channels opened but not yet active, may need more time" + return 0 + fi + else + error "Failed to open channels" + echo "lnd-3 result: $result3" + echo "lnd-4 result: $result4" + return 1 + fi +} + start_regtest() { if is_regtest_running; then log "Regtest network already running" @@ -128,6 +275,9 @@ start_regtest() { error "lnd-4 failed to start" return 1 fi + + # Ensure lnd-4 has a channel for invoices + ensure_lnd4_channel || warn "Could not setup lnd-4 channel (funding may fail)" } stop_regtest() { @@ -336,8 +486,10 @@ show_status() { echo " Withdraw API: http://${local_ip}:1777" echo "" + local lnd4_channel_balance=$(get_lnd4_channel_balance) echo -e "${CYAN}lnd-4 (Lightning.Pub backend)${NC}" - echo " Balance: ${lnd4_balance} sats" + echo " Channel Balance: ${lnd4_channel_balance} sats" + echo " Wallet Balance: ${lnd4_balance} sats" echo "" echo -e "${CYAN}ATM App${NC}" @@ -413,6 +565,9 @@ cmd_up() { echo " Start with: regtest-start" echo " Or use: ./dev.sh up --standalone" exit 1 + elif [[ "$standalone" != "true" ]]; then + # Regtest already running, but ensure lnd-4 has channels + ensure_lnd4_channel || warn "Could not setup lnd-4 channel (funding may fail)" fi # 2. Build from worktree if specified