4. Automated Validation & Rate Limits
Summary: validation happens before PoV. We accept a window only if the payload is canonical JSON, values are plausible, the tuple (device_id, start_ts, end_ts) does not overlap previous windows, and replay/duplicates are blocked with idempotency and rate limits. Anything that fails is rejected or quarantined before attestations.
What this layer does
It protects the pipeline from bad or abusive input. It verifies schema and canonical form, window rules, value sanity, duplicate/replay, and throughput per device_id and operator. Only then do we compute evidenceHash, derive claimId, and move on to attestation.
Validation rules
Example: minimal validator (TypeScript)
type Window = {
batch_id: `0x${string}`;
device_id: `0x${string}`;
start_ts: number; // UTC seconds
end_ts: number; // UTC seconds
quantity_wh: number;
nonce: `0x${string}`;
};
type Now = () => number; // ms
export function validateWindow(
payloadCanonicalJson: string,
headers: { xDeviceId: string; xWindowId: string; xNonce: string; xTimestamp: number },
opts: {
now: Now;
minDurSec: number; maxDurSec: number;
maxSkewMs: number;
ratedWhPerWindow: number;
lastWindows: Array<{start_ts:number; end_ts:number}>;
seenBatchIds: Set<string>;
seenNoncesByDevice: Map<string, Set<string>>;
idempotentStore: Map<string, string>; // batch_id -> canonical JSON
}
) {
// 1) Canonical match
const parsed = JSON.parse(payloadCanonicalJson) as Window;
const reCanon = JSON.stringify(parsed, Object.keys(parsed).sort().reduce((o,k)=>(o[k]=parsed[k as keyof Window],o),{} as any)).replace(/\s+/g,'');
if (reCanon !== payloadCanonicalJson) throw new Error("NON_CANONICAL_JSON");
// 2) Header congruence
if (headers.xDeviceId !== parsed.device_id) throw new Error("SCHEMA_INVALID");
if (headers.xWindowId !== parsed.batch_id) throw new Error("SCHEMA_INVALID");
if (headers.xNonce !== parsed.nonce) throw new Error("SCHEMA_INVALID");
// 3) Window integrity
if (!(parsed.start_ts < parsed.end_ts)) throw new Error("SCHEMA_INVALID");
const dur = parsed.end_ts - parsed.start_ts;
if (dur < opts.minDurSec || dur > opts.maxDurSec) throw new Error("OUT_OF_BOUNDS");
// 4) Timestamp skew
const skew = Math.abs(opts.now() - headers.xTimestamp);
if (skew > opts.maxSkewMs) throw new Error("TIMESTAMP_SKEW");
// 5) Overlap check for this device
for (const w of opts.lastWindows) {
const overlap = Math.max(0, Math.min(parsed.end_ts, w.end_ts) - Math.max(parsed.start_ts, w.start_ts));
if (overlap > 0) throw new Error("OVERLAPPING_WINDOW");
}
// 6) Plausibility
if (parsed.quantity_wh < 0) throw new Error("NEGATIVE_QUANTITY");
if (parsed.quantity_wh > opts.ratedWhPerWindow * 1.15) throw new Error("OUT_OF_BOUNDS");
// 7) Duplicate batch id (idempotent upsert)
if (opts.seenBatchIds.has(parsed.batch_id)) {
const prior = opts.idempotentStore.get(parsed.batch_id);
if (prior !== payloadCanonicalJson) throw new Error("DUPLICATE_BATCH");
}
// 8) Nonce replay per device
const nonces = opts.seenNoncesByDevice.get(parsed.device_id) ?? new Set<string>();
if (nonces.has(parsed.nonce)) throw new Error("REPLAY_NONCE");
// if all good, record idempotently
opts.seenBatchIds.add(parsed.batch_id);
nonces.add(parsed.nonce);
opts.seenNoncesByDevice.set(parsed.device_id, nonces);
opts.idempotentStore.set(parsed.batch_id, payloadCanonicalJson);
return parsed; // safe to hash and attest
}Clear outcomes
If a rule fails, return a specific error like NON_CANONICAL_JSON, OVERLAPPING_WINDOW, TIMESTAMP_SKEW, NEGATIVE_QUANTITY, OUT_OF_BOUNDS, DUPLICATE_BATCH, REPLAY_NONCE, or RATE_LIMITED. If a value is suspicious but not clearly wrong (for example, sudden spike), place the window in quarantine (QUARANTINED) for attestor review instead of hard rejecting.
Conformance
Write canonical JSON and submit with signed headers; ensure start_ts < end_ts and no overlaps per device_id; keep quantity_wh within device bounds; prevent nonce reuse and duplicate batch_id except for true idempotency; enforce device/operator rate limits; only after passing, compute evidenceHash and claimId and proceed to attest.
Bottom line: validate early, rate-limit fairly. It keeps junk out, protects attestors, and lets the PoV Gate focus on evidence—not cleanup.
Last updated
