AsyncAPI specification for GASP (Graph Aware Sync Protocol), the
cross-node UTXO synchronisation protocol implemented in
gasp-core (@bsv/gasp-core).
GASP is a bidirectional gossip/sync protocol between overlay nodes. Two parties exchange UTXO lists (the "initial exchange") and then walk the transaction graph in a request/response pattern to transfer any UTXOs the counterparty does not yet hold.
Initiator Responder
| |
|-- GASPInitialRequest ---------------------->|
|<- GASPInitialResponse -----------------------|
|-- GASPInitialReply ------------------------->| (if not unidirectional)
| |
| [for each UTXO the counterparty is missing]
|-- requestNode(graphID, txid, vout, meta) -->|
|<- GASPNode ---------------------------------|
| |
| [responder may request further inputs]
|<- submitNode(GASPNode) ---------------------|
|-- GASPNodeResponse ------------------------>|
| (repeat until graph is complete)
| |
Source of truth: /ts/gasp-core/src/GASP.ts
Initiator sends its sync parameters. The responder replies on the
gasp/initialResponse channel.
Initiator sends sync parameters to the responder.
Accepts the following message:
First message in a GASP sync session. The initiator declares its protocol version, the timestamp of the last sync with this party, and an optional page size limit.
Parameters sent by the initiator to start a GASP sync session. Version mismatch (current version is 1) causes the responder to throw GASPVersionMismatchError and abort the session.
{
"version": 1,
"since": 1714000000,
"limit": 1000
}
Responder sends back its list of known UTXOs and the timestamp from which it wants to receive UTXOs from the initiator.
Initiator receives the responder's UTXO list and since timestamp.
Accepts the following message:
Responder's reply to GASPInitialRequest. Contains the list of UTXOs the responder has seen since `request.since`, plus the timestamp from which the responder wants UTXOs back from the initiator.
Responder's answer to GASPInitialRequest. UTXOList contains all
UTXOs the responder has seen since request.since; unconfirmed
(non-timestamped) UTXOs are always included regardless of timestamp.
{
"UTXOList": [
{
"txid": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"outputIndex": 0,
"score": 1714000000
}
],
"since": 1714001000
}
Initiator (if operating in bidirectional mode) sends the set of UTXOs it holds that the responder does not. Absent in unidirectional mode.
Initiator (bidirectional mode only) sends UTXOs the responder is missing.
Accepts the following message:
Initiator's follow-up (bidirectional mode). UTXOs the initiator holds that were not in the Initial Response — i.e. UTXOs the responder needs.
Sent by the initiator in bidirectional mode. Contains UTXOs the
initiator holds that are newer than response.since AND were not
already present in the Initial Response (so the responder can ingest
them).
{
"UTXOList": [
{
"txid": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"outputIndex": 0,
"score": 1714000000
}
]
}
Either party requests a specific graph node (transaction + output) from the other. Used when walking the transaction graph to hydrate UTXOs.
Request a specific transaction node from the counterparty.
Accepts the following message:
Request for a specific transaction node identified by graphID, txid, outputIndex, and whether transaction/output metadata should be included.
Request for a specific graph node. graphID is the 36-byte outpoint
string (<txid>.<vout>) identifying the tip of the graph being walked.
{
"graphID": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2.0",
"txid": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"outputIndex": 0,
"metadata": true
}
The responding party delivers the requested GASPNode (raw transaction, optional BUMP proof, optional metadata).
Receive a requested graph node from the counterparty.
Accepts the following message:
A transaction node: the raw transaction, the output index, an optional BUMP merkle proof, optional metadata strings, and a mapping of input outpoints to metadata hashes so the receiver can request ancestors.
A fully-hydrated graph node. rawTx is the complete serialised
Bitcoin transaction in hex. proof is a hex-encoded BUMP (BRC-74)
merkle proof, only present for confirmed transactions. inputs maps
each input outpoint (<txid>.<vout>) to the hash of its metadata,
allowing the recipient to detect when it needs updated metadata.
{
"graphID": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2.0",
"rawTx": "0100000001...",
"outputIndex": 0,
"proof": "string",
"txMetadata": "string",
"outputMetadata": "string",
"inputs": {
"property1": {
"hash": "string"
},
"property2": {
"hash": "string"
}
}
}
A party submits a node it is trying to push to the counterparty. The counterparty appends it to the temporary graph and may respond with a list of additional inputs it still needs.
Push a graph node to the counterparty for ingestion.
Accepts the following message:
A transaction node: the raw transaction, the output index, an optional BUMP merkle proof, optional metadata strings, and a mapping of input outpoints to metadata hashes so the receiver can request ancestors.
A fully-hydrated graph node. rawTx is the complete serialised
Bitcoin transaction in hex. proof is a hex-encoded BUMP (BRC-74)
merkle proof, only present for confirmed transactions. inputs maps
each input outpoint (<txid>.<vout>) to the hash of its metadata,
allowing the recipient to detect when it needs updated metadata.
{
"graphID": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2.0",
"rawTx": "0100000001...",
"outputIndex": 0,
"proof": "string",
"txMetadata": "string",
"outputMetadata": "string",
"inputs": {
"property1": {
"hash": "string"
},
"property2": {
"hash": "string"
}
}
}
Response to a submitted node; specifies which additional input transactions (if any) the recipient still needs to complete the graph. An empty / null response means the graph is complete.
Receive the counterparty's response to a submitted node, listing any additional input transactions needed to complete the graph.
Accepts the following message:
Response to a submitted GASPNode. Lists the input outpoints (in 36-byte `<txid>.<vout>` format) that the recipient still needs to complete the graph. A null / absent response means no further inputs are required and the graph is complete.
Response to a submitted GASPNode. requestedInputs lists outpoints
the recipient still needs in order to complete the graph and whether
metadata is required for each. If null or omitted, the graph is
complete and will be validated and finalised.
{
"requestedInputs": {
"property1": {
"metadata": true
},
"property2": {
"metadata": true
}
}
}
First message in a GASP sync session. The initiator declares its protocol version, the timestamp of the last sync with this party, and an optional page size limit.
Parameters sent by the initiator to start a GASP sync session. Version mismatch (current version is 1) causes the responder to throw GASPVersionMismatchError and abort the session.
Responder's reply to GASPInitialRequest. Contains the list of UTXOs the responder has seen since `request.since`, plus the timestamp from which the responder wants UTXOs back from the initiator.
Responder's answer to GASPInitialRequest. UTXOList contains all
UTXOs the responder has seen since request.since; unconfirmed
(non-timestamped) UTXOs are always included regardless of timestamp.
Initiator's follow-up (bidirectional mode). UTXOs the initiator holds that were not in the Initial Response — i.e. UTXOs the responder needs.
Sent by the initiator in bidirectional mode. Contains UTXOs the
initiator holds that are newer than response.since AND were not
already present in the Initial Response (so the responder can ingest
them).
Request for a specific transaction node identified by graphID, txid, outputIndex, and whether transaction/output metadata should be included.
Request for a specific graph node. graphID is the 36-byte outpoint
string (<txid>.<vout>) identifying the tip of the graph being walked.
A transaction node: the raw transaction, the output index, an optional BUMP merkle proof, optional metadata strings, and a mapping of input outpoints to metadata hashes so the receiver can request ancestors.
A fully-hydrated graph node. rawTx is the complete serialised
Bitcoin transaction in hex. proof is a hex-encoded BUMP (BRC-74)
merkle proof, only present for confirmed transactions. inputs maps
each input outpoint (<txid>.<vout>) to the hash of its metadata,
allowing the recipient to detect when it needs updated metadata.
Response to a submitted GASPNode. Lists the input outpoints (in 36-byte `<txid>.<vout>` format) that the recipient still needs to complete the graph. A null / absent response means no further inputs are required and the graph is complete.
Response to a submitted GASPNode. requestedInputs lists outpoints
the recipient still needs in order to complete the graph and whether
metadata is required for each. If null or omitted, the graph is
complete and will be validated and finalised.
Parameters sent by the initiator to start a GASP sync session. Version mismatch (current version is 1) causes the responder to throw GASPVersionMismatchError and abort the session.
Responder's answer to GASPInitialRequest. UTXOList contains all
UTXOs the responder has seen since request.since; unconfirmed
(non-timestamped) UTXOs are always included regardless of timestamp.
Sent by the initiator in bidirectional mode. Contains UTXOs the
initiator holds that are newer than response.since AND were not
already present in the Initial Response (so the responder can ingest
them).
Minimal outpoint descriptor used in the initial exchange phases.
score is a sortable timestamp (seconds since epoch) assigned when
the UTXO was first confirmed; unconfirmed UTXOs may have score 0.
Request for a specific graph node. graphID is the 36-byte outpoint
string (<txid>.<vout>) identifying the tip of the graph being walked.
A fully-hydrated graph node. rawTx is the complete serialised
Bitcoin transaction in hex. proof is a hex-encoded BUMP (BRC-74)
merkle proof, only present for confirmed transactions. inputs maps
each input outpoint (<txid>.<vout>) to the hash of its metadata,
allowing the recipient to detect when it needs updated metadata.
Response to a submitted GASPNode. requestedInputs lists outpoints
the recipient still needs in order to complete the graph and whether
metadata is required for each. If null or omitted, the graph is
complete and will be validated and finalised.
Thrown (and serialised into the response) when the responder's GASP version differs from the version declared in GASPInitialRequest.