Fix write-check by disabling verification by default, since it isn't working yet. Also add tests

This commit is contained in:
pleb
2026-03-22 20:00:16 -07:00
parent dc5023d272
commit ef7463a29a
8 changed files with 292 additions and 25 deletions
+7
View File
@@ -10,6 +10,7 @@ export interface RelayTarget {
export interface WriteCheckConfig {
enabled: boolean;
verifyRead: boolean;
kind: number;
privkey?: string;
}
@@ -34,6 +35,7 @@ const DEFAULT_LISTEN_ADDR = "0.0.0.0";
const DEFAULT_PORT = 9464;
const DEFAULT_LOG_LEVEL: LogLevel = "info";
const DEFAULT_WRITE_CHECK_ENABLED = true;
const DEFAULT_WRITE_CHECK_VERIFY_READ = false;
const DEFAULT_WRITE_CHECK_KIND = 30078;
const MIN_TIMEOUT_SECONDS = 1;
@@ -170,6 +172,10 @@ export function loadConfig(env: NodeJS.ProcessEnv = process.env): AppConfig {
}
const writeEnabledFlag = parseBoolean(env.WRITE_CHECK_ENABLED, DEFAULT_WRITE_CHECK_ENABLED);
const writeVerifyReadFlag = parseBoolean(
env.WRITE_CHECK_VERIFY_READ,
DEFAULT_WRITE_CHECK_VERIFY_READ,
);
const writeCheckKind = parseInteger(
env.WRITE_CHECK_KIND,
DEFAULT_WRITE_CHECK_KIND,
@@ -200,6 +206,7 @@ export function loadConfig(env: NodeJS.ProcessEnv = process.env): AppConfig {
const staleAfterMs = probeIntervalMs + probeTimeoutMs + 5_000;
const writeCheck: WriteCheckConfig = {
enabled: writeEnabledFlag,
verifyRead: writeVerifyReadFlag,
kind: writeCheckKind,
...(resolvedWritePrivkey ? { privkey: resolvedWritePrivkey } : {}),
};
+45 -17
View File
@@ -23,6 +23,7 @@ interface RelayCheckNode {
interface NocapResult {
open?: RelayCheckNode;
read?: RelayCheckNode;
write?: RelayCheckNode;
}
interface RelayProbeState {
@@ -192,8 +193,13 @@ export class RelayProber {
const adapters = Object.values(NocapEveryAdapterDefault);
await nocap.useAdapters(adapters);
const checks: string[] =
this.config.writeCheck.enabled && !this.config.writeCheck.verifyRead
? ["open", "read", "write"]
: ["open", "read"];
const result = (await withTimeout(
nocap.check(["open", "read"], true) as Promise<NocapResult>,
nocap.check(checks, true) as Promise<NocapResult>,
this.config.probeTimeoutMs * 2,
"nocap open/read",
)) as NocapResult;
@@ -211,27 +217,49 @@ export class RelayProber {
}
if (this.config.writeCheck.enabled) {
const privkey = this.config.writeCheck.privkey;
if (!privkey) {
writeConfirmOk = false;
this.metrics.incProbeError(relayLabel, "write_confirm");
} else {
const writeResult = await runWriteConfirm({
relay: relay.relay,
host: relay.host,
kind: this.config.writeCheck.kind,
privkey,
timeoutMs: this.config.probeTimeoutMs,
});
writeConfirmOk = writeResult.ok;
writeDurationMs = durationOrDefault(writeResult.durationMs);
if (!writeResult.ok) {
if (!this.config.writeCheck.verifyRead) {
// Match nocap behavior: use websocket write check in the same nocap session.
const writeNode = result.write;
writeConfirmOk =
writeNode !== undefined &&
writeNode.status !== "error" &&
writeNode.data !== false;
writeDurationMs = durationOrDefault(result.write?.duration);
if (!writeConfirmOk) {
this.metrics.incProbeError(relayLabel, "write_confirm");
this.logger.warn(
{ relay: relayLabel, check: "write_confirm", reason: writeResult.reason },
{
relay: relayLabel,
check: "write_confirm",
reason: result.write?.message ?? "nocap write check failed",
},
"write confirmation failed",
);
}
} else {
const privkey = this.config.writeCheck.privkey;
if (!privkey) {
writeConfirmOk = false;
this.metrics.incProbeError(relayLabel, "write_confirm");
} else {
const writeResult = await runWriteConfirm({
relay: relay.relay,
host: relay.host,
kind: this.config.writeCheck.kind,
privkey,
verifyRead: this.config.writeCheck.verifyRead,
timeoutMs: this.config.probeTimeoutMs,
});
writeConfirmOk = writeResult.ok;
writeDurationMs = durationOrDefault(writeResult.durationMs);
if (!writeResult.ok) {
this.metrics.incProbeError(relayLabel, "write_confirm");
this.logger.warn(
{ relay: relayLabel, check: "write_confirm", reason: writeResult.reason },
"write confirmation failed",
);
}
}
}
}
+8
View File
@@ -6,6 +6,7 @@ interface WriteConfirmInput {
host: string;
kind: number;
privkey: string;
verifyRead: boolean;
timeoutMs: number;
}
@@ -108,6 +109,13 @@ export async function runWriteConfirm(input: WriteConfirmInput): Promise<WriteCo
await withTimeout(relay.publish(event), input.timeoutMs, "relay publish");
if (!input.verifyRead) {
return {
ok: true,
durationMs: Math.round(performance.now() - startedAt),
};
}
const elapsedMs = performance.now() - startedAt;
const remainingMs = Math.max(1, input.timeoutMs - Math.floor(elapsedMs));