@bsv/overlay 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/package.json +2 -2
- package/dist/cjs/src/Engine.js +10 -3
- package/dist/cjs/src/Engine.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/Engine.js +11 -3
- package/dist/esm/src/Engine.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/Engine.d.ts +3 -1
- package/dist/types/src/Engine.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/docs/API.md +619 -356
- package/package.json +2 -2
- package/src/Engine.ts +32 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bsv/overlay",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "BSV Blockchain Overlay Services Engine",
|
|
6
6
|
"main": "dist/cjs/mod.js",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"@bsv/gasp": "^1.2.0",
|
|
77
|
-
"@bsv/sdk": "^1.6.
|
|
77
|
+
"@bsv/sdk": "^1.6.20",
|
|
78
78
|
"knex": "^3.1.0"
|
|
79
79
|
}
|
|
80
80
|
}
|
package/src/Engine.ts
CHANGED
|
@@ -47,8 +47,9 @@ export class Engine {
|
|
|
47
47
|
* @param {boolean} throwOnBroadcastFailure - Enables / disables throwing an error when a transaction broadcast failure is detected.
|
|
48
48
|
* @param {OverlayBroadcastFacilitator} overlayBroadcastFacilitator - Facilitator for propagation to other Overlay Services.
|
|
49
49
|
* @param {typeof console} logger - The place where log entries are written.
|
|
50
|
+
* @param {boolean} suppressDefaultSyncAdvertisements - Whether to suppress the default (SHIP/SLAP) sync advertisements.
|
|
50
51
|
*/
|
|
51
|
-
constructor
|
|
52
|
+
constructor(
|
|
52
53
|
public managers: { [key: string]: TopicManager },
|
|
53
54
|
public lookupServices: { [key: string]: LookupService },
|
|
54
55
|
public storage: Storage,
|
|
@@ -63,7 +64,8 @@ export class Engine {
|
|
|
63
64
|
public logPrefix = '[OVERLAY_ENGINE] ',
|
|
64
65
|
public throwOnBroadcastFailure = false,
|
|
65
66
|
public overlayBroadcastFacilitator: OverlayBroadcastFacilitator = new HTTPSOverlayBroadcastFacilitator(),
|
|
66
|
-
public logger: typeof console = console
|
|
67
|
+
public logger: typeof console = console,
|
|
68
|
+
public suppressDefaultSyncAdvertisements = true
|
|
67
69
|
) {
|
|
68
70
|
// To encourage synchronization of overlay services, the SHIP sync strategy is used by default for all overlay topics, except for 'tm_ship' and 'tm_slap'.
|
|
69
71
|
// For these two topics, any existing trackers are combined with the provided shipTrackers and slapTrackers omitting any duplicates.
|
|
@@ -98,13 +100,13 @@ export class Engine {
|
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
// Helper functions for logging timings
|
|
101
|
-
private startTime
|
|
103
|
+
private startTime(label: string): void {
|
|
102
104
|
if (this.logTime) {
|
|
103
105
|
this.logger.time(`${this.logPrefix} ${label}`)
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
private endTime
|
|
109
|
+
private endTime(label: string): void {
|
|
108
110
|
if (this.logTime) {
|
|
109
111
|
this.logger.timeEnd(`${this.logPrefix} ${label}`)
|
|
110
112
|
}
|
|
@@ -121,7 +123,7 @@ export class Engine {
|
|
|
121
123
|
*
|
|
122
124
|
* @returns {Promise<STEAK>} The submitted transaction execution acknowledgement
|
|
123
125
|
*/
|
|
124
|
-
async submit
|
|
126
|
+
async submit(taggedBEEF: TaggedBEEF, onSteakReady?: (steak: STEAK) => void, mode: 'historical-tx' | 'current-tx' = 'current-tx', offChainValues?: number[]): Promise<STEAK> {
|
|
125
127
|
for (const t of taggedBEEF.topics) {
|
|
126
128
|
if (this.managers[t] === undefined || this.managers[t] === null) {
|
|
127
129
|
throw new Error(`This server does not support this topic: ${t}`)
|
|
@@ -455,7 +457,7 @@ export class Engine {
|
|
|
455
457
|
* @param LookupQuestion — The question to ask the Overlay Services Engine
|
|
456
458
|
* @returns The answer to the question
|
|
457
459
|
*/
|
|
458
|
-
async lookup
|
|
460
|
+
async lookup(lookupQuestion: LookupQuestion): Promise<LookupAnswer> {
|
|
459
461
|
// Validate a lookup service for the provider is found
|
|
460
462
|
const lookupService = this.lookupServices[lookupQuestion.service]
|
|
461
463
|
if (lookupService === undefined || lookupService === null) throw new Error(`Lookup service not found for provider: ${lookupQuestion.service} `)
|
|
@@ -508,7 +510,7 @@ export class Engine {
|
|
|
508
510
|
* @throws Will throw an error if there are issues during the advertisement synchronization process.
|
|
509
511
|
* @returns {Promise<void>} A promise that resolves when the synchronization process is complete.
|
|
510
512
|
*/
|
|
511
|
-
async syncAdvertisements
|
|
513
|
+
async syncAdvertisements(): Promise<void> {
|
|
512
514
|
if (
|
|
513
515
|
this.advertiser === undefined ||
|
|
514
516
|
typeof this.hostingURL !== 'string' ||
|
|
@@ -520,8 +522,14 @@ export class Engine {
|
|
|
520
522
|
const advertiser = this.advertiser
|
|
521
523
|
|
|
522
524
|
// Step 1: Retrieve Current Configuration
|
|
523
|
-
|
|
524
|
-
|
|
525
|
+
let configuredTopics = Object.keys(this.managers)
|
|
526
|
+
let configuredServices = Object.keys(this.lookupServices)
|
|
527
|
+
|
|
528
|
+
// Filter out default SHIP/SLAP topics/services if suppressDefaultSyncAdvertisements is true
|
|
529
|
+
if (this.suppressDefaultSyncAdvertisements === true) {
|
|
530
|
+
configuredTopics = configuredTopics.filter(topic => topic !== 'tm_ship' && topic !== 'tm_slap')
|
|
531
|
+
configuredServices = configuredServices.filter(service => service !== 'ls_ship' && service !== 'ls_slap')
|
|
532
|
+
}
|
|
525
533
|
|
|
526
534
|
// Step 2: Fetch Existing Advertisements
|
|
527
535
|
const currentSHIPAdvertisements = await advertiser.findAllAdvertisements('SHIP')
|
|
@@ -574,7 +582,7 @@ export class Engine {
|
|
|
574
582
|
*
|
|
575
583
|
* @throws Error if the overlay service engine is not configured for topical synchronization.
|
|
576
584
|
*/
|
|
577
|
-
async startGASPSync
|
|
585
|
+
async startGASPSync(): Promise<void> {
|
|
578
586
|
if (this.syncConfiguration === undefined) {
|
|
579
587
|
throw new Error('Overlay Service Engine not configured for topical synchronization!')
|
|
580
588
|
}
|
|
@@ -636,7 +644,7 @@ export class Engine {
|
|
|
636
644
|
try {
|
|
637
645
|
// Read the last interaction score from storage
|
|
638
646
|
const lastInteraction = await this.storage.getLastInteraction(endpoint, topic)
|
|
639
|
-
|
|
647
|
+
|
|
640
648
|
const gasp = new GASP(
|
|
641
649
|
new OverlayGASPStorage(topic, this),
|
|
642
650
|
new OverlayGASPRemote(endpoint, topic),
|
|
@@ -646,7 +654,7 @@ export class Engine {
|
|
|
646
654
|
true
|
|
647
655
|
)
|
|
648
656
|
await gasp.sync(endpoint, DEFAULT_GASP_SYNC_LIMIT)
|
|
649
|
-
|
|
657
|
+
|
|
650
658
|
// Save the updated last interaction score
|
|
651
659
|
if (gasp.lastInteraction > lastInteraction) {
|
|
652
660
|
await this.storage.updateLastInteraction(endpoint, topic, gasp.lastInteraction)
|
|
@@ -676,7 +684,7 @@ export class Engine {
|
|
|
676
684
|
* @param topic - The topic for which UTXOs are being requested.
|
|
677
685
|
* @returns A promise that resolves to a GASPInitialResponse containing the list of UTXOs and the provided min block height.
|
|
678
686
|
*/
|
|
679
|
-
async provideForeignSyncResponse
|
|
687
|
+
async provideForeignSyncResponse(initialRequest: GASPInitialRequest, topic: string): Promise<GASPInitialResponse> {
|
|
680
688
|
const outputs = await this.storage.findUTXOsForTopic(topic, initialRequest.since, initialRequest.limit)
|
|
681
689
|
|
|
682
690
|
return {
|
|
@@ -698,7 +706,7 @@ export class Engine {
|
|
|
698
706
|
* @returns A promise that resolves to a GASPNode containing the raw transaction and other optional data.
|
|
699
707
|
* @throws An error if no output is found for the given transaction ID and output index.
|
|
700
708
|
*/
|
|
701
|
-
async provideForeignGASPNode
|
|
709
|
+
async provideForeignGASPNode(graphID: string, txid: string, outputIndex: number): Promise<GASPNode> {
|
|
702
710
|
const hydrator = async (output: Output | null): Promise<GASPNode> => {
|
|
703
711
|
if (output?.beef === undefined) {
|
|
704
712
|
throw new Error('No matching output found!')
|
|
@@ -776,7 +784,7 @@ export class Engine {
|
|
|
776
784
|
*
|
|
777
785
|
* @returns {Promise<Output | undefined>} - A promise that resolves to the output history if found, or undefined if not.
|
|
778
786
|
*/
|
|
779
|
-
async getUTXOHistory
|
|
787
|
+
async getUTXOHistory(
|
|
780
788
|
output: Output,
|
|
781
789
|
historySelector?: ((beef: number[], outputIndex: number, currentDepth: number) => Promise<boolean>) | number,
|
|
782
790
|
currentDepth = 0
|
|
@@ -857,7 +865,7 @@ export class Engine {
|
|
|
857
865
|
* @param output - The UTXO to be deleted.
|
|
858
866
|
* @returns {Promise<void>} - A promise that resolves when the deletion process is complete.
|
|
859
867
|
*/
|
|
860
|
-
private async deleteUTXODeep
|
|
868
|
+
private async deleteUTXODeep(output: Output): Promise<void> {
|
|
861
869
|
try {
|
|
862
870
|
// Delete the current output IFF there are no references to it
|
|
863
871
|
if (output.consumedBy.length === 0) {
|
|
@@ -913,7 +921,7 @@ export class Engine {
|
|
|
913
921
|
* @param txid BE hex string double hash of transaction proven by proof.
|
|
914
922
|
* @param proof for txid
|
|
915
923
|
*/
|
|
916
|
-
private updateInputProofs
|
|
924
|
+
private updateInputProofs(tx: Transaction, txid: string, proof: MerklePath): void {
|
|
917
925
|
if (tx.merklePath !== undefined) {
|
|
918
926
|
// Update the merkle path to handle potential reorgs
|
|
919
927
|
tx.merklePath = proof
|
|
@@ -938,7 +946,7 @@ export class Engine {
|
|
|
938
946
|
* @param txid - The txid for which proof is a valid merkle path.
|
|
939
947
|
* @param proof - The merklePath proving txid is a mined transaction hash
|
|
940
948
|
*/
|
|
941
|
-
private async updateMerkleProof
|
|
949
|
+
private async updateMerkleProof(output: Output, txid: string, proof: MerklePath): Promise<void> {
|
|
942
950
|
if (output.beef === undefined) {
|
|
943
951
|
throw new Error('Output must have associated transaction BEEF!')
|
|
944
952
|
}
|
|
@@ -972,7 +980,7 @@ export class Engine {
|
|
|
972
980
|
* @param proof - Merkle proof containing the Merkle path and other relevant data to verify the transaction.
|
|
973
981
|
* @param blockHeight - The block height associated with the incoming merkle proof.
|
|
974
982
|
*/
|
|
975
|
-
async handleNewMerkleProof
|
|
983
|
+
async handleNewMerkleProof(txid: string, proof: MerklePath, blockHeight?: number): Promise<void> {
|
|
976
984
|
const outputs = await this.storage.findOutputsForTransaction(txid, true)
|
|
977
985
|
|
|
978
986
|
if (outputs === undefined || outputs.length === 0) {
|
|
@@ -995,7 +1003,7 @@ export class Engine {
|
|
|
995
1003
|
* @public
|
|
996
1004
|
* @returns {Promise<Record<string, { name: string; shortDescription: string; iconURL?: string; version?: string; informationURL?: string; }>>} - Supported topic managers and their metadata
|
|
997
1005
|
*/
|
|
998
|
-
async listTopicManagers
|
|
1006
|
+
async listTopicManagers(): Promise<Record<string, {
|
|
999
1007
|
name: string
|
|
1000
1008
|
shortDescription: string
|
|
1001
1009
|
iconURL?: string
|
|
@@ -1028,7 +1036,7 @@ export class Engine {
|
|
|
1028
1036
|
* @public
|
|
1029
1037
|
* @returns {Promise<Record<string, { name: string; shortDescription: string; iconURL?: string; version?: string; informationURL?: string; }>>} - Supported lookup services and their metadata
|
|
1030
1038
|
*/
|
|
1031
|
-
async listLookupServiceProviders
|
|
1039
|
+
async listLookupServiceProviders(): Promise<Record<string, {
|
|
1032
1040
|
name: string
|
|
1033
1041
|
shortDescription: string
|
|
1034
1042
|
iconURL?: string
|
|
@@ -1061,7 +1069,7 @@ export class Engine {
|
|
|
1061
1069
|
* @public
|
|
1062
1070
|
* @returns {Promise<string>} - the documentation for the topic manager
|
|
1063
1071
|
*/
|
|
1064
|
-
async getDocumentationForTopicManager
|
|
1072
|
+
async getDocumentationForTopicManager(manager: any): Promise<string> {
|
|
1065
1073
|
const documentation = await this.managers[manager]?.getDocumentation?.()
|
|
1066
1074
|
return documentation !== undefined ? documentation : 'No documentation found!'
|
|
1067
1075
|
}
|
|
@@ -1071,7 +1079,7 @@ export class Engine {
|
|
|
1071
1079
|
* @public
|
|
1072
1080
|
* @returns {Promise<string>} - the documentation for the lookup service
|
|
1073
1081
|
*/
|
|
1074
|
-
async getDocumentationForLookupServiceProvider
|
|
1082
|
+
async getDocumentationForLookupServiceProvider(provider: any): Promise<string> {
|
|
1075
1083
|
const documentation = await this.lookupServices[provider]?.getDocumentation?.()
|
|
1076
1084
|
return documentation !== undefined ? documentation : 'No documentation found!'
|
|
1077
1085
|
}
|
|
@@ -1086,7 +1094,7 @@ export class Engine {
|
|
|
1086
1094
|
* @param url - The URL string to validate
|
|
1087
1095
|
* @returns {boolean} - Returns `false` if the URL violates any of the conditions `true` otherwise
|
|
1088
1096
|
*/
|
|
1089
|
-
private isValidUrl
|
|
1097
|
+
private isValidUrl(url: string): boolean {
|
|
1090
1098
|
try {
|
|
1091
1099
|
const parsedUrl = new URL(url)
|
|
1092
1100
|
|