Loading…
Graph Aware Sync Protocol — synchronize transaction graphs between overlay nodes with incremental building, SPV validation, and bandwidth efficiency.
npm install @bsv/gaspimport {
GASP,
LogLevel,
type GASPNode,
type GASPNodeResponse,
type GASPRemote,
type GASPStorage
} from '@bsv/gasp'
// Implement GASPStorage
class MyStorage implements GASPStorage {
async findKnownUTXOs(since: number, limit?: number) {
return [
{ txid: 'abc...', outputIndex: 0, score: Date.now() },
{ txid: 'def...', outputIndex: 1, score: Date.now() }
]
}
async hydrateGASPNode(
graphID: string,
txid: string,
outputIndex: number,
metadata: boolean
): Promise<GASPNode> {
return {
graphID,
rawTx: '0100...',
outputIndex,
proof: 'BUMP_proof...',
txMetadata: metadata ? 'transaction metadata' : undefined,
outputMetadata: metadata ? 'output metadata' : undefined
}
}
async findNeededInputs(tx: GASPNode): Promise<GASPNodeResponse | void> {
return
}
async appendToGraph(tx: GASPNode, spentBy?: string) {
// Store node in temporary graph
}
async validateGraphAnchor(graphID: string) {
// Confirm graph is anchored in blockchain
}
async discardGraph(graphID: string) {
// Remove temporary graph data after a failed sync
}
async finalizeGraph(graphID: string) {
// Finalize into persistent storage
}
}
declare const remote: GASPRemote
// Initialize and sync
const gasp = new GASP(new MyStorage(), remote, 0, '[GASP] ', false, false, LogLevel.INFO, false)
await gasp.sync('https://peer.example.com')import {
type GASPInitialRequest,
type GASPInitialResponse,
type GASPNode,
type GASPNodeResponse,
type GASPRemote
} from '@bsv/gasp'
class MyRemote implements GASPRemote {
async getInitialResponse(request: GASPInitialRequest) {
const response = await fetch('https://peer.example.com/gasp/initial', {
method: 'POST',
body: JSON.stringify(request)
})
return response.json()
}
async getInitialReply(response: GASPInitialResponse) {
const reply = await fetch('https://peer.example.com/gasp/reply', {
method: 'POST',
body: JSON.stringify(response)
})
return reply.json()
}
async requestNode(
graphID: string,
txid: string,
outputIndex: number,
metadata: boolean
): Promise<GASPNode> {
const response = await fetch('https://peer.example.com/gasp/node', {
method: 'POST',
body: JSON.stringify({ graphID, txid, outputIndex, metadata })
})
return response.json()
}
async submitNode(node: GASPNode): Promise<GASPNodeResponse | void> {
const response = await fetch('https://peer.example.com/gasp/submit', {
method: 'POST',
body: JSON.stringify(node)
})
return response.json()
}
}const gaspPullOnly = new GASP(
storage,
remote,
0,
'[GASP-Pull] ',
false,
true, // unidirectional = true
LogLevel.DEBUG,
false
)
await gaspPullOnly.sync('https://peer.example.com')
// Local storage updated, but remote sees no data from usconst gaspSequential = new GASP(
storage,
remote,
0,
'[GASP-Sequential] ',
false,
false,
LogLevel.WARN,
true // sequential = true
)
await gaspSequential.sync('https://peer.example.com')
// One operation at a time to avoid DB lockingtxid.outputIndex (dot-separated)undefined if no inputs needed; empty object {} may cause issuesvalidateGraphAnchor() must throw; returning gracefully doesn't stop syncsubmitNode() in unidirectional mode; remote won't processconfigureEnableGASPSync()