Skip to content

Commit 5625c82

Browse files
authored
Merge pull request #152 from ty-everett/codex/overlay-monitor-arc-callback
Add Overlay Express monitor and ARC callbacks
2 parents 03926f1 + 8095a42 commit 5625c82

9 files changed

Lines changed: 737 additions & 4 deletions

File tree

infra/overlay-server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"dependencies": {
2929
"@bsv/overlay": "^2.0.3",
3030
"@bsv/overlay-discovery-services": "^2.0.3",
31-
"@bsv/overlay-express": "^2.2.1",
31+
"@bsv/overlay-express": "^2.3.0",
3232
"@bsv/overlay-topics": "^1.0.1",
3333
"@bsv/sdk": "^2.1.3",
3434
"dotenv": "^17.2.4",

packages/overlays/overlay-express/CHANGELOG.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. The format
55
## Table of Contents
66

77
- [Unreleased](#unreleased)
8+
- [2.3.0](#230-2026-05-28)
89
- [0.7.11](#0711-2025-08-13)
910

1011
## [Unreleased]
@@ -29,6 +30,18 @@ All notable changes to this project will be documented in this file. The format
2930

3031
---
3132

33+
## [2.3.0] - 2026-05-28
34+
35+
### Added
36+
- Added `OverlayMonitor`, a reusable worker for probing Overlay Express `/lookup`
37+
responses and reporting BEEF proof-shape bloat.
38+
39+
### Fixed
40+
- ARC broadcasts now include an explicit `/arc-ingest` callback URL, with optional
41+
callback-token validation for deployments that configure one.
42+
43+
---
44+
3245
## [0.7.11] - 2025-08-13
3346

3447
### Added
@@ -62,4 +75,4 @@ Replace `X.X.X` with the new version number and `YYYY-MM-DD` with the release da
6275
-
6376
```
6477

65-
Use this template as the starting point for each new version. Always update the "Unreleased" section with changes as they're implemented, and then move them under the new version header when that version is released.
78+
Use this template as the starting point for each new version. Always update the "Unreleased" section with changes as they're implemented, and then move them under the new version header when that version is released.

packages/overlays/overlay-express/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,39 @@ server.registerHealthCheck({
116116

117117
The janitor service also understands the richer `/health` response format, so existing SHIP/SLAP health validation remains compatible.
118118

119+
### Overlay Monitor
120+
121+
`OverlayMonitor` provides a reusable worker for monitoring Overlay Express lookup behavior. It posts configured `/lookup` probes to any Overlay Express deployment, measures response size, parses returned BEEF, and reports whether responsive output transactions have direct Merkle proofs or are being served with deeper proof ancestry.
122+
123+
This is intended to be run by deployments as a long-running monitor process or by cluster scheduling. It is not tied to a specific deployment platform.
124+
125+
```typescript
126+
import { OverlayMonitor } from '@bsv/overlay-express'
127+
128+
const monitor = new OverlayMonitor({
129+
intervalMs: 24 * 60 * 60 * 1000,
130+
targets: [
131+
{
132+
name: 'example-overlay',
133+
baseUrl: 'https://overlay.example',
134+
probes: [
135+
{
136+
name: 'example-topic',
137+
service: 'ls_example',
138+
query: { topic: 'tm_example' },
139+
maxOutputs: 20
140+
}
141+
]
142+
}
143+
],
144+
onReport: async report => {
145+
console.log(JSON.stringify(report.summary))
146+
}
147+
})
148+
149+
monitor.start()
150+
```
151+
119152
## License
120153

121154
The license for the code in this repository is the Open BSV License. Refer to [LICENSE.txt](./LICENSE.txt) for the license text.

packages/overlays/overlay-express/mod.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,16 @@ export {
1111
export { BanService, type BannedRecord } from './src/BanService.js'
1212
export { BanAwareLookupWrapper } from './src/BanAwareLookupWrapper.js'
1313
export { JanitorService, type JanitorConfig, type JanitorReport, type HostHealthResult } from './src/JanitorService.js'
14+
export {
15+
OverlayMonitor,
16+
analyzeOverlayLookupResponse,
17+
type OverlayLookupOutputSummary,
18+
type OverlayLookupProbe,
19+
type OverlayLookupProbeResult,
20+
type OverlayMonitorConfig,
21+
type OverlayMonitorLogger,
22+
type OverlayMonitorReport,
23+
type OverlayMonitorTarget,
24+
type OverlayMonitorThresholds,
25+
type OverlayMonitorWarning
26+
} from './src/OverlayMonitor.js'

packages/overlays/overlay-express/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bsv/overlay-express",
3-
"version": "2.2.1",
3+
"version": "2.3.0",
44
"type": "module",
55
"description": "BSV Blockchain Overlay Express",
66
"main": "dist/cjs/mod.js",

packages/overlays/overlay-express/src/OverlayExpress.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ export default class OverlayExpress {
189189
// ARC API Key
190190
arcApiKey: string | undefined = undefined
191191

192+
// Optional ARC callback token for /arc-ingest notifications
193+
arcCallbackToken: string | undefined = undefined
194+
192195
// Verbose request logging
193196
verboseRequestLogging: boolean = false
194197

@@ -372,6 +375,15 @@ export default class OverlayExpress {
372375
this.logger.log(chalk.blue('ARC API key has been configured.'))
373376
}
374377

378+
/**
379+
* Configures the ARC callback token expected by /arc-ingest.
380+
* @param token - The token ARC should present when posting callback notifications.
381+
*/
382+
configureArcCallbackToken (token: string): void {
383+
this.arcCallbackToken = token
384+
this.logger.log(chalk.blue('ARC callback token has been configured.'))
385+
}
386+
375387
/**
376388
* Enables or disables GASP synchronization (high-level setting).
377389
* This is a broad toggle that can be overridden or customized through syncConfiguration.
@@ -581,7 +593,11 @@ export default class OverlayExpress {
581593
private buildBroadcaster (): Broadcaster | undefined {
582594
if (typeof this.arcApiKey !== 'string') return undefined
583595
const arcUrl = this.network === 'test' ? 'https://arc-test.taal.com' : 'https://arc.taal.com'
584-
return new ARC(arcUrl, { apiKey: this.arcApiKey })
596+
return new ARC(arcUrl, {
597+
apiKey: this.arcApiKey,
598+
callbackUrl: `https://${this.advertisableFQDN}/arc-ingest`,
599+
callbackToken: this.arcCallbackToken
600+
})
585601
}
586602

587603
/** Resolve the SLAP trackers from config or network defaults. */
@@ -1253,6 +1269,18 @@ export default class OverlayExpress {
12531269
this.app.post('/arc-ingest', (req, res) => {
12541270
; (async () => {
12551271
try {
1272+
if (typeof this.arcCallbackToken === 'string' && this.arcCallbackToken.length > 0) {
1273+
const authorization = req.headers.authorization
1274+
const headerToken = Array.isArray(authorization) ? authorization[0] : authorization
1275+
const xCallbackToken = req.headers['x-callback-token']
1276+
const callbackToken = Array.isArray(xCallbackToken) ? xCallbackToken[0] : xCallbackToken
1277+
const bearerToken = typeof headerToken === 'string' && headerToken.startsWith('Bearer ')
1278+
? headerToken.slice('Bearer '.length)
1279+
: headerToken
1280+
if (bearerToken !== this.arcCallbackToken && callbackToken !== this.arcCallbackToken) {
1281+
return res.status(401).json({ status: 'error', message: 'Unauthorized callback' })
1282+
}
1283+
}
12561284
const { txid, merklePath: merklePathHex, blockHeight } = req.body
12571285
const merklePath = MerklePath.fromHex(merklePathHex)
12581286
await engine.handleNewMerkleProof(txid, merklePath, blockHeight)

0 commit comments

Comments
 (0)