-
Notifications
You must be signed in to change notification settings - Fork 196
Expand file tree
/
Copy pathrun_bot.sh
More file actions
executable file
·168 lines (160 loc) · 8.21 KB
/
Copy pathrun_bot.sh
File metadata and controls
executable file
·168 lines (160 loc) · 8.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/usr/bin/env bash
# Drive the settlement-arbitrage bot with all output teed to a log file.
#
# A self-contained launcher so the bot can be started/stopped deterministically
# without rediscovering the launch mechanics each time.
#
# ./run_bot.sh # foreground (output -> console + log)
# ./run_bot.sh start # detached (setsid), pid -> logs/bot_run.pid
# ./run_bot.sh stop # kill the running bot (by pidfile + pkill)
# ./run_bot.sh status # is it running?
set -u
cd /workspaces/degenbot
LOGDIR=/workspaces/degenbot/logs
LOG="$LOGDIR/bot_run.log"
PIDFILE="$LOGDIR/bot_run.pid"
mkdir -p "$LOGDIR"
# --------------------------------------------------------------------------
# Conservative (HARD/LOUD) defaults now live in the CODE, not here (Z4KQXF).
# Every invocation — run_bot.sh, a hand-run, a CI/harness — gets loud failure
# by default; there is no liberal default posture anymore. Flags that follow
# are all default-ON in code via `bot_env_flag_default_on` (opt OUT with =0):
# DEGENBOT_ASSERT_SOLVER_STATE (ADR-021 publish tripwire, fatal on desync)
# — script-DISABLED here for the fast path (see export block below); the
# code default remains ON for hand-runs/harness.
# DEGENBOT_VERIFY_DBG (structural verify diagnostics / divergence set)
# DEGENBOT_DUMP_CALL_TRACE (full revm call trace on sim failure)
# DEGENBOT_V2_CALC_TRACE (V2 reserves slot8 before each sim)
# DEGENBOT_SIM_LOG_REVERTED_SWAPS (per-hop actual-vs-predicted on revert)
# DEGENBOT_SIM_EXIT_ON_FAIL (stop on first sim failure) - see below: this
# script DEFAULTS it to 0; failing sims are identified via OTel traces.
# DEGENBOT_WS_COMPLETENESS (per-block eth_getLogs vs WS delivery cross-
# check; NEW default-ON since B4GX7C, so a live WS log drop aborts loudly)
# Script-defaulted high-noise traces (set =0 to opt out; the Rust gate is
# presence-gated on "1"/"true", so these are OFF in hand-runs by default):
# DEGENBOT_WS_TRACE # [trace] ws-log for EVERY relevant-topic WS
# log with block/log_index/tx_index/topic0/removed/decision — high-volume,
# but the catch-all for "did this log even arrive and apply before the
# solver-state check fired" desync investigations
# Per-target/high-noise (still OFF): DEGENBOT_DRAIN_DBG, DEGENBOT_TRACE_REGISTER_SEED
# DEGENBOT_DUMP_TICK_MAPS (opt-in: dump full seed + verifier tick maps for the
# tick-map desync re-assembly aid; high volume, set only for an investigation)
#
# Sim-failure policy: this script DEFAULTS DEGENBOT_SIM_EXIT_ON_FAIL=0 (keep
# running through thin-margin/no-profit reverts - the routine arb-filter
# outcome). Failing simulations are identified from OTel traces/metrics going
# forward, not by killing the bot. Override to 1 to restore the old fail-fast.
# --------------------------------------------------------------------------
# --------------------------------------------------------------------------
# Debug-visible instrumented runs (default ON here).
#
# The Rust core's granular diagnostics ([solver-dbg],
# [solver-st], [v2-calc-trace], ...) are gated behind the `debug` tracing
# level AND the Python-side DEBUG logger (see docs/logging.md). Set BOTH below
# so those lines reach logs/bot_run.log in these instrumented runs:
#
# * RUST_LOG is the Rust `tracing` EnvFilter gate. Raising the
# degenbot_* crates to `debug` makes the fine-grained
# diagnostics visible while `info` keeps routine status
# lines; the alloy/tungstenite targets are held at `warn`
# to mirror the code's built-in default and stop their
# lifecycle INFO noise from flooding the log.
# * DEGENBOT_DEBUG=1 is the Python `logging` gate. Without it the crate-root
# Python loggers stay at INFO and drop the debug records
# before they reach the log/bot_run.log tee.
#
# Both respect a pre-set value: set RUST_LOG / DEGENBOT_DEBUG yourself to opt
# out (e.g. RUST_LOG=warn ./run_bot.sh) or tighten the scope.
# --------------------------------------------------------------------------
DEFAULT_RUST_LOG="info,degenbot_bot=debug,degenbot_arbitrage=debug,degenbot_simulation=debug,degenbot_solvers=debug,alloy_pubsub=warn,alloy_transport=warn,alloy_transport_ws=warn,alloy_transport_ipc=warn,alloy_transport_http=warn,alloy_provider=warn,alloy_rpc=warn,alloy_network=warn,alloy_contract=warn,tungstenite=warn"
export RUST_LOG="${RUST_LOG:-$DEFAULT_RUST_LOG}"
export DEGENBOT_DEBUG="${DEGENBOT_DEBUG:-1}"
export DEGENBOT_OTEL="${DEGENBOT_OTEL:-1}"
export DEGENBOT_SIM_EXIT_ON_FAIL="${DEGENBOT_SIM_EXIT_ON_FAIL:-0}"
export DEGENBOT_WS_TRACE="${DEGENBOT_WS_TRACE:-1}"
# Solver-state verification policy: the CODE default stays ON (loud fail-stop),
# but this script defaults the per-publish chain-diff verifier OFF so the bot
# runs the fast "solve against possibly-stale state, invalidate later" path.
# DEGENBOT_ASSERT_SOLVER_STATE=1 re-enables the hard gate for audits. A
# sampling-based silent-decay detector is the planned replacement.
export DEGENBOT_ASSERT_SOLVER_STATE="${DEGENBOT_ASSERT_SOLVER_STATE:-0}"
# The actual bot invocation (uv rebuilds the Rust extension if any rust
# source / Cargo.toml is newer than the installed build).
BOT_CMD=(uv run python examples/eth_settlement_arbitrage_v2_v3_v4_rust.py)
start() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then
echo "[runner] bot already running (pid $(cat "$PIDFILE"))" >&2
return 1
fi
: > "$LOG"
: > "$PIDFILE"
# setsid: new session + no controlling terminal, so the launching shell
# can exit without the pump dying (SIGHUP) and the tool shell's return
# isn't entangled with the bot's life. exec is NOT used so `$!` is the
# (setsid'd) uv pid we record. Output is captured by direct fd redirection
# (never a tee pipeline), so the log is authoritative and survives the
# launching shell going away.
setsid "${BOT_CMD[@]}" >>"$LOG" 2>&1 < /dev/null &
echo $! > "$PIDFILE"
# Runner diagnostics go to the log too, so the whole launch is in one place.
echo "[runner] started bot pid $(cat "$PIDFILE") $(date -Is)" | tee -a "$LOG" >&2
}
stop() {
if [ -f "$PIDFILE" ]; then
kill -TERM "$(cat "$PIDFILE")" 2>/dev/null
sleep 1
kill -9 "$(cat "$PIDFILE")" 2>/dev/null
rm -f "$PIDFILE"
fi
# The uv wrapper may exit while its python child lingers; kill by name too.
pkill -9 -f eth_settlement_arbitrage_v2_v3_v4 2>/dev/null
echo "[runner] stopped $(date -Is)"
}
status() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then
echo "[runner] running pid $(cat "$PIDFILE")"
ps -o pid,etime,cmd -p "$(cat "$PIDFILE")" 2>/dev/null | tail -1
else
echo "[runner] not running"
fi
}
foreground() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then
echo "[runner] bot already running (pid $(cat "$PIDFILE")) — stop it first" >&2
return 1
fi
# Fresh truncation, same as `start`, so the log always reflects this run
# (the append-only `tee -a` behaviour is gone for determinism).
: > "$LOG"
: > "$PIDFILE"
echo "[runner] starting bot $(date -Is)" | tee -a "$LOG" >&2
# Bot output goes to the log by direct fd redirection — authoritative and
# immune to a closing console (no `tee` pipeline to SIGPIPE and drop the
# tail). The console is only a live mirror fed by `tail -f`.
"${BOT_CMD[@]}" >>"$LOG" 2>&1 < /dev/null &
BOTPID=$!
echo "$BOTPID" > "$PIDFILE"
tail -f -n +1 "$LOG" &
TAILPID=$!
# Forward Ctrl-C / TERM to the bot so it stops cleanly (the pump then gets
# its exit path rather than being killed out from under the lock).
trap 'kill -TERM "$BOTPID" 2>/dev/null' INT TERM
wait "$BOTPID"
BOTRC=$?
kill "$TAILPID" 2>/dev/null
wait "$TAILPID" 2>/dev/null
rm -f "$PIDFILE"
trap - INT TERM
echo "[runner] bot exited rc=$BOTRC $(date -Is)" | tee -a "$LOG" >&2
return "$BOTRC"
}
case "${1:-foreground}" in
start) start ;;
stop) stop ;;
status) status ;;
foreground) foreground ;;
*)
echo "usage: $0 {start|stop|status|foreground}" >&2
exit 1
;;
esac