@bsv/overlay 0.4.1 → 0.4.2
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 +5 -4
- package/dist/cjs/src/Engine.js +18 -8
- package/dist/cjs/src/Engine.js.map +1 -1
- package/dist/cjs/src/GASP/OverlayGASPRemote.js +8 -4
- package/dist/cjs/src/GASP/OverlayGASPRemote.js.map +1 -1
- package/dist/cjs/src/GASP/OverlayGASPStorage.js +25 -20
- package/dist/cjs/src/GASP/OverlayGASPStorage.js.map +1 -1
- package/dist/cjs/src/storage/knex/KnexStorage.js +32 -7
- package/dist/cjs/src/storage/knex/KnexStorage.js.map +1 -1
- package/dist/cjs/src/storage/knex/migrations/2025-06-25-001-gasp-pagination-support.js +43 -0
- package/dist/cjs/src/storage/knex/migrations/2025-06-25-001-gasp-pagination-support.js.map +1 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/Engine.js +17 -10
- package/dist/esm/src/Engine.js.map +1 -1
- package/dist/esm/src/GASP/OverlayGASPRemote.js +2 -1
- package/dist/esm/src/GASP/OverlayGASPRemote.js.map +1 -1
- package/dist/esm/src/GASP/OverlayGASPStorage.js +15 -14
- package/dist/esm/src/GASP/OverlayGASPStorage.js.map +1 -1
- package/dist/esm/src/storage/knex/KnexStorage.js +32 -7
- package/dist/esm/src/storage/knex/KnexStorage.js.map +1 -1
- package/dist/esm/src/storage/knex/migrations/2025-06-25-001-gasp-pagination-support.js +39 -0
- package/dist/esm/src/storage/knex/migrations/2025-06-25-001-gasp-pagination-support.js.map +1 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/Engine.d.ts.map +1 -1
- package/dist/types/src/GASP/OverlayGASPRemote.d.ts +1 -1
- package/dist/types/src/GASP/OverlayGASPRemote.d.ts.map +1 -1
- package/dist/types/src/GASP/OverlayGASPStorage.d.ts +2 -5
- package/dist/types/src/GASP/OverlayGASPStorage.d.ts.map +1 -1
- package/dist/types/src/Output.d.ts +1 -0
- package/dist/types/src/Output.d.ts.map +1 -1
- package/dist/types/src/storage/Storage.d.ts +17 -2
- package/dist/types/src/storage/Storage.d.ts.map +1 -1
- package/dist/types/src/storage/knex/KnexStorage.d.ts +3 -1
- package/dist/types/src/storage/knex/KnexStorage.d.ts.map +1 -1
- package/dist/types/src/storage/knex/migrations/2025-06-25-001-gasp-pagination-support.d.ts +4 -0
- package/dist/types/src/storage/knex/migrations/2025-06-25-001-gasp-pagination-support.d.ts.map +1 -0
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/package.json +5 -4
- package/src/Engine.ts +20 -11
- package/src/GASP/OverlayGASPRemote.ts +3 -2
- package/src/GASP/OverlayGASPStorage.ts +17 -16
- package/src/Output.ts +1 -0
- package/src/__tests/Engine.test.ts +65 -63
- package/src/__tests/OverlayGASPRemote.test.ts +1 -1
- package/src/__tests/OverlayGASPStorage.test.ts +21 -17
- package/src/storage/Storage.ts +19 -2
- package/src/storage/knex/KnexStorage.ts +37 -7
- package/src/storage/knex/migrations/2025-06-25-001-gasp-pagination-support.ts +46 -0
- package/dist/cjs/src/GASP/GASP.js +0 -283
- package/dist/cjs/src/GASP/GASP.js.map +0 -1
- package/dist/esm/src/GASP/GASP.js +0 -288
- package/dist/esm/src/GASP/GASP.js.map +0 -1
- package/dist/types/src/GASP/GASP.d.ts +0 -218
- package/dist/types/src/GASP/GASP.d.ts.map +0 -1
package/src/Engine.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { TopicManager } from './TopicManager.js'
|
|
|
2
2
|
import { LookupService } from './LookupService.js'
|
|
3
3
|
import { Storage } from './storage/Storage.js'
|
|
4
4
|
import type { Output } from './Output.js'
|
|
5
|
-
import { LookupFormula } from './LookupFormula.js'
|
|
6
5
|
import {
|
|
7
6
|
Transaction,
|
|
8
7
|
ChainTracker,
|
|
@@ -25,6 +24,8 @@ import { SyncConfiguration } from './SyncConfiguration.js'
|
|
|
25
24
|
import { OverlayGASPRemote } from './GASP/OverlayGASPRemote.js'
|
|
26
25
|
import { OverlayGASPStorage } from './GASP/OverlayGASPStorage.js'
|
|
27
26
|
|
|
27
|
+
const DEFAULT_GASP_SYNC_LIMIT = 10000
|
|
28
|
+
|
|
28
29
|
/**
|
|
29
30
|
* An engine for running BSV Overlay Services (topic managers and lookup services).
|
|
30
31
|
*/
|
|
@@ -355,7 +356,8 @@ export class Engine {
|
|
|
355
356
|
spent: false,
|
|
356
357
|
beef: taggedBEEF.beef,
|
|
357
358
|
consumedBy: [],
|
|
358
|
-
outputsConsumed
|
|
359
|
+
outputsConsumed,
|
|
360
|
+
score: Date.now()
|
|
359
361
|
})
|
|
360
362
|
this.endTime(`insertNewOutput_${txid.substring(0, 10)}`)
|
|
361
363
|
newUTXOs.push({ txid, outputIndex })
|
|
@@ -632,15 +634,23 @@ export class Engine {
|
|
|
632
634
|
this.logger.info(`[GASP SYNC] Starting sync for topic "${topic}" with peer "${endpoint}"`)
|
|
633
635
|
|
|
634
636
|
try {
|
|
637
|
+
// Read the last interaction score from storage
|
|
638
|
+
const lastInteraction = await this.storage.getLastInteraction(endpoint, topic)
|
|
639
|
+
|
|
635
640
|
const gasp = new GASP(
|
|
636
641
|
new OverlayGASPStorage(topic, this),
|
|
637
642
|
new OverlayGASPRemote(endpoint, topic),
|
|
638
|
-
|
|
643
|
+
lastInteraction,
|
|
639
644
|
`[GASP Sync of ${topic} with ${endpoint}]`,
|
|
640
645
|
true,
|
|
641
646
|
true
|
|
642
647
|
)
|
|
643
|
-
await gasp.sync()
|
|
648
|
+
await gasp.sync(endpoint, DEFAULT_GASP_SYNC_LIMIT)
|
|
649
|
+
|
|
650
|
+
// Save the updated last interaction score
|
|
651
|
+
if (gasp.lastInteraction > lastInteraction) {
|
|
652
|
+
await this.storage.updateLastInteraction(endpoint, topic, gasp.lastInteraction)
|
|
653
|
+
}
|
|
644
654
|
|
|
645
655
|
this.logger.info(`[GASP SYNC] Sync successful for topic "${topic}" with peer "${endpoint}"`)
|
|
646
656
|
} catch (err) {
|
|
@@ -667,15 +677,14 @@ export class Engine {
|
|
|
667
677
|
* @returns A promise that resolves to a GASPInitialResponse containing the list of UTXOs and the provided min block height.
|
|
668
678
|
*/
|
|
669
679
|
async provideForeignSyncResponse (initialRequest: GASPInitialRequest, topic: string): Promise<GASPInitialResponse> {
|
|
670
|
-
const
|
|
680
|
+
const outputs = await this.storage.findUTXOsForTopic(topic, initialRequest.since, initialRequest.limit)
|
|
671
681
|
|
|
672
682
|
return {
|
|
673
|
-
UTXOList:
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
}),
|
|
683
|
+
UTXOList: outputs.map(output => ({
|
|
684
|
+
txid: output.txid,
|
|
685
|
+
outputIndex: output.outputIndex,
|
|
686
|
+
score: output.score ?? 0
|
|
687
|
+
})),
|
|
679
688
|
since: initialRequest.since
|
|
680
689
|
}
|
|
681
690
|
}
|
|
@@ -36,7 +36,8 @@ export class OverlayGASPRemote implements GASPRemote {
|
|
|
36
36
|
return {
|
|
37
37
|
UTXOList: result.UTXOList.map((utxo: any) => ({
|
|
38
38
|
txid: utxo.txid,
|
|
39
|
-
outputIndex: utxo.outputIndex
|
|
39
|
+
outputIndex: utxo.outputIndex,
|
|
40
|
+
score: utxo.score ?? 0
|
|
40
41
|
})),
|
|
41
42
|
since: result.since
|
|
42
43
|
}
|
|
@@ -101,7 +102,7 @@ export class OverlayGASPRemote implements GASPRemote {
|
|
|
101
102
|
|
|
102
103
|
// Only used when supporting bidirectional sync.
|
|
103
104
|
// Overlay services does not support this.
|
|
104
|
-
async submitNode (node: GASPNode): Promise<
|
|
105
|
+
async submitNode (node: GASPNode): Promise<GASPNodeResponse | undefined> {
|
|
105
106
|
throw new Error('Node submission not supported!')
|
|
106
107
|
}
|
|
107
108
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GASPNode, GASPNodeResponse, GASPStorage } from '@bsv/gasp'
|
|
1
|
+
import { GASPNode, GASPNodeResponse, GASPStorage, GASPOutput } from '@bsv/gasp'
|
|
2
2
|
import { MerklePath, Transaction, Utils } from '@bsv/sdk'
|
|
3
3
|
import { Engine } from '../Engine.js'
|
|
4
4
|
|
|
@@ -29,11 +29,12 @@ export class OverlayGASPStorage implements GASPStorage {
|
|
|
29
29
|
* @param since
|
|
30
30
|
* @returns
|
|
31
31
|
*/
|
|
32
|
-
async findKnownUTXOs (since: number): Promise<
|
|
32
|
+
async findKnownUTXOs (since: number): Promise<GASPOutput[]> {
|
|
33
33
|
const UTXOs = await this.engine.storage.findUTXOsForTopic(this.topic, since)
|
|
34
34
|
return UTXOs.map(output => ({
|
|
35
35
|
txid: output.txid,
|
|
36
|
-
outputIndex: output.outputIndex
|
|
36
|
+
outputIndex: output.outputIndex,
|
|
37
|
+
score: output.score ?? 0
|
|
37
38
|
}))
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -80,7 +81,7 @@ export class OverlayGASPStorage implements GASPStorage {
|
|
|
80
81
|
const parsedTx = Transaction.fromHex(tx.rawTx)
|
|
81
82
|
if (tx.proof === undefined) {
|
|
82
83
|
for (const input of parsedTx.inputs) {
|
|
83
|
-
response.requestedInputs[`${input.sourceTXID}.${input.sourceOutputIndex}`] = {
|
|
84
|
+
response.requestedInputs[`${input.sourceTXID ?? ''}.${input.sourceOutputIndex}`] = {
|
|
84
85
|
metadata: false
|
|
85
86
|
}
|
|
86
87
|
}
|
|
@@ -220,12 +221,13 @@ export class OverlayGASPStorage implements GASPStorage {
|
|
|
220
221
|
// For any input to this transaction, see if it's a valid coin that's admitted. If so, it's a previous coin.
|
|
221
222
|
const previousCoins: number[] = []
|
|
222
223
|
const tx = Transaction.fromBEEF(beef)
|
|
223
|
-
for (const inputIndex
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
224
|
+
for (const [inputIndex, input] of tx.inputs.entries()) {
|
|
225
|
+
const sourceTXID = input.sourceTXID ?? input.sourceTransaction?.id('hex')
|
|
226
|
+
if (sourceTXID != null && sourceTXID !== '') {
|
|
227
|
+
const coin = `${sourceTXID}.${input.sourceOutputIndex}`
|
|
228
|
+
if (coins.has(coin)) {
|
|
229
|
+
previousCoins.push(Number(inputIndex))
|
|
230
|
+
}
|
|
229
231
|
}
|
|
230
232
|
}
|
|
231
233
|
const admittanceInstructions = await this.engine.managers[this.topic].identifyAdmissibleOutputs(beef, previousCoins)
|
|
@@ -293,7 +295,7 @@ export class OverlayGASPStorage implements GASPStorage {
|
|
|
293
295
|
|
|
294
296
|
// Start the hydrator with the root node
|
|
295
297
|
const foundRoot = this.temporaryGraphNodeRefs[graphID]
|
|
296
|
-
if (
|
|
298
|
+
if (foundRoot == null) {
|
|
297
299
|
throw new Error('Unable to find root node in graph for finalization!')
|
|
298
300
|
}
|
|
299
301
|
hydrator(foundRoot)
|
|
@@ -309,15 +311,14 @@ export class OverlayGASPStorage implements GASPStorage {
|
|
|
309
311
|
// Given a node, hydrate its merkle proof or all inputs, returning a reference to the hydrated node's Transaction object
|
|
310
312
|
const hydrator = (node: GraphNode): Transaction => {
|
|
311
313
|
const tx = Transaction.fromHex(node.rawTx)
|
|
312
|
-
if (node.proof) {
|
|
314
|
+
if (node.proof != null && node.proof !== '') {
|
|
313
315
|
tx.merklePath = MerklePath.fromHex(node.proof)
|
|
314
316
|
return tx // Transaction with proof, end of the line.
|
|
315
317
|
}
|
|
316
318
|
// For each input, look it up and recurse.
|
|
317
|
-
for (const inputIndex
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
if (!foundNode) {
|
|
319
|
+
for (const [inputIndex, input] of tx.inputs.entries()) {
|
|
320
|
+
const foundNode = this.temporaryGraphNodeRefs[`${input.sourceTXID ?? ''}.${input.sourceOutputIndex}`]
|
|
321
|
+
if (foundNode == null) {
|
|
321
322
|
throw new Error('Required input node for unproven parent not found in temporary graph store. Ensure, for every parent of any given already-proven node (kept for Overlay-specific historical reasons), that a proof is also provided on those inputs. While implicitly they are valid by virtue of their descendents being proven in the blockchain, BEEF serialization will still fail when winding forward the topical UTXO set histories during sync.')
|
|
322
323
|
}
|
|
323
324
|
tx.inputs[inputIndex].sourceTransaction = hydrator(foundNode)
|
package/src/Output.ts
CHANGED
|
@@ -6,13 +6,19 @@ import { Storage } from '../storage/Storage'
|
|
|
6
6
|
import { Transaction, Utils, TaggedBEEF, AdmittanceInstructions, STEAK } from '@bsv/sdk'
|
|
7
7
|
import { Output } from '../Output'
|
|
8
8
|
import { SyncConfiguration } from '../SyncConfiguration'
|
|
9
|
-
import { Advertiser } from '../Advertiser
|
|
9
|
+
import { Advertiser } from '../Advertiser'
|
|
10
10
|
|
|
11
11
|
const mockChainTracker = {
|
|
12
12
|
isValidRootForHeight: jest.fn(async () => true),
|
|
13
13
|
currentHeight: jest.fn(async () => 800000)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
// Call the method that would normally trigger syncAdvertisements
|
|
17
|
+
const engineSubmit = jest.fn(async (taggedBEEF: TaggedBEEF, onSteakReady: any, mode?: string): Promise<STEAK> => {
|
|
18
|
+
const result: STEAK = { tm_helloworld: { outputsToAdmit: [], coinsToRetain: [], coinsRemoved: [] } }
|
|
19
|
+
return result
|
|
20
|
+
})
|
|
21
|
+
|
|
16
22
|
const BRC62Hex = '0100beef01fe636d0c0007021400fe507c0c7aa754cef1f7889d5fd395cf1f785dd7de98eed895dbedfe4e5bc70d1502ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e010b00bc4ff395efd11719b277694cface5aa50d085a0bb81f613f70313acd28cf4557010400574b2d9142b8d28b61d88e3b2c3f44d858411356b49a28a4643b6d1a6a092a5201030051a05fc84d531b5d250c23f4f886f6812f9fe3f402d61607f977b4ecd2701c19010000fd781529d58fc2523cf396a7f25440b409857e7e221766c57214b1d38c7b481f01010062f542f45ea3660f86c013ced80534cb5fd4c19d66c56e7e8c5d4bf2d40acc5e010100b121e91836fd7cd5102b654e9f72f3cf6fdbfd0b161c53a9c54b12c841126331020100000001cd4e4cac3c7b56920d1e7655e7e260d31f29d9a388d04910f1bbd72304a79029010000006b483045022100e75279a205a547c445719420aa3138bf14743e3f42618e5f86a19bde14bb95f7022064777d34776b05d816daf1699493fcdf2ef5a5ab1ad710d9c97bfb5b8f7cef3641210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013e660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000001000100000001ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e000000006a47304402203a61a2e931612b4bda08d541cfb980885173b8dcf64a3471238ae7abcd368d6402204cbf24f04b9aa2256d8901f0ed97866603d2be8324c2bfb7a37bf8fc90edd5b441210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013c660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000000'
|
|
17
23
|
const exampleTX = Transaction.fromHexBEEF(BRC62Hex)
|
|
18
24
|
|
|
@@ -29,7 +35,8 @@ const mockOutput: Output = {
|
|
|
29
35
|
beef: exampleBeef,
|
|
30
36
|
spent: false,
|
|
31
37
|
outputsConsumed: [],
|
|
32
|
-
consumedBy: []
|
|
38
|
+
consumedBy: [],
|
|
39
|
+
score: 1234567890
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
const invalidHostingUrls = [
|
|
@@ -90,7 +97,9 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
90
97
|
updateConsumedBy: jest.fn(),
|
|
91
98
|
updateTransactionBEEF: jest.fn(),
|
|
92
99
|
deleteOutput: jest.fn(),
|
|
93
|
-
findUTXOsForTopic: jest.fn()
|
|
100
|
+
findUTXOsForTopic: jest.fn(),
|
|
101
|
+
updateLastInteraction: jest.fn(),
|
|
102
|
+
getLastInteraction: jest.fn(async () => 0)
|
|
94
103
|
}
|
|
95
104
|
})
|
|
96
105
|
|
|
@@ -109,7 +118,7 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
109
118
|
undefined
|
|
110
119
|
)
|
|
111
120
|
|
|
112
|
-
engine.submit =
|
|
121
|
+
engine.submit = engineSubmit
|
|
113
122
|
|
|
114
123
|
// Call the method that would normally trigger syncAdvertisements
|
|
115
124
|
const result = await engine.syncAdvertisements()
|
|
@@ -148,9 +157,8 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
148
157
|
undefined
|
|
149
158
|
)
|
|
150
159
|
|
|
151
|
-
|
|
152
|
-
engine.
|
|
153
|
-
const result = await engine.syncAdvertisements()
|
|
160
|
+
engine.submit = engineSubmit
|
|
161
|
+
await engine.syncAdvertisements()
|
|
154
162
|
expect(engine.submit).toHaveBeenCalled()
|
|
155
163
|
|
|
156
164
|
// Verify that Advertiser methods are called
|
|
@@ -237,23 +245,12 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
237
245
|
})
|
|
238
246
|
})
|
|
239
247
|
describe('handleNewMerkleProof tests', () => {
|
|
240
|
-
const mockOutput: Output = {
|
|
241
|
-
txid: exampleTXID,
|
|
242
|
-
outputIndex: 0,
|
|
243
|
-
outputScript: exampleTX.outputs[0].lockingScript.toBinary(),
|
|
244
|
-
topic: 'hello',
|
|
245
|
-
satoshis: exampleTX.outputs[0].satoshis,
|
|
246
|
-
beef: exampleBeef,
|
|
247
|
-
spent: false,
|
|
248
|
-
outputsConsumed: [],
|
|
249
|
-
consumedBy: []
|
|
250
|
-
}
|
|
251
248
|
it('0 simple proof', async () => {
|
|
252
|
-
const beef =
|
|
249
|
+
const beef = beef27c8f1
|
|
253
250
|
const txid = txid27c8f
|
|
254
251
|
const tx = Transaction.fromHexBEEF(beef)
|
|
255
252
|
|
|
256
|
-
const
|
|
253
|
+
const output27c8fZero: Output = {
|
|
257
254
|
txid,
|
|
258
255
|
outputIndex: 0,
|
|
259
256
|
outputScript: tx.outputs[0].lockingScript.toBinary(),
|
|
@@ -262,7 +259,8 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
262
259
|
beef: tx.toBEEF(),
|
|
263
260
|
spent: false,
|
|
264
261
|
outputsConsumed: [],
|
|
265
|
-
consumedBy: []
|
|
262
|
+
consumedBy: [],
|
|
263
|
+
score: Date.now()
|
|
266
264
|
}
|
|
267
265
|
|
|
268
266
|
mockLookupService.lookup = jest.fn(async () => [{
|
|
@@ -271,8 +269,8 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
271
269
|
history: 1
|
|
272
270
|
}])
|
|
273
271
|
let newBEEF: number[] = []
|
|
274
|
-
mockStorageEngine.findOutput = jest.fn(async () =>
|
|
275
|
-
mockStorageEngine.findOutputsForTransaction = jest.fn(async () => [
|
|
272
|
+
mockStorageEngine.findOutput = jest.fn(async () => output27c8fZero)
|
|
273
|
+
mockStorageEngine.findOutputsForTransaction = jest.fn(async () => [output27c8fZero])
|
|
276
274
|
mockStorageEngine.updateTransactionBEEF = jest.fn(async (txid: string, beef: number[]) => {
|
|
277
275
|
newBEEF = beef
|
|
278
276
|
})
|
|
@@ -287,8 +285,8 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
287
285
|
mockChainTracker
|
|
288
286
|
)
|
|
289
287
|
|
|
290
|
-
const merklePath = Transaction.fromHexBEEF(
|
|
291
|
-
if (
|
|
288
|
+
const merklePath = Transaction.fromHexBEEF(beef27c8f0).merklePath
|
|
289
|
+
if (merklePath == null) throw new Error('improper test setup')
|
|
292
290
|
await engine.handleNewMerkleProof(txid, merklePath)
|
|
293
291
|
expect(newBEEF.length > 0 && newBEEF.length < beef.length / 2).toBe(true)
|
|
294
292
|
})
|
|
@@ -311,9 +309,10 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
311
309
|
beef: tx.toBEEF(),
|
|
312
310
|
spent: false,
|
|
313
311
|
outputsConsumed: [],
|
|
314
|
-
consumedBy: []
|
|
312
|
+
consumedBy: [],
|
|
313
|
+
score: Date.now()
|
|
315
314
|
}
|
|
316
|
-
if (consumes) {
|
|
315
|
+
if (consumes != null) {
|
|
317
316
|
const c = findOutput(consumes.txid, consumes.outputIndex)
|
|
318
317
|
c.consumedBy.push(o)
|
|
319
318
|
o.outputsConsumed.push(c)
|
|
@@ -346,52 +345,52 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
346
345
|
txid a7d4cac391f5b3d8dedaacb3cd8b5afac54df2d8e043ae0452abcfe190686494 output 17 1132 sats
|
|
347
346
|
*/
|
|
348
347
|
|
|
349
|
-
const tx17d182 = Transaction.fromHexBEEF(
|
|
348
|
+
const tx17d182 = Transaction.fromHexBEEF(beef17d1824)
|
|
350
349
|
const tx942620 = tx17d182.inputs[0].sourceTransaction
|
|
351
350
|
const tx509f5e = tx942620.inputs[0].sourceTransaction
|
|
352
351
|
const tx877734 = tx509f5e.inputs[0].sourceTransaction
|
|
353
352
|
const tx37abad = tx877734.inputs[0].sourceTransaction
|
|
354
353
|
|
|
355
|
-
const
|
|
356
|
-
const
|
|
357
|
-
const
|
|
358
|
-
const
|
|
359
|
-
|
|
354
|
+
const output37abadZero = addConsumingOutput(tx37abad, 0)
|
|
355
|
+
const output877734Zero = addConsumingOutput(tx877734, 0, output37abadZero)
|
|
356
|
+
const output509f5eZero = addConsumingOutput(tx509f5e, 0, output877734Zero)
|
|
357
|
+
const output942620Zero = addConsumingOutput(tx942620, 0, output509f5eZero)
|
|
358
|
+
addConsumingOutput(tx17d182, 0, output942620Zero)
|
|
360
359
|
|
|
361
|
-
const mp37abad = Transaction.fromHexBEEF(
|
|
360
|
+
const mp37abad = Transaction.fromHexBEEF(beef37abad0).merklePath
|
|
362
361
|
await engine.handleNewMerkleProof(txid37abad, mp37abad)
|
|
363
362
|
expect(Object.keys(newBEEF).length).toBe(0)
|
|
364
363
|
|
|
365
|
-
const mp877734 = Transaction.fromHexBEEF(
|
|
364
|
+
const mp877734 = Transaction.fromHexBEEF(beef8777340).merklePath
|
|
366
365
|
await engine.handleNewMerkleProof(txid877734, mp877734)
|
|
367
|
-
expect(newBEEF[`${txid877734}`]).toBe(
|
|
368
|
-
expect(newBEEF[`${txid509f5e}`].length).toBeGreaterThan(
|
|
369
|
-
expect(newBEEF[`${txid942620}`].length).toBeGreaterThan(
|
|
370
|
-
expect(newBEEF[`${txid17d182}`].length).toBeGreaterThan(
|
|
366
|
+
expect(newBEEF[`${txid877734}`]).toBe(beef8777340)
|
|
367
|
+
expect(newBEEF[`${txid509f5e}`].length).toBeGreaterThan(beef509f5e0.length)
|
|
368
|
+
expect(newBEEF[`${txid942620}`].length).toBeGreaterThan(beef9426200.length)
|
|
369
|
+
expect(newBEEF[`${txid17d182}`].length).toBeGreaterThan(beef17d1820.length)
|
|
371
370
|
expect(Object.keys(newBEEF).length).toBe(4)
|
|
372
371
|
|
|
373
|
-
const mp509f5e = Transaction.fromHexBEEF(
|
|
372
|
+
const mp509f5e = Transaction.fromHexBEEF(beef509f5e0).merklePath
|
|
374
373
|
await engine.handleNewMerkleProof(txid509f5e, mp509f5e)
|
|
375
|
-
expect(newBEEF[`${txid877734}`]).toBe(
|
|
376
|
-
expect(newBEEF[`${txid509f5e}`]).toBe(
|
|
377
|
-
expect(newBEEF[`${txid942620}`].length).toBeGreaterThan(
|
|
378
|
-
expect(newBEEF[`${txid17d182}`].length).toBeGreaterThan(
|
|
374
|
+
expect(newBEEF[`${txid877734}`]).toBe(beef8777340)
|
|
375
|
+
expect(newBEEF[`${txid509f5e}`]).toBe(beef509f5e0)
|
|
376
|
+
expect(newBEEF[`${txid942620}`].length).toBeGreaterThan(beef9426200.length)
|
|
377
|
+
expect(newBEEF[`${txid17d182}`].length).toBeGreaterThan(beef17d1820.length)
|
|
379
378
|
expect(Object.keys(newBEEF).length).toBe(4)
|
|
380
379
|
|
|
381
|
-
const mp942620 = Transaction.fromHexBEEF(
|
|
380
|
+
const mp942620 = Transaction.fromHexBEEF(beef9426200).merklePath
|
|
382
381
|
await engine.handleNewMerkleProof(txid942620, mp942620)
|
|
383
|
-
expect(newBEEF[`${txid877734}`]).toBe(
|
|
384
|
-
expect(newBEEF[`${txid509f5e}`]).toBe(
|
|
385
|
-
expect(newBEEF[`${txid942620}`]).toBe(
|
|
386
|
-
expect(newBEEF[`${txid17d182}`].length).toBeGreaterThan(
|
|
382
|
+
expect(newBEEF[`${txid877734}`]).toBe(beef8777340)
|
|
383
|
+
expect(newBEEF[`${txid509f5e}`]).toBe(beef509f5e0)
|
|
384
|
+
expect(newBEEF[`${txid942620}`]).toBe(beef9426200)
|
|
385
|
+
expect(newBEEF[`${txid17d182}`].length).toBeGreaterThan(beef17d1820.length)
|
|
387
386
|
expect(Object.keys(newBEEF).length).toBe(4)
|
|
388
387
|
|
|
389
|
-
const mp17d182 = Transaction.fromHexBEEF(
|
|
388
|
+
const mp17d182 = Transaction.fromHexBEEF(beef17d1820).merklePath
|
|
390
389
|
await engine.handleNewMerkleProof(txid17d182, mp17d182)
|
|
391
|
-
expect(newBEEF[`${txid877734}`]).toBe(
|
|
392
|
-
expect(newBEEF[`${txid509f5e}`]).toBe(
|
|
393
|
-
expect(newBEEF[`${txid942620}`]).toBe(
|
|
394
|
-
expect(newBEEF[`${txid17d182}`]).toBe(
|
|
390
|
+
expect(newBEEF[`${txid877734}`]).toBe(beef8777340)
|
|
391
|
+
expect(newBEEF[`${txid509f5e}`]).toBe(beef509f5e0)
|
|
392
|
+
expect(newBEEF[`${txid942620}`]).toBe(beef9426200)
|
|
393
|
+
expect(newBEEF[`${txid17d182}`]).toBe(beef17d1820)
|
|
395
394
|
expect(Object.keys(newBEEF).length).toBe(4)
|
|
396
395
|
})
|
|
397
396
|
})
|
|
@@ -631,7 +630,10 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
631
630
|
topics: ['hello']
|
|
632
631
|
})
|
|
633
632
|
// Test the new UTXO was added
|
|
634
|
-
expect(mockStorageEngine.insertOutput).toHaveBeenCalledWith(
|
|
633
|
+
expect(mockStorageEngine.insertOutput).toHaveBeenCalledWith(expect.objectContaining({
|
|
634
|
+
...mockOutput,
|
|
635
|
+
score: expect.any(Number)
|
|
636
|
+
}))
|
|
635
637
|
})
|
|
636
638
|
it('Notifies lookup services about incoming admissible UTXOs', async () => {
|
|
637
639
|
// Mock findUTXO to return a UTXO
|
|
@@ -1137,9 +1139,9 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
1137
1139
|
})
|
|
1138
1140
|
|
|
1139
1141
|
// beef27c8f_1 is 1 level deep, i.e. proofs on inputs
|
|
1140
|
-
const
|
|
1142
|
+
const beef27c8f1 = '0100beef01feafcf0c000802020044ef36fc6c79af360b13f2164c6e772e6e5e2083a54d72894f34710fe6a68cf80302792c8c563b17721744d8f101d79e873aae62816d0fd47dd9d90ada219c1b252d010000059e83aae2cfc6a35477566439dd9d58969cc41a134864c671c9b844f2a409a60101004991c129bba819832d6dd315c3a2065bd31b1a60aff8192be335f83731641e690101002f87724a7387df82417902266d2a4fb2fee857451e963a352ce8acbb279aa9eb010100a9e9eb55d20cef840bacbdb26ad8d6e7680ef7653364830b1e770fa140ece6bb010100f0ecd03fff2df21b0034d331cade50152781be9052dcec54eb95c963ef1cdcbf0101006fdb2c01a266e761a32f53b3ad0fabbca31ae234d31d85d9af9bbd624b321c9b0101008108cad77aabf7b0ee371f42afd773cada534244535f7108c7590df2b9d5f8a2020100000006e9847b33c5d666ccee1dccd52235489d8d58bf432be1b8c0cc7c13af80f10703030000006b483045022100fe8a18e043d693246a56c9b32ff553bea89a0bbe389bc55e8244044dcd865de3022065245c30fbbcc6820e4761048ed28c587bf41ece1933dfb85b8fa8c3433d93504121022f2ac22e73a55aa4ff21e905f66959200642ae74716544f834a48af5aa53fb27ffffffff7e8823d7e3e5565fdb9e53c015ad5b63bc6dd6ee1a9be7f7a8e105c903783d45050000006b483045022100e6332a6459350ff2486a39b6d79cdc0b65b6d52cf898fc457e45880c0db01b2a02206e34126bc81e6f03c6de90278788d6b2be3a3f5d7bd85e6442bbea90b8a5e2394121029780a1a98be5ff17a3228feb830e3bc32395ebecc5cf6de08f7a5685faf66c07ffffffff7e8823d7e3e5565fdb9e53c015ad5b63bc6dd6ee1a9be7f7a8e105c903783d45040000006b483045022100dfba71c6c33d2366b2202ea136271fd2f3a26c0a7295f6dd6018fbe12fc48708022052387ca532247bbfffef4b076fd2fbbdebe85b3cf53c73004897cd07be5d1ad6412103f735eb69c9f0b3c90dd2798b709e12a5b3d176a4690bd2a31ec616af9ecd47b5ffffffff7e8823d7e3e5565fdb9e53c015ad5b63bc6dd6ee1a9be7f7a8e105c903783d45020000006b483045022100f941b74c5da1e7f0ce4d1c08745e4d6b8ef56656199505caeff4b74f54890cec02201eaa0d01112497c89ebe4818687c5f3305629a83abd3b0bf5135feee68f57ca0412103fb0ec51f9e6e45b213cb1deff921e3322624cfb6d4a4ba5dc699867cf163b736ffffffff7e8823d7e3e5565fdb9e53c015ad5b63bc6dd6ee1a9be7f7a8e105c903783d45030000006a47304402205a3a2848350fdc19cae73243bea16dfc1e8fbbd5cecde4b5c88a57790505cebb022043db51d04998d52ec394d0e945a76e9922dd63caffb882242bec2ced2a35c7f1412102bae3e2f47dceaed7db2a212e059a00674a0087e3395b92d9f12cdbefdbc84efaffffffffad49b6f41125ffadab03cb2dcc24caf2c897c2cd4aed6e0a3b5c003f2dde757a030000006b483045022100aa7aaec7fc6c5a2f4d5318b7fcbbca0f223c5c198f8fc0e1c8d59aee7155af1202207a4960fb58aa86eba12852f84fa3cdb4c427c7374fe737b3d5bcd9e2a6d76e3b412102b55cfd872e85b3dd424dcceafe01ed5a87dfb599d354ab7fc50d9ec48af77f6effffffff1a400d0300000000001976a914f182138abcb69c7c2339040605aa0a442cfec44288acc8000000000000001976a914e9d2276f468223a6d650672ab9d4c1271fb157e288acacb00000000000001976a914c0ea0208a097df8146933ae15f3ce545d5451e7388ac7a140000000000001976a9142d9ae3291f9393639fe2c38c9a7a948d136a10b488acea070000000000001976a91435d1c396b7ccb467118a41c2d77ebf79fb5fb7eb88ac17050000000000001976a9140dac1e2ddc975ee6d9f393e2ccd4876edb386cdd88ac51060000000000001976a91422878cb2f57a1ebe513815562003128f6e99eda188ac67040000000000001976a91439a752923ba1ef8b126ba7886646d58f54521c6588ac1e040000000000001976a914a939565af52d3fa974a040f42c35365d76b98f6a88acec030000000000001976a914c90823a53e29cafd35a225cc14e3a44eda143a5788ac05040000000000001976a914af6f8d6aaec3bf123efc17c8977bfad1ec1c859388acec030000000000001976a914d4c5e66a062e634be1c6f0eb1f2af0acebecb47988acf1030000000000001976a914a94a3e84bd740095ab39bed110cd3b3922c8595088ace8030000000000001976a914aa2e3c3bf6f3ee79f5af3b94eab2be60a394ce4c88aceb030000000000001976a91459394fa083ff3726571c79624dba3b38f14d924c88ace8030000000000001976a914726eb3ae6211711aa1624f3d767035b0b44abdc488ace8030000000000001976a9145f4680a099a6dc6891af3094aaab96aa66a6259888ace8030000000000001976a914f1a4fbd99e3923b0934abdb8839c337eb2fd50b888ace8030000000000001976a9147ed0ad307f5fe9993f984e7525c0012e3569594588ace8030000000000001976a91407f386bcdc4892cc2d0be3226b721ceaf04750b288ace8030000000000001976a914b51edaaa3c92d0af94109d952c7ddf13aa345f9988ace8030000000000001976a914018f4e02bd74f17a75f5b3965db4633ab514c57588ace8030000000000001976a914cc8d1f7ba5406b81efbc23da0fcccb4d3fe5b40a88ace8030000000000001976a914db1d4b7bd3e62f535dc3f2c8d0a989b000fa736d88ace8030000000000001976a914b8ea69358da7bea9506b15db6fc6597b3849b0a188ace8030000000000001976a914ecd769fdd67e04786e871c50c1a10504861bd79488ac0000000001000100000001792c8c563b17721744d8f101d79e873aae62816d0fd47dd9d90ada219c1b252d070000006b48304502210090368b5925795abb0415a3cd6265d7abae7d3541fb7f2fdb1fdffdd916b3fce3022068136da44df8ee367807c7c59c950ea8d428adfe142268cd6371cf4c1b4c3208412102858ea1804708d1e16e77b49ba1559b3742797f5f43efd3922fa3d21557521d7cffffffff03f401000000000000fde10121026afd108ddbc05e093207ebdf06557a3d66e15b96accbf1766c2e7d6efa3d1981ac22313852713463583334356b6a7461734467764b41455a435135564c5a72516f76786d2081d846bcae65ce281829b6d81eff3862a68b8eaf4e99ad97c0c4ad2e149631c020f936ace2d2b4034710dec819e343f69ddbb1a16d721b88413b697c2475f75f504c4e8470062e6966cb7ec80864e5e1217ecf2b3f113bb5307e1ec1d338678e54b426a11a267e990f7dcd85072c7b3870fabb54812d7f8a7aaa672ce01e4f8a2c6a1d532849877329bd23be0b3383fcb437ffd1ff05aad824343bfe5bae52d5775ed99ba9d5a72038dd50f81153e674a8b1c5d659aac361e660cc5657b291eda149de2505efb0bbac0a353331393633353238334c797f3040f01934bb25733d4700a0309194a7defd8ceea7a8a59ad279c6237e2917264a115773777c5746546288b15ec1cf6788b801dd3952fec804cadbba2ff4e05464735e2db83c3509b59119efc843716c34becd2884f011f2e7f61f382237891875115b6ea5bac1c3e9ca6c575b44547d589c38c1b5a8cadb463044022016e1fdb226b465f3151aaa1e033b122dd58f3b495d2846d532f784ec8f6fc9ae022031dc12155c02e7f588c9f6d975a79c9c26cf341c1c88578cd6a87a3c01f6a73d6d6d6d6dc8000000000000001976a914010b7bfa8ff585b6d95f8a18a998cbd87508bd4188aca9010000000000001976a914254c6f1ce67d27ae4dafb03d2ba08318df2883c588ac0000000000'
|
|
1141
1143
|
// beef27c8f_0 is 0 levels deep, i.e. tx has merklePath
|
|
1142
|
-
const
|
|
1144
|
+
const beef27c8f0 = '0100beef01fef4f10c000902fd020100ab2d9b3bbfc2ecf5c834f7719bf10dcabef31cfa3b78fa714bd3a2b3958fc6b5fd0301029515629d935d81e704ca97b8dc02a698c39d78f06bbb3d8d46bcaa5178f3c827018000fc94b1da08b5d0850afcc4948a9e129a2c2c0bb629090ca84fef5d326ceadbc2014100fa78356192a22189dd3c2a03bfb2e043667a55a85386a8d0f0853bbaa54ba748012100e37888006acc37cbfc6a459117c3e957b00e8ff3a90d93bc9aaa3fc9d972453701110052564e444cbe4b1f24015d91f5cfd7eff63e5f403613a7b48e77efa32761f950010900acef65445ef232f1fcb527bab67fccc90ae9d0c610a4f752d84c5e10a3415d74010500e1fadd176551150808ae96ff2b4dff487c432788d23db25fd3fb5e8b3e16b96f0103003e530f146a992ed9378807fa43bc1e6033de0711d728ee3a0ea1507b5ffff2940100006c8eca8a9d680ab2ae4dc1f0e247f282de3f32b99175e6f9ddb4f8e76ae0bf1b010100000001792c8c563b17721744d8f101d79e873aae62816d0fd47dd9d90ada219c1b252d070000006b48304502210090368b5925795abb0415a3cd6265d7abae7d3541fb7f2fdb1fdffdd916b3fce3022068136da44df8ee367807c7c59c950ea8d428adfe142268cd6371cf4c1b4c3208412102858ea1804708d1e16e77b49ba1559b3742797f5f43efd3922fa3d21557521d7cffffffff03f401000000000000fde10121026afd108ddbc05e093207ebdf06557a3d66e15b96accbf1766c2e7d6efa3d1981ac22313852713463583334356b6a7461734467764b41455a435135564c5a72516f76786d2081d846bcae65ce281829b6d81eff3862a68b8eaf4e99ad97c0c4ad2e149631c020f936ace2d2b4034710dec819e343f69ddbb1a16d721b88413b697c2475f75f504c4e8470062e6966cb7ec80864e5e1217ecf2b3f113bb5307e1ec1d338678e54b426a11a267e990f7dcd85072c7b3870fabb54812d7f8a7aaa672ce01e4f8a2c6a1d532849877329bd23be0b3383fcb437ffd1ff05aad824343bfe5bae52d5775ed99ba9d5a72038dd50f81153e674a8b1c5d659aac361e660cc5657b291eda149de2505efb0bbac0a353331393633353238334c797f3040f01934bb25733d4700a0309194a7defd8ceea7a8a59ad279c6237e2917264a115773777c5746546288b15ec1cf6788b801dd3952fec804cadbba2ff4e05464735e2db83c3509b59119efc843716c34becd2884f011f2e7f61f382237891875115b6ea5bac1c3e9ca6c575b44547d589c38c1b5a8cadb463044022016e1fdb226b465f3151aaa1e033b122dd58f3b495d2846d532f784ec8f6fc9ae022031dc12155c02e7f588c9f6d975a79c9c26cf341c1c88578cd6a87a3c01f6a73d6d6d6d6dc8000000000000001976a914010b7bfa8ff585b6d95f8a18a998cbd87508bd4188aca9010000000000001976a914254c6f1ce67d27ae4dafb03d2ba08318df2883c588ac000000000100'
|
|
1143
1145
|
// full txid
|
|
1144
1146
|
const txid27c8f = '27c8f37851aabc468d3dbb6bf0789dc398a602dcb897ca04e7815d939d621595'
|
|
1145
1147
|
|
|
@@ -1153,13 +1155,13 @@ const txid27c8f = '27c8f37851aabc468d3dbb6bf0789dc398a602dcb897ca04e7815d939d621
|
|
|
1153
1155
|
txid a7d4cac391f5b3d8dedaacb3cd8b5afac54df2d8e043ae0452abcfe190686494 output 17 1132 sats
|
|
1154
1156
|
*/
|
|
1155
1157
|
const txid17d182 = '17d1829ba8424b97369ee8b528ee8b65d9d4b9c08d037d224a7be7c025f78f78'
|
|
1156
|
-
const
|
|
1157
|
-
const
|
|
1158
|
+
const beef17d1820 = '0100beef01feaff60c000c02fd660302788ff725c0e77b4a227d038dc0b9d4d9658bee28b5e89e36974b42a89b82d117fd670300fe2b9c31ae10a15803f91f63df0cf6a5b6771db9dd831e5bc37a36460a1ffa0701fdb201009bf0e3a5854c4b4c8d62c0ade2754ae1bbc0f16a3e49251ed964486b8dc387f101d80003ae2ec810744139e9989e4f36d8f5ebb160981481e68647890d11e3dda971fa016d0081efcddc14858ead1f427f235d2b21c8de43e33bfeb155ed79f666dd4dd490c2013700a6a847f6e264cfa64c0b6aad6b74912c63c6fc89728be813d104abd2724b98a5011a0062c7d393b9518b05d2d0891ae8c2cd840c93e051d2944bb8e651c976301c4e50010c008d8ee79c1a042cf43f4dcd880aeb4ff7f54552cd3a4c9a40c72cc16ed6847cee01070050194d11d12eddf5e56926b28778f0f64ad54e79eb4df4ce7834ddfc57bf882d010200bd66a0cdbb0af933166931b1050dd108e02d76cff19afd614e681fcbdf1be0740100008b36364159630b47b4c27f6e1e056e820b0aa350ab5dde2520fc1753129b628c010100cab620ac48bb55de40c8c5ddb62bbc44c907fbf5d882326d427f4cd4b34334800101001163b76c2c6824c07a53af2ea86da1b1d946340d9377d3b9b84560e074aea3a6010100000001d75744af67fa32a56ba0256a818e23747133cca140926eb65b1eb00310202694000000006a473044022027137acdeb7583e966a9e8825c9f5edb909b2fd46d40e6ee83846d164529630e0220644e82a46d813fac2836650ce832cdba7eb46b6c134982b36e84f5f08a921dbb412102b963cd9b5a1419c041a4c4ac46f5205a2b8cb691cd5633e5d498ddcf3d37460b0000000001ac040000000000001976a914ae0545a670c6f739f9a8963aee37be95df0d9b2a88ac000000000100'
|
|
1159
|
+
const beef17d1824 = '0100beef01fedcee0c000d02f8020954d485defac354e5fc826434eaf6ee4f3a81969f0f7d104e7dd46871adab37f900fa225908f222f8f7f291731a10e93cdf410189ca01adc688edf5577552aa8ff2017d006cfea8ad6ace7ecce9bbbe729eb9dca25f9be064b150d290588c3364867ee112013f00bfbacc8bfdda7f734c160fcfee972dd9182aede73290367aab62b5ce242e5655011e007a0eb94f2bcf98489247a01551a843d9cf1e091522c32f50ce347ba5057b439d010e00beb857ba543d2bd199e68c63a480c73b83660eca27d2ce105355741f27017876010600d5fb1ea8440e41b4ffde093dd53d6ed741c4fe4fe66ff43f6a4eb9af3c6ddebb010200169db3be130a9e8aff1dbff39abee477d3a224cb3e118c39794bb7ba427b707501000083cd0ce2d2734835c45331cd06f38556cf4e07634d599f59692ad9980175a7f201010022f4a629e99ca5838f56f87b050bdefa9b9f621c08745cb27b941d9c6750d99a01010032b90a4148ff984b0efee309a578cb87d278142c014f1a7fd5351b3e3cd4c7da01010082dc3ea570250357fca88652ee1628928136c29eb4910b7e5627e0ffef1d958a010100f5194f41c28960f0dba669f4715229f59f59afb5d55f50a2a7556111b8da67130101009cd7f9a65014cc6fd5c0b71391d0b70eb983ea3b03a2fbd7a13150775855953405010000000237c2148f306355078cedfe61c8574f393476a43abd2cee5b31f1c73e39db86d7000000006a47304402207ee089c64fa810ad88e03f7bad4ae57c9b7de215d222a5bf52f9259d171b717a0220643d3cb4423b5b7ffcb7b2b59eb81dede0a25319aaa0228d27e59d5e238c35a2412102641b5a033ce332a9fc0f81dee7948c099b194758d8352bd5572988ac760ae2faffffffff94646890e1cfab5204ae43e0d8f24dc5fa5a8bcdb3acdaded8b3f591c3cad4a7110000006a47304402205b92eaba4a6c029385e9cf291631b98d0c7aa6851755fb44279e2b1ebd12759702206e96f3bac252f2c5cf5edf7f8828d6358baaa9fe34aa163faeb9b31aac830e47412102577e2a3877a253d9e7587c3d77a4038b4af5e51113393c2713c6d50c9da5de6effffffff03b0040000000000001976a914ae0545a670c6f739f9a8963aee37be95df0d9b2a88acc8000000000000001976a914292e61672fc24a9a70cfa6f73a9af5655652629d88ac13050000000000001976a914ad2ab55d09559074e41e2a2c1c89742e13bee03088ac00000000010001000000010954d485defac354e5fc826434eaf6ee4f3a81969f0f7d104e7dd46871adab37000000006b4830450221009c67deb38aa6b5ed8bfa140e9464e1b1ee2908a296bb70e3d164725254491c6a02207b595dcced1136c276edfc1e5e5901279cf6f0a6432e4c1a908468262e7d9543412102b963cd9b5a1419c041a4c4ac46f5205a2b8cb691cd5633e5d498ddcf3d37460b0000000001af040000000000001976a914ae0545a670c6f739f9a8963aee37be95df0d9b2a88ac00000000000100000001c5b2a279b9b1fec42846b9d6ed7cf6345b08dcdd4b4a17e2d017b98edb347787000000006b483045022100c0992a684be99a07bc87e03bf88701acefc033c1aa57cf4a3b15253e64c8962a022031d5b3af1684a1a1a201eb16fc1fbca8522ae16b9c0d340e8bec48eeea1fe458412102b963cd9b5a1419c041a4c4ac46f5205a2b8cb691cd5633e5d498ddcf3d37460b0000000001ae040000000000001976a914ae0545a670c6f739f9a8963aee37be95df0d9b2a88ac00000000000100000001e9d6dc3084dca9606fe43406208a8dcbba568f60671ee2df4f50189cf75e9f50000000006b483045022100c9c8baa777fe09c1310788614d4eba88b6027d39eada18a5a79c6a33e55919c302205222961b1f63dddd425cd418571797cb3a68aa59ac37331c0fc61fc9de66c34d412102b963cd9b5a1419c041a4c4ac46f5205a2b8cb691cd5633e5d498ddcf3d37460b0000000001ad040000000000001976a914ae0545a670c6f739f9a8963aee37be95df0d9b2a88ac00000000000100000001d75744af67fa32a56ba0256a818e23747133cca140926eb65b1eb00310202694000000006a473044022027137acdeb7583e966a9e8825c9f5edb909b2fd46d40e6ee83846d164529630e0220644e82a46d813fac2836650ce832cdba7eb46b6c134982b36e84f5f08a921dbb412102b963cd9b5a1419c041a4c4ac46f5205a2b8cb691cd5633e5d498ddcf3d37460b0000000001ac040000000000001976a914ae0545a670c6f739f9a8963aee37be95df0d9b2a88ac0000000000'
|
|
1158
1160
|
const txid942620 = '9426201003b01e5bb66e9240a1cc337174238e816a25a06ba532fa67af4457d7'
|
|
1159
|
-
const
|
|
1161
|
+
const beef9426200 = '0100beef01fe07ef0c0008022802d75744af67fa32a56ba0256a818e23747133cca140926eb65b1eb00310202694290089598873694014f9706b6074a1b349fcf59df875e58a0cf3a8900c6e5830f33601150036fffb4b882171c594a27d37c5d7827cc706811c3e0acd152e0f3ee1c7ac98f9010b002b3b5c611cbea3bbdf9e99646cb23e80b62fc2dc2e619656157296878d46d8b30104002877b6b97c95fd55c0584d0ccf683c9ad6c60be146dd73605b93ef042da648a0010300d1d01ac14f19d974f8131b9cdb38ae2abcf5403d5c3f0d2772a1c995c136356b01000017ece09932fa7c6d464c633df200003c2328beb26290c7b9b1333eb84c90c544010100cd4147f92f226bc39354a78209db1f521ffd8720e3fcc9c942ee1dd535513d0f0101005daeb3f84528a58700c58c8479f29cd627b07c198602b6c08033340262c0c607010100000001e9d6dc3084dca9606fe43406208a8dcbba568f60671ee2df4f50189cf75e9f50000000006b483045022100c9c8baa777fe09c1310788614d4eba88b6027d39eada18a5a79c6a33e55919c302205222961b1f63dddd425cd418571797cb3a68aa59ac37331c0fc61fc9de66c34d412102b963cd9b5a1419c041a4c4ac46f5205a2b8cb691cd5633e5d498ddcf3d37460b0000000001ad040000000000001976a914ae0545a670c6f739f9a8963aee37be95df0d9b2a88ac000000000100'
|
|
1160
1162
|
const txid509f5e = '509f5ef79c18504fdfe21e67608f56bacb8d8a200634e46f60a9dc8430dcd6e9'
|
|
1161
|
-
const
|
|
1163
|
+
const beef509f5e0 = '0100beef01fe05ef0c0009029800fb09f12f5632f7af6409432fc914d1e68fc499270fa29f3b3c43fb00ebeb8ed09902e9d6dc3084dca9606fe43406208a8dcbba568f60671ee2df4f50189cf75e9f50014d00ccb4f6ea2fabdfaf86b0e3837cc702ddde19cb5112e680f00832330b03be1d290127000480365544cd4dca6262cc25567f241d650339773f3f9ef1b9a25b9a034945c30112004ab6bdfecf74af1da1e0574671d06aef63dcde80133d1a6c46beda2ad08abc15010800ce75abf88ee3de3e2f89be0462e1cb0b9470b67947b9880e941bb6565a44bc86010500940d69edc69fc8694485452b961b8df8a2e0c1ff7bdbfeee1e6855542a7e7cd10103002217abcbd7e5431fffc0f52624ee3cf659e39734ae5335d5d196193f7f6e39ab01000082d3a59ca910a1c6fc1f06ab2a5ea80ffee7a39d9a987c85701cfaaf604219f80101008bed85ed818e9d69147000e8687b2efed77e5ee0073e5a2640033715747bd0c2010100000001c5b2a279b9b1fec42846b9d6ed7cf6345b08dcdd4b4a17e2d017b98edb347787000000006b483045022100c0992a684be99a07bc87e03bf88701acefc033c1aa57cf4a3b15253e64c8962a022031d5b3af1684a1a1a201eb16fc1fbca8522ae16b9c0d340e8bec48eeea1fe458412102b963cd9b5a1419c041a4c4ac46f5205a2b8cb691cd5633e5d498ddcf3d37460b0000000001ae040000000000001976a914ae0545a670c6f739f9a8963aee37be95df0d9b2a88ac000000000100'
|
|
1162
1164
|
const txid877734 = '877734db8eb917d0e2174a4bdddc085b34f67cedd6b94628c4feb1b979a2b2c5'
|
|
1163
|
-
const
|
|
1165
|
+
const beef8777340 = '0100beef01fedfee0c000e02fd202900eeebd665d8893249c90dabbd50266fb7e0f125dd8ee087a3c8089debf09499d4fd212902c5b2a279b9b1fec42846b9d6ed7cf6345b08dcdd4b4a17e2d017b98edb34778701fd911400b32e903076f6869d4e0a9fa2d00f5c8bad598d3ede5b4bafef88debdb1d3de6901fd490a000a79573c8eb909d30c4e9653f90ea2869e44220d551da81cc96913b2fcd734aa01fd2505003d6db6b39d889be1535a478da0c3428e8107872ac55f0fcfdd2225b6a402d1dc01fd9302008ae31e7e4d4e766814ea11b337b5b51f5d807737f802c44c8d0d75a583a61bde01fd480100e962a171fcc0e79bf55b1433d79564f8d3b2622ecbcb84c9ede792d353e0afb901a5007d0a8d8a3a2f0eb209e82f5e80ef6c4835b7d07c85d6ac8c613cc8754a47bd79015300b070576d92310f1e08a12581ecea4d1d4de48beb15ff7e42eddc1b957fa2909d012800544a58cac6b4dd78cebd84178dc1572693552fec5777a055dad0068bd67aec6101150025674a887fff026640fe9851cbffb37bd8e02780c4f6c0476ed3cee4e4884c2f010b0023aa2b01e8a59c3b79976918d95ae6a044ace2264e3690f9846f452499c0cbad01040078033c2619a3b115bfc71d09addf13e288660be1841cf6769ffb9924aca246970103004d2d6ae3e2c02703b773c49af789b7372b5b71bf92b49e2dc4b921880df984540100003b86537a85e5047596a482ac2dba30d1798b26d200c08a2fb19d8d75b2c2a1b50101000000010954d485defac354e5fc826434eaf6ee4f3a81969f0f7d104e7dd46871adab37000000006b4830450221009c67deb38aa6b5ed8bfa140e9464e1b1ee2908a296bb70e3d164725254491c6a02207b595dcced1136c276edfc1e5e5901279cf6f0a6432e4c1a908468262e7d9543412102b963cd9b5a1419c041a4c4ac46f5205a2b8cb691cd5633e5d498ddcf3d37460b0000000001af040000000000001976a914ae0545a670c6f739f9a8963aee37be95df0d9b2a88ac000000000100'
|
|
1164
1166
|
const txid37abad = '37abad7168d47d4e107d0f9f96813a4feef6ea346482fce554c3fade85d45409'
|
|
1165
|
-
const
|
|
1167
|
+
const beef37abad0 = '0100beef01fedcee0c000d02f8020954d485defac354e5fc826434eaf6ee4f3a81969f0f7d104e7dd46871adab37f900fa225908f222f8f7f291731a10e93cdf410189ca01adc688edf5577552aa8ff2017d006cfea8ad6ace7ecce9bbbe729eb9dca25f9be064b150d290588c3364867ee112013f00bfbacc8bfdda7f734c160fcfee972dd9182aede73290367aab62b5ce242e5655011e007a0eb94f2bcf98489247a01551a843d9cf1e091522c32f50ce347ba5057b439d010e00beb857ba543d2bd199e68c63a480c73b83660eca27d2ce105355741f27017876010600d5fb1ea8440e41b4ffde093dd53d6ed741c4fe4fe66ff43f6a4eb9af3c6ddebb010200169db3be130a9e8aff1dbff39abee477d3a224cb3e118c39794bb7ba427b707501000083cd0ce2d2734835c45331cd06f38556cf4e07634d599f59692ad9980175a7f201010022f4a629e99ca5838f56f87b050bdefa9b9f621c08745cb27b941d9c6750d99a01010032b90a4148ff984b0efee309a578cb87d278142c014f1a7fd5351b3e3cd4c7da01010082dc3ea570250357fca88652ee1628928136c29eb4910b7e5627e0ffef1d958a010100f5194f41c28960f0dba669f4715229f59f59afb5d55f50a2a7556111b8da67130101009cd7f9a65014cc6fd5c0b71391d0b70eb983ea3b03a2fbd7a13150775855953401010000000237c2148f306355078cedfe61c8574f393476a43abd2cee5b31f1c73e39db86d7000000006a47304402207ee089c64fa810ad88e03f7bad4ae57c9b7de215d222a5bf52f9259d171b717a0220643d3cb4423b5b7ffcb7b2b59eb81dede0a25319aaa0228d27e59d5e238c35a2412102641b5a033ce332a9fc0f81dee7948c099b194758d8352bd5572988ac760ae2faffffffff94646890e1cfab5204ae43e0d8f24dc5fa5a8bcdb3acdaded8b3f591c3cad4a7110000006a47304402205b92eaba4a6c029385e9cf291631b98d0c7aa6851755fb44279e2b1ebd12759702206e96f3bac252f2c5cf5edf7f8828d6358baaa9fe34aa163faeb9b31aac830e47412102577e2a3877a253d9e7587c3d77a4038b4af5e51113393c2713c6d50c9da5de6effffffff03b0040000000000001976a914ae0545a670c6f739f9a8963aee37be95df0d9b2a88acc8000000000000001976a914292e61672fc24a9a70cfa6f73a9af5655652629d88ac13050000000000001976a914ad2ab55d09559074e41e2a2c1c89742e13bee03088ac000000000100'
|
|
@@ -22,7 +22,7 @@ describe('OverlayGASPRemote', () => {
|
|
|
22
22
|
it('should send a request and return a valid response', async () => {
|
|
23
23
|
const mockRequest: GASPInitialRequest = { version: 1, since: 0 }
|
|
24
24
|
const mockResponse: GASPInitialResponse = {
|
|
25
|
-
UTXOList: [{ txid: 'txid1', outputIndex: 0 }],
|
|
25
|
+
UTXOList: [{ txid: 'txid1', outputIndex: 0, score: 0 }],
|
|
26
26
|
since: 1234567890
|
|
27
27
|
};
|
|
28
28
|
|
|
@@ -30,7 +30,8 @@ describe('OverlayGASPStorage', () => {
|
|
|
30
30
|
|
|
31
31
|
it('throws error when max nodes are exceeded', async () => {
|
|
32
32
|
overlayStorage.maxNodesInGraph = 1
|
|
33
|
-
|
|
33
|
+
const graphNode: GraphNode = { txid: 'txid123', children: [], rawTx: '', graphID: 'txid4321.2', outputIndex: 0 }
|
|
34
|
+
overlayStorage.temporaryGraphNodeRefs['txid123.0'] = graphNode
|
|
34
35
|
|
|
35
36
|
const mockTx = {
|
|
36
37
|
rawTx: '334455',
|
|
@@ -44,12 +45,15 @@ describe('OverlayGASPStorage', () => {
|
|
|
44
45
|
|
|
45
46
|
describe('findKnownUTXOs', () => {
|
|
46
47
|
it('should return known UTXOs since a given timestamp', async () => {
|
|
47
|
-
const mockUTXOs = [{ txid: 'txid1', outputIndex: 0 }, { txid: 'txid2', outputIndex: 1 }]
|
|
48
|
+
const mockUTXOs = [{ txid: 'txid1', outputIndex: 0, score: 0 }, { txid: 'txid2', outputIndex: 1, score: 0 }]
|
|
48
49
|
mockEngine.storage.findUTXOsForTopic.mockResolvedValue(mockUTXOs)
|
|
49
50
|
|
|
50
51
|
const result = await overlayStorage.findKnownUTXOs(1234567890)
|
|
51
52
|
|
|
52
|
-
expect(result).toEqual(
|
|
53
|
+
expect(result).toEqual([
|
|
54
|
+
{ txid: 'txid1', outputIndex: 0, score: 0 },
|
|
55
|
+
{ txid: 'txid2', outputIndex: 1, score: 0 }
|
|
56
|
+
])
|
|
53
57
|
expect(mockEngine.storage.findUTXOsForTopic).toHaveBeenCalledWith('test-topic', 1234567890)
|
|
54
58
|
})
|
|
55
59
|
|
|
@@ -125,32 +129,32 @@ describe('OverlayGASPStorage', () => {
|
|
|
125
129
|
|
|
126
130
|
describe('discardGraph', () => {
|
|
127
131
|
it('should discard the graph and its nodes', async () => {
|
|
128
|
-
|
|
132
|
+
const graphNode1: GraphNode = {
|
|
129
133
|
txid: 'txid123',
|
|
130
|
-
time: Date.now(),
|
|
131
134
|
graphID: 'txid123.0',
|
|
132
135
|
rawTx: 'rawTxData',
|
|
133
136
|
outputIndex: 0,
|
|
134
137
|
children: [],
|
|
135
138
|
parent: undefined
|
|
136
|
-
}
|
|
139
|
+
}
|
|
140
|
+
overlayStorage.temporaryGraphNodeRefs['txid123.0'] = graphNode1
|
|
137
141
|
|
|
138
|
-
|
|
142
|
+
const parentNode: GraphNode = {
|
|
143
|
+
txid: 'txid123',
|
|
144
|
+
graphID: 'txid123.0',
|
|
145
|
+
rawTx: 'rawTxData',
|
|
146
|
+
outputIndex: 0,
|
|
147
|
+
children: []
|
|
148
|
+
}
|
|
149
|
+
const graphNode2: GraphNode = {
|
|
139
150
|
txid: 'txid124',
|
|
140
|
-
time: Date.now(),
|
|
141
151
|
graphID: 'txid123.0',
|
|
142
152
|
rawTx: 'rawTxData',
|
|
143
153
|
outputIndex: 1,
|
|
144
154
|
children: [],
|
|
145
|
-
parent:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
graphID: 'txid123.0',
|
|
149
|
-
rawTx: 'rawTxData',
|
|
150
|
-
outputIndex: 0,
|
|
151
|
-
children: []
|
|
152
|
-
} as GraphNode
|
|
153
|
-
} as GraphNode
|
|
155
|
+
parent: parentNode
|
|
156
|
+
}
|
|
157
|
+
overlayStorage.temporaryGraphNodeRefs['txid124.0'] = graphNode2
|
|
154
158
|
|
|
155
159
|
await overlayStorage.discardGraph('txid123.0')
|
|
156
160
|
|
package/src/storage/Storage.ts
CHANGED
|
@@ -38,10 +38,11 @@ export interface Storage {
|
|
|
38
38
|
/**
|
|
39
39
|
* Finds current UTXOs that have been admitted into a given topic
|
|
40
40
|
* @param topic - The topic for which we want to find Unspent Transaction Outputs (UTXOs).
|
|
41
|
-
* @param since - Optional parameter indicating the minimum
|
|
41
|
+
* @param since - Optional parameter indicating the minimum score value to retrieve matching UTXOs from. This is used for score-based filtering.
|
|
42
|
+
* @param limit - Optional parameter to limit the number of results returned
|
|
42
43
|
* @returns A promise that resolves to an array of matching UTXOs.
|
|
43
44
|
*/
|
|
44
|
-
findUTXOsForTopic: (topic: string, since?: number, includeBEEF?: boolean) => Promise<Output[]>
|
|
45
|
+
findUTXOsForTopic: (topic: string, since?: number, limit?: number, includeBEEF?: boolean) => Promise<Output[]>
|
|
45
46
|
|
|
46
47
|
/**
|
|
47
48
|
* Deletes an output from storage
|
|
@@ -99,4 +100,20 @@ export interface Storage {
|
|
|
99
100
|
* @returns Whether the transaction is already applied
|
|
100
101
|
*/
|
|
101
102
|
doesAppliedTransactionExist: (tx: AppliedTransaction) => Promise<boolean>
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Updates the last interaction score for a given host and topic
|
|
106
|
+
* @param host — The host identifier
|
|
107
|
+
* @param topic — The topic for which to update the interaction score
|
|
108
|
+
* @param since — The score value to store
|
|
109
|
+
*/
|
|
110
|
+
updateLastInteraction: (host: string, topic: string, since: number) => Promise<void>
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Retrieves the last interaction score for a given host and topic
|
|
114
|
+
* @param host — The host identifier
|
|
115
|
+
* @param topic — The topic to query
|
|
116
|
+
* @returns The last interaction score, or 0 if not found
|
|
117
|
+
*/
|
|
118
|
+
getLastInteraction: (host: string, topic: string) => Promise<number>
|
|
102
119
|
}
|