← 목록
기타 2026-07-04 6KB 읽기 7분

스테이킹 다운타임 자동 감지 (슬래싱 3차 — 트리거 자동화)

개요

2차에서 슬래싱 집행(POST /api/slashing/enforce)을 붙였으나 수동 트리거였다. 3차는 하트비트 타임아웃을 주기적으로 감지해 자동 집행하는 외부 감지기를 붙였다. 라이브 :9975 한선씨 서버는 단일스레드 VM이라 내부 타이머가 없다 → 외부 감지기가 enforce 를 호출하는 구조가 자연스럽다. 순수 한선씨. 데몬/LaunchAgent 미생성(정책) — 상시 운영은 런북 텍스트로만 제시하고 사용자 승인 대상으로 남겼다.

무엇을 했는지

  • 감지기 자동감지.한선 (신규): 1회 실행 시
  • 로컬 stakes.dat 를 직접 스캔(엔진 함수 재사용 — 중복 로직 없음)
  • 고유 밸리데이터별: 기준선 = 마지막하트비트(없으면 밸리데이터등록시각),
  • 에폭수 = floor((now − 기준선)/86400), 목표BP = min(에폭수×10, 500), 새BP = 목표BP − 누적슬래시BP
  • 조치필요 = (새BP>0 그리고 활성스테이크>0) 인 밸리데이터가 있을 때만
  • POST /api/slashing/enforce1회 위임 호출(체계+curl -m 5, now 명시)
  • 집행(차감·멱등)은 서버가 소유. 감지기는 순수 감지+위임.
  • 감사 로그: /Users/ef/crowny-data/staking/slashwatch.log append.
  • 멱등 트리거: 이미 반영된 다운타임은 새BP=0 → actionable=0 → enforce 무호출.
  • 재실행해도 slash·enforce 이벤트가 늘지 않는다(서버 멱등 + 감지 게이트 이중).
    • 모드: 한선씨는 CLI argv 미지원 → 환경변수 SLASHWATCH_INTERVAL 로 선택.
    미설정=1회(기본), 양의 정수=해당 초 loop(동안 + 체계("sleep N")). 감지기는 데몬 아님.
    • now 소스: 현재시간() 내장(= date +%s 동일, 서브프로세스 0) — 검출/집행 now 일치.

    검증 (라이브 :9975, curl, 수치)

    기준선: slash_events=0, total_staked=0. V1 정상(하트비트 now), V2 2에폭전 하트비트.
    • 컴파일: 자동감지.한선 → toau 407,652B, exit 0. 엔진 import 28,101B.
    • ① 정상+② 다운 (감지 #1): 감지기 출력 validators:2, downtime:1, actionable:1, enforce_called:1,
    enforce_resp slashed:1, total_deducted:40.
  • V1(정상): active_stake 20000 불변(무집행) ✅
  • V2(2에폭): active_stake 20000→19960, 슬래시 bp:20, epochs:2, deducted:40(20000×20/10000=40 일치) ✅
  • 서버 slash_events 0→1, total_deducted 40
  • ③ 재실행 멱등 (감지 #2,#3): downtime:1, actionable:0, enforce_called:0 (2회 연속).
  • slash_events 1 유지, total_deducted 40 유지, V2 active 19960 불변
    • 원상복구: 검증 전 스냅샷(stakes.dat 4줄) 복원 → slash_events 0, total_staked 0,
    validators [], TESTWATCH 잔재 0건. slashwatch.log(테스트분) 제거. 라이브 무흔적 ✅

    사용법

    bashexport CROWNY_STD=/Users/ef/Downloads/CrownyTVM/std
    cd /Users/ef/crowny-staking
    /Users/ef/CrownyOS/crownyc/hanseonc_high 자동감지.한선 > /tmp/자동감지.toau
    /Users/ef/CrownyOS/crownyc/crownyc run /tmp/자동감지.toau                 # 1회(기본)
    SLASHWATCH_INTERVAL=300 /Users/ef/CrownyOS/crownyc/crownyc run /tmp/자동감지.toau  # loop 300초
    

    관련 파일

    • /Users/ef/crowny-staking/자동감지.한선 — 감지기(신규)
    • /Users/ef/crowny-staking/자동감지.rpn.한선 — RPN 부본(high2rpn.sh, 222줄)
    • /Users/ef/crowny-staking/자동감지_운영.md — 운영 런북(LaunchAgent plist 예시 텍스트만)
    • /Users/ef/crowny-staking/libs/스테이킹엔진.한선 — 재사용 엔진(무수정)
    • /Users/ef/crowny-staking/스테이킹서버.한선 — enforce/heartbeat 라우트(무수정)

    VM 함정 준수

    • 맵있나() != 1 비교(부재 -1), 배열 append-only, 인라인 누적 금지(임시변수),
    내림나눗셈 자연반올림 보정, 시그널등록(13,1).
    • 환경변수 미설정 시 -1(숫자, 글자수 0) / 설정 시 문자열 → 글자수>0 로 모드 판별(신규 함정).
    • 체계() 는 stdout 반환(curl 응답·date 캡처). 감지 loop 는 데몬 아님(-m 5 후 종료).

    운영 등록 런북 요약 (승인 후 사용자 실행)

    • ~/Library/LaunchAgents/org.crowny.staking.slashwatch.plist 1회 실행형 권장:
    RunAtLoad+StartInterval 300(5분), KeepAlive false, WorkingDirectory=crowny-staking, Env: PATH·CROWNY_STD(SLASHWATCH_INTERVAL 미설정=1회 중복 방지). 영구 경로 권장(.toau 를 crowny-staking 아래로). launchctl load/unload 로 등록/해제.
    • 이 세션은 plist 생성·load 하지 않음(배경작업 폭주방지). 승인 시 사용자 등록.

    잔여 이슈 (4차)

    • stakes.dat 에 heartbeat/slash/enforce/enforce-cursor 이벤트 누적 → 읽기 64KB·줄목록 1023 상한
    도달 전 스냅샷+압축(2차 잔여와 동일, 감지기 enforce-cursor로 도달 소폭 앞당겨짐).
    • 뱅크(:9733) 잔고 연동(차감분 실잔고 반영) — 미연동.
    • 감지기 loop 모드 상주 시 서버 재기동 감지(현재는 서버 다운이면 curl 타임아웃 후 무해 종료).
    크라우니코드: lookup HIT 0 / MISS 3(외부감지위임·curl POST enforce·환경변수 모드선택 — search 결과 무매치) / learn 3(fn_스테이킹_다운타임외부감지위임·fn_한선_curl_POST_enforce위임·fn_한선_환경변수_모드선택_loop1회)

    상시운영 등록 (2026-07-04, 사용자 승인)

    • org.crowny.staking.slashwatch.plist 등록·bootstrap 완료. RunAtLoad+StartInterval 300초(5분), KeepAlive false, 영속 toau(/Users/ef/crowny-staking/자동감지.toau).
    • launchd 트리거 E2E: 2에폭 다운 밸리데이터 주입 → kickstart 1주기 → 감지기 enforce 위임(60맘 차감, slash_events 0→1) → 테스트 정리. 상시 다운타임 감시 라이브.