Skip to content
46 changes: 41 additions & 5 deletions cl-hive.py
Original file line number Diff line number Diff line change
Expand Up @@ -1701,6 +1701,12 @@ def on_custommsg(peer_id: str, payload: str, plugin: Plugin, **kwargs):
)
return {"result": "continue"}

# Update last_seen for any valid Hive message from a member (Issue #59)
if database:
member = database.get_member(peer_id)
if member:
database.update_member(peer_id, last_seen=int(time.time()))

# Dispatch based on message type
try:
if msg_type == HiveMessageType.HELLO:
Expand Down Expand Up @@ -2056,6 +2062,21 @@ def handle_attest(peer_id: str, payload: Dict, plugin: Plugin) -> Dict:
manifest_features = manifest_data.get("features", [])
database.save_peer_capabilities(peer_id, manifest_features)

# Capture addresses from listpeers for the new member (Issue #60)
if safe_plugin:
try:
peers_info = safe_plugin.rpc.listpeers(id=peer_id)
if peers_info and peers_info.get('peers'):
addrs = peers_info['peers'][0].get('netaddr', [])
if addrs:
database.update_member(peer_id, addresses=json.dumps(addrs))
except Exception:
pass # Non-critical, will be captured on next gossip or connect

# Initialize presence tracking so uptime_pct starts accumulating (Issue #59)
# The peer is connected (they just completed the handshake), so mark online
database.update_presence(peer_id, is_online=True, now_ts=int(time.time()), window_seconds=30 * 86400)

handshake_mgr.clear_challenge(peer_id)

# Set hive fee policy for new member (0 fee to all hive members)
Expand Down Expand Up @@ -2790,14 +2811,20 @@ def on_peer_connected(**kwargs):
database.update_member(peer_id, last_seen=now)
database.update_presence(peer_id, is_online=True, now_ts=now, window_seconds=30 * 86400)

# Track VPN connection status
# Track VPN connection status + populate missing addresses (Issue #60)
peer_address = None
if vpn_transport and safe_plugin:
if safe_plugin:
try:
peers = safe_plugin.rpc.listpeers(id=peer_id)
if peers and peers.get('peers') and peers['peers'][0].get('netaddr'):
peer_address = peers['peers'][0]['netaddr'][0]
vpn_transport.on_peer_connected(peer_id, peer_address)
if peers and peers.get('peers'):
netaddr = peers['peers'][0].get('netaddr', [])
if netaddr:
peer_address = netaddr[0]
if vpn_transport:
vpn_transport.on_peer_connected(peer_id, peer_address)
# Populate addresses if missing
if not member.get('addresses'):
database.update_member(peer_id, addresses=json.dumps(netaddr))
except Exception:
pass

Expand Down Expand Up @@ -8119,6 +8146,15 @@ def membership_maintenance_loop():
if updated > 0 and safe_plugin:
safe_plugin.log(f"Synced uptime for {updated} member(s)", level='debug')

# Sync contribution ratios from ledger to hive_members (Issue #59)
if membership_mgr:
members_list = database.get_all_members()
for m in members_list:
pid = m.get("peer_id")
if pid:
ratio = membership_mgr.calculate_contribution_ratio(pid)
database.update_member(pid, contribution_ratio=ratio)

# Phase 9: Planner and governance data pruning
database.cleanup_expired_actions() # Mark expired as 'expired'
database.prune_planner_logs(older_than_days=30)
Expand Down
1 change: 1 addition & 0 deletions docs/THE_HIVE_ARTICLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
**Turn your solo Lightning node into part of a coordinated fleet.**

---
![Image](https://r2.primal.net/cache/9/97/87/9978775eca7fbe1f5f78548d888580613a8080ec826080580024d98526fdd4e6.png)

## The Problem with Running a Lightning Node Alone

Expand Down
18 changes: 18 additions & 0 deletions modules/rpc_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,18 @@ def status(ctx: HiveContext) -> Dict[str, Any]:
if ctx.our_pubkey:
our_member = ctx.database.get_member(ctx.our_pubkey)
if our_member:
uptime_raw = our_member.get("uptime_pct", 0.0)
contribution_ratio = our_member.get("contribution_ratio", 0.0)
# Enrich with live contribution ratio if available (Issue #59)
if ctx.membership_mgr:
contribution_ratio = ctx.membership_mgr.calculate_contribution_ratio(ctx.our_pubkey)
uptime_raw = round(uptime_raw * 100, 2)
our_membership = {
"tier": our_member.get("tier"),
"joined_at": our_member.get("joined_at"),
"pubkey": ctx.our_pubkey,
"uptime_pct": uptime_raw,
"contribution_ratio": contribution_ratio,
}

return {
Expand Down Expand Up @@ -312,6 +320,16 @@ def members(ctx: HiveContext) -> Dict[str, Any]:
return {"error": "Hive not initialized"}

all_members = ctx.database.get_all_members()

# Enrich with live contribution ratio from ledger (Issue #59)
if ctx.membership_mgr:
for m in all_members:
peer_id = m.get("peer_id")
if peer_id:
m["contribution_ratio"] = ctx.membership_mgr.calculate_contribution_ratio(peer_id)
# Format uptime as percentage (stored as 0.0-1.0 decimal)
m["uptime_pct"] = round(m.get("uptime_pct", 0.0) * 100, 2)

return {
"count": len(all_members),
"members": all_members,
Expand Down
Loading
Loading