myco-bonding-curve/dashboard/tabs/crdt_flow.py

113 lines
4.2 KiB
Python

"""CRDT Flow tab — multi-peer network simulation."""
import streamlit as st
from src.crdt.bridge import Network, NetworkConfig, EventType
from src.crdt.labor_crdt import AttestationEntry, submit_attestation
from src.crdt.intent_matching import Intent, add_intent
from src.crdt.dca_schedule import create_dca_schedule, DCAScheduleRegistry
from dashboard.charts import fig_crdt_divergence
def render():
st.header("CRDT Network Simulation")
col1, col2, col3, col4 = st.columns(4)
with col1:
n_peers = st.slider("Peers", 2, 10, 5)
with col2:
partition_prob = st.slider("Partition probability", 0.0, 0.5, 0.15, 0.05)
with col3:
reconnect_delay = st.slider("Reconnect delay", 1.0, 20.0, 5.0, 1.0)
with col4:
sim_steps = st.slider("Steps", 10, 100, 40)
if st.button("Simulate Network", key="crdt_run"):
peer_ids = [f"p{i+1}" for i in range(n_peers)]
config = NetworkConfig(
partition_probability=partition_prob,
reconnect_delay=reconnect_delay,
seed=42,
)
net = Network.create(peer_ids, config)
# Inject mutations across peers
for i, pid in enumerate(peer_ids):
if i % 3 == 0:
entry = AttestationEntry(
entry_id=f"e{i}", contribution_type="code",
units=5.0, timestamp=1.0, attester="admin",
)
net.mutate_peer(pid, lambda s, e=entry, c=f"dev_{i}": _with_labor(s, c, e))
elif i % 3 == 1:
intent = Intent(
intent_id=f"i{i}", maker=f"user_{i}",
sell_token="USDC", sell_amount=100.0,
buy_token="MYCO", min_buy_amount=80.0,
valid_until=999.0,
)
net.mutate_peer(pid, lambda s, it=intent: _with_intent(s, it))
else:
schedule = create_dca_schedule(
schedule_id=f"s{i}", maker=f"maker_{i}",
total_amount=1000.0, n_chunks=5,
start_time=0.0, interval=1.0,
)
net.mutate_peer(pid, lambda s, sc=schedule: _with_dca(s, sc))
with st.spinner("Simulating network..."):
sim_result = net.simulate(steps=sim_steps)
sim_result["convergence_time"] = net.convergence_time()
st.session_state["crdt_result"] = sim_result
if "crdt_result" in st.session_state:
result = st.session_state["crdt_result"]
# Metrics
m1, m2, m3, m4 = st.columns(4)
m1.metric("Final Divergence", result["divergence"][-1])
m2.metric("Total Merges", result["merge_count"][-1])
n_partitions = sum(1 for e in result["events"] if e.event_type == EventType.PARTITION)
m3.metric("Partition Events", n_partitions)
ct = result.get("convergence_time")
m4.metric("Convergence Time", f"{ct:.1f}" if ct is not None else "N/A")
st.plotly_chart(fig_crdt_divergence(result), use_container_width=True)
# Per-peer state table
st.subheader("Per-Peer State Signatures (final)")
peer_sigs = result["peer_signatures"]
table_data = []
for pid, sigs in peer_sigs.items():
final = sigs[-1] if sigs else ()
table_data.append({
"Peer": pid,
"Labor Logs": final[0] if len(final) > 0 else 0,
"Labor Entries": final[1] if len(final) > 1 else 0,
"Intents": final[2] if len(final) > 2 else 0,
"Flow Peers": final[3] if len(final) > 3 else 0,
"Trust Peers": final[4] if len(final) > 4 else 0,
"Credit Lines": final[5] if len(final) > 5 else 0,
"DCA Schedules": final[6] if len(final) > 6 else 0,
})
st.dataframe(table_data, use_container_width=True)
def _with_labor(state, contributor, entry):
state.labor = submit_attestation(state.labor, contributor, entry)
return state
def _with_intent(state, intent):
state.intents = add_intent(state.intents, intent)
return state
def _with_dca(state, schedule):
state.dca = DCAScheduleRegistry(
schedules={**state.dca.schedules, schedule.schedule_id: schedule}
)
return state