@bsv/overlay 0.1.27 → 0.2.0
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 +3 -3
- package/dist/cjs/src/Engine.js +95 -13
- package/dist/cjs/src/Engine.js.map +1 -1
- package/dist/cjs/src/GASP/OverlayGASPRemote.js.map +1 -1
- package/dist/cjs/src/GASP/OverlayGASPStorage.js +1 -1
- package/dist/cjs/src/GASP/OverlayGASPStorage.js.map +1 -1
- package/dist/cjs/src/storage/knex/KnexStorage.js.map +1 -1
- package/dist/cjs/src/storage/knex/migrations/2024-05-18-001-initial.js.map +1 -1
- package/dist/cjs/src/storage/knex/migrations/2024-07-10-001-block-height.js.map +1 -1
- package/dist/cjs/src/storage/knex/migrations/2024-07-17-001-transactions.js.map +1 -1
- package/dist/cjs/src/storage/knex/migrations/2024-07-18-001-indexes.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/Engine.js +93 -12
- package/dist/esm/src/Engine.js.map +1 -1
- package/dist/esm/src/GASP/OverlayGASPRemote.js.map +1 -1
- package/dist/esm/src/GASP/OverlayGASPStorage.js +1 -1
- package/dist/esm/src/GASP/OverlayGASPStorage.js.map +1 -1
- package/dist/esm/src/storage/knex/KnexStorage.js.map +1 -1
- package/dist/esm/src/storage/knex/migrations/2024-05-18-001-initial.js.map +1 -1
- package/dist/esm/src/storage/knex/migrations/2024-07-10-001-block-height.js.map +1 -1
- package/dist/esm/src/storage/knex/migrations/2024-07-17-001-transactions.js.map +1 -1
- package/dist/esm/src/storage/knex/migrations/2024-07-18-001-indexes.js.map +1 -1
- 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.map +1 -1
- package/dist/types/src/LookupService.d.ts +67 -48
- package/dist/types/src/LookupService.d.ts.map +1 -1
- package/dist/types/src/Output.d.ts +2 -2
- package/dist/types/src/Output.d.ts.map +1 -1
- package/dist/types/src/storage/Storage.d.ts.map +1 -1
- package/dist/types/src/storage/knex/KnexStorage.d.ts.map +1 -1
- package/dist/types/src/storage/knex/all-migrations.d.ts +2 -2
- package/dist/types/src/storage/knex/all-migrations.d.ts.map +1 -1
- package/dist/types/src/storage/knex/migrations/2024-05-18-001-initial.d.ts.map +1 -1
- package/dist/types/src/storage/knex/migrations/2024-07-10-001-block-height.d.ts.map +1 -1
- package/dist/types/src/storage/knex/migrations/2024-07-17-001-transactions.d.ts.map +1 -1
- package/dist/types/src/storage/knex/migrations/2024-07-18-001-indexes.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/Engine.ts +139 -61
- package/src/GASP/OverlayGASPRemote.ts +6 -6
- package/src/GASP/OverlayGASPStorage.ts +17 -17
- package/src/LookupService.ts +112 -49
- package/src/Output.ts +1 -1
- package/src/__tests/Engine.test.ts +38 -29
- package/src/storage/Storage.ts +0 -1
- package/src/storage/knex/KnexStorage.ts +12 -12
- package/src/storage/knex/all-migrations.ts +1 -1
- package/src/storage/knex/migrations/2024-05-18-001-initial.ts +2 -2
- package/src/storage/knex/migrations/2024-07-10-001-block-height.ts +2 -2
- package/src/storage/knex/migrations/2024-07-17-001-transactions.ts +2 -2
- package/src/storage/knex/migrations/2024-07-18-001-indexes.ts +2 -2
package/src/LookupService.ts
CHANGED
|
@@ -1,68 +1,131 @@
|
|
|
1
1
|
import { LookupFormula } from './LookupFormula.js'
|
|
2
|
-
import { LookupQuestion, LookupAnswer
|
|
2
|
+
import { Script, LookupQuestion, LookupAnswer } from '@bsv/sdk'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
*/
|
|
4
|
+
/* ---------------------------------------------------------------------------
|
|
5
|
+
* Modes a Lookup Service may request from the Overlay Services Engine
|
|
6
|
+
* -------------------------------------------------------------------------- */
|
|
7
|
+
export type AdmissionMode = 'locking-script' | 'whole-tx'
|
|
8
|
+
export type SpendNotificationMode = 'none' | 'txid' | 'script' | 'whole-tx'
|
|
9
|
+
|
|
10
|
+
/* ---------------------------------------------------------------------------
|
|
11
|
+
* Admission-Notification payloads
|
|
12
|
+
* -------------------------------------------------------------------------- */
|
|
13
|
+
export type OutputAdmittedByTopic =
|
|
14
|
+
| { // «locking-script» mode
|
|
15
|
+
mode: 'locking-script'
|
|
16
|
+
txid: string // ID of the *admitted* transaction
|
|
17
|
+
outputIndex: number // index of admitted output
|
|
18
|
+
topic: string // topic into which it was admitted
|
|
19
|
+
satoshis: number // value of the output
|
|
20
|
+
lockingScript: Script // script in this output
|
|
21
|
+
}
|
|
22
|
+
| { // «whole-tx» mode
|
|
23
|
+
mode: 'whole-tx'
|
|
24
|
+
atomicBEEF: number[] // whole transaction (Atomic BEEF)
|
|
25
|
+
outputIndex: number
|
|
26
|
+
topic: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* ---------------------------------------------------------------------------
|
|
30
|
+
* Spend-Notification payloads
|
|
31
|
+
* -------------------------------------------------------------------------- */
|
|
32
|
+
export type OutputSpent =
|
|
33
|
+
| { // «none» – “it was spent”
|
|
34
|
+
mode: 'none'
|
|
35
|
+
txid: string
|
|
36
|
+
outputIndex: number
|
|
37
|
+
topic: string
|
|
38
|
+
}
|
|
39
|
+
| { // «txid» – pointer only
|
|
40
|
+
mode: 'txid'
|
|
41
|
+
txid: string
|
|
42
|
+
outputIndex: number
|
|
43
|
+
topic: string
|
|
44
|
+
spendingTxid: string
|
|
45
|
+
}
|
|
46
|
+
| { // «script» – granular input data
|
|
47
|
+
mode: 'script'
|
|
48
|
+
txid: string
|
|
49
|
+
outputIndex: number
|
|
50
|
+
topic: string
|
|
51
|
+
spendingTxid: string
|
|
52
|
+
inputIndex: number
|
|
53
|
+
unlockingScript: Script
|
|
54
|
+
sequenceNumber: number
|
|
55
|
+
}
|
|
56
|
+
| { // «whole-tx» – full spending TX
|
|
57
|
+
mode: 'whole-tx'
|
|
58
|
+
txid: string
|
|
59
|
+
outputIndex: number
|
|
60
|
+
topic: string
|
|
61
|
+
spendingAtomicBEEF: number[]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* ---------------------------------------------------------------------------
|
|
65
|
+
* Metadata structure returned by getMetaData()
|
|
66
|
+
* -------------------------------------------------------------------------- */
|
|
67
|
+
export interface LookupServiceMetaData {
|
|
68
|
+
name: string
|
|
69
|
+
shortDescription: string
|
|
70
|
+
iconURL?: string
|
|
71
|
+
version?: string
|
|
72
|
+
informationURL?: string
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* ---------------------------------------------------------------------------
|
|
76
|
+
* Lookup Service Interface
|
|
77
|
+
* -------------------------------------------------------------------------- */
|
|
7
78
|
export interface LookupService {
|
|
79
|
+
/* -------------------------------------------------------------------------
|
|
80
|
+
* REQUIRED static declarations
|
|
81
|
+
* ----------------------------------------------------------------------- */
|
|
82
|
+
readonly admissionMode: AdmissionMode
|
|
83
|
+
readonly spendNotificationMode: SpendNotificationMode
|
|
8
84
|
|
|
85
|
+
/* -------------------------------------------------------------------------
|
|
86
|
+
* REQUIRED lifecycle hooks
|
|
87
|
+
* ----------------------------------------------------------------------- */
|
|
9
88
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @param outputIndex - The index of the transaction output (UTXO) within the transaction.
|
|
13
|
-
* @param outputScript - The script associated with the transaction output.
|
|
14
|
-
* @param topic - The topic to which the new UTXO is being added.
|
|
15
|
-
* @returns A promise that resolves when the processing of the new UTXO is complete.
|
|
89
|
+
* Invoked when a Topic Manager admits a new UTXO.
|
|
90
|
+
* The payload shape depends on this.admissionMode.
|
|
16
91
|
*/
|
|
17
|
-
|
|
92
|
+
outputAdmittedByTopic: (payload: OutputAdmittedByTopic) => Promise<void> | void
|
|
18
93
|
|
|
19
94
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* @param txid - The transaction ID of the spent UTXO.
|
|
23
|
-
* @param outputIndex - The index of the transaction output that was spent.
|
|
24
|
-
* @param topic - The topic from which the UTXO was spent.
|
|
25
|
-
*
|
|
26
|
-
* @returns A promise that resolves when processing is complete.
|
|
95
|
+
* Invoked when a previously-admitted UTXO is spent.
|
|
96
|
+
* The payload shape depends on this.spendNotificationMode.
|
|
27
97
|
*/
|
|
28
|
-
outputSpent?: (
|
|
98
|
+
outputSpent?: (payload: OutputSpent) => Promise<void> | void
|
|
29
99
|
|
|
30
100
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* @param txid - The transaction ID of the deleted UTXO.
|
|
34
|
-
* @param outputIndex - The index of the transaction output that was deleted.
|
|
35
|
-
* @param topic - The topic from which the UTXO was deleted.
|
|
36
|
-
*
|
|
37
|
-
* @returns A promise that resolves when processing is complete.
|
|
101
|
+
* Called when a Topic Manager decides that **historical retention** of the
|
|
102
|
+
* specified UTXO is no longer required.
|
|
38
103
|
*/
|
|
39
|
-
|
|
104
|
+
outputNoLongerRetainedInHistory?: (
|
|
105
|
+
txid: string,
|
|
106
|
+
outputIndex: number,
|
|
107
|
+
topic: string
|
|
108
|
+
) => Promise<void> | void
|
|
40
109
|
|
|
41
110
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
111
|
+
* LEGAL EVICTION:
|
|
112
|
+
* Permanently remove the referenced UTXO from all indices maintained by the
|
|
113
|
+
* Lookup Service. After eviction the service MUST NOT reference the output
|
|
114
|
+
* in any future lookup answer.
|
|
45
115
|
*/
|
|
116
|
+
outputEvicted: (
|
|
117
|
+
txid: string,
|
|
118
|
+
outputIndex: number
|
|
119
|
+
) => Promise<void> | void
|
|
120
|
+
|
|
121
|
+
/* -------------------------------------------------------------------------
|
|
122
|
+
* Query API
|
|
123
|
+
* ----------------------------------------------------------------------- */
|
|
46
124
|
lookup: (question: LookupQuestion) => Promise<LookupAnswer | LookupFormula>
|
|
47
125
|
|
|
48
|
-
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* @returns A promise that resolves to a documentation string.
|
|
52
|
-
*/
|
|
126
|
+
/* -------------------------------------------------------------------------
|
|
127
|
+
* Documentation helpers
|
|
128
|
+
* ----------------------------------------------------------------------- */
|
|
53
129
|
getDocumentation: () => Promise<string>
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Returns a metadata object that can be used to identify the lookup service.
|
|
57
|
-
*
|
|
58
|
-
* @returns A promise that resolves to a metadata object containing the name, short description,
|
|
59
|
-
* and optional properties such as icon URL, version, and information URL.
|
|
60
|
-
*/
|
|
61
|
-
getMetaData: () => Promise<{
|
|
62
|
-
name: string
|
|
63
|
-
shortDescription: string
|
|
64
|
-
iconURL?: string
|
|
65
|
-
version?: string
|
|
66
|
-
informationURL?: string
|
|
67
|
-
}>
|
|
130
|
+
getMetaData: () => Promise<LookupServiceMetaData>
|
|
68
131
|
}
|
package/src/Output.ts
CHANGED
|
@@ -25,7 +25,7 @@ const mockOutput: Output = {
|
|
|
25
25
|
outputIndex: 0,
|
|
26
26
|
outputScript: exampleTX.outputs[0].lockingScript.toBinary(),
|
|
27
27
|
topic: 'hello',
|
|
28
|
-
satoshis: exampleTX.outputs[0].satoshis
|
|
28
|
+
satoshis: exampleTX.outputs[0].satoshis,
|
|
29
29
|
beef: exampleBeef,
|
|
30
30
|
spent: false,
|
|
31
31
|
outputsConsumed: [],
|
|
@@ -33,20 +33,19 @@ const mockOutput: Output = {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
const invalidHostingUrls = [
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
'http://example.com', // Invalid: http
|
|
37
|
+
'https://localhost:3000', // Invalid: localhost
|
|
38
|
+
'https://192.168.1.1', // Invalid: internal private IP
|
|
39
|
+
'https://127.0.0.1', // Invalid: loopback IP
|
|
40
|
+
'https://0.0.0.0', // Invalid: non-routable IP
|
|
41
|
+
'http://172.16.0.1', // Invalid: private IP
|
|
42
|
+
'[::1]'
|
|
43
43
|
]
|
|
44
44
|
|
|
45
|
-
|
|
46
45
|
const validHostingUrls = [
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
'https://example.com', // Valid: public URL
|
|
47
|
+
'https://8.8.8.8', // Valid: public routable IP
|
|
48
|
+
'https://255.255.255.255' // Valid: public routable IP
|
|
50
49
|
]
|
|
51
50
|
|
|
52
51
|
const mockAdvertiser: Advertiser = {
|
|
@@ -70,10 +69,13 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
mockLookupService = {
|
|
73
|
-
|
|
72
|
+
outputAdmittedByTopic: jest.fn(),
|
|
74
73
|
outputSpent: jest.fn(),
|
|
75
74
|
lookup: jest.fn(),
|
|
76
|
-
|
|
75
|
+
outputNoLongerRetainedInHistory: jest.fn(),
|
|
76
|
+
outputEvicted: jest.fn(),
|
|
77
|
+
admissionMode: 'locking-script',
|
|
78
|
+
spendNotificationMode: 'none',
|
|
77
79
|
getDocumentation: async () => 'Service Documentation',
|
|
78
80
|
getMetaData: async () => ({ name: 'Mock Service', shortDescription: 'Mock Short Service Description' })
|
|
79
81
|
}
|
|
@@ -107,7 +109,7 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
107
109
|
undefined
|
|
108
110
|
)
|
|
109
111
|
|
|
110
|
-
engine.submit = jest.fn(async (taggedBEEF: TaggedBEEF, onSteakReady: any, mode?: string) => ({
|
|
112
|
+
engine.submit = jest.fn(async (taggedBEEF: TaggedBEEF, onSteakReady: any, mode?: string) => ({ tm_helloworld: { outputsToAdmit: [], coinsToRetain: [], coinsRemoved: [] } } as STEAK))
|
|
111
113
|
|
|
112
114
|
// Call the method that would normally trigger syncAdvertisements
|
|
113
115
|
const result = await engine.syncAdvertisements()
|
|
@@ -128,8 +130,8 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
128
130
|
parseAdvertisement: jest.fn().mockReturnValue({
|
|
129
131
|
protocol: 'SHIP',
|
|
130
132
|
topicOrServiceName: 'mock-topic',
|
|
131
|
-
timestamp: Date.now()
|
|
132
|
-
})
|
|
133
|
+
timestamp: Date.now()
|
|
134
|
+
})
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
for (const url of validHostingUrls) {
|
|
@@ -147,7 +149,7 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
147
149
|
)
|
|
148
150
|
|
|
149
151
|
// Call the method that would normally trigger syncAdvertisements
|
|
150
|
-
engine.submit = jest.fn(async (taggedBEEF: TaggedBEEF, onSteakReady: any, mode?: string) => ({
|
|
152
|
+
engine.submit = jest.fn(async (taggedBEEF: TaggedBEEF, onSteakReady: any, mode?: string) => ({ tm_helloworld: { outputsToAdmit: [], coinsToRetain: [], coinsRemoved: [] } } as STEAK))
|
|
151
153
|
const result = await engine.syncAdvertisements()
|
|
152
154
|
expect(engine.submit).toHaveBeenCalled()
|
|
153
155
|
|
|
@@ -240,7 +242,7 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
240
242
|
outputIndex: 0,
|
|
241
243
|
outputScript: exampleTX.outputs[0].lockingScript.toBinary(),
|
|
242
244
|
topic: 'hello',
|
|
243
|
-
satoshis: exampleTX.outputs[0].satoshis
|
|
245
|
+
satoshis: exampleTX.outputs[0].satoshis,
|
|
244
246
|
beef: exampleBeef,
|
|
245
247
|
spent: false,
|
|
246
248
|
outputsConsumed: [],
|
|
@@ -305,7 +307,7 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
305
307
|
outputIndex,
|
|
306
308
|
outputScript: tx.outputs[outputIndex].lockingScript.toBinary(),
|
|
307
309
|
topic: 'hello',
|
|
308
|
-
satoshis: tx.outputs[outputIndex].satoshis
|
|
310
|
+
satoshis: tx.outputs[outputIndex].satoshis,
|
|
309
311
|
beef: tx.toBEEF(),
|
|
310
312
|
spent: false,
|
|
311
313
|
outputsConsumed: [],
|
|
@@ -554,7 +556,12 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
554
556
|
beef: exampleBeef,
|
|
555
557
|
topics: ['Hello']
|
|
556
558
|
})
|
|
557
|
-
expect(engine.lookupServices.Hello.outputSpent).toHaveBeenCalledWith(
|
|
559
|
+
expect(engine.lookupServices.Hello.outputSpent).toHaveBeenCalledWith({
|
|
560
|
+
mode: 'none',
|
|
561
|
+
txid: exampleTXID,
|
|
562
|
+
outputIndex: 0,
|
|
563
|
+
topic: 'Hello'
|
|
564
|
+
})
|
|
558
565
|
})
|
|
559
566
|
})
|
|
560
567
|
describe('When previous UTXOs were not retained by the topic manager', () => {
|
|
@@ -579,7 +586,7 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
579
586
|
})
|
|
580
587
|
// Test that previous UTXOs are deleted
|
|
581
588
|
expect(mockStorageEngine.deleteOutput).toHaveBeenCalledWith(exampleTXID, 0, 'hello')
|
|
582
|
-
expect(mockLookupService.
|
|
589
|
+
expect(mockLookupService.outputNoLongerRetainedInHistory).toHaveBeenCalledWith(exampleTXID, 0, 'hello')
|
|
583
590
|
})
|
|
584
591
|
it('Notifies all lookup services about the output being spent (the notification about the actual deletion will come from deleteUTXODeep)', async () => {
|
|
585
592
|
// Mock findUTXO to return a UTXO
|
|
@@ -601,7 +608,7 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
601
608
|
topics: ['Hello']
|
|
602
609
|
})
|
|
603
610
|
// Was the lookup service notified of the output deletion?
|
|
604
|
-
expect(mockLookupService.
|
|
611
|
+
expect(mockLookupService.outputNoLongerRetainedInHistory).toHaveBeenCalledWith(exampleTXID, 0, 'hello')
|
|
605
612
|
})
|
|
606
613
|
})
|
|
607
614
|
it('Adds admissible UTXOs to the storage engine', async () => {
|
|
@@ -646,12 +653,14 @@ describe('BSV Overlay Services Engine', () => {
|
|
|
646
653
|
topics: ['Hello']
|
|
647
654
|
})
|
|
648
655
|
// Test the lookup service was notified of the new UTXO
|
|
649
|
-
expect(mockLookupService.
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
656
|
+
expect(mockLookupService.outputAdmittedByTopic).toHaveBeenCalledWith({
|
|
657
|
+
mode: 'locking-script',
|
|
658
|
+
txid: exampleTXID,
|
|
659
|
+
satoshis: 26172,
|
|
660
|
+
outputIndex: 0,
|
|
661
|
+
lockingScript: exampleTX.outputs[0].lockingScript,
|
|
662
|
+
topic: 'Hello'
|
|
663
|
+
})
|
|
655
664
|
})
|
|
656
665
|
describe('For each consumed UTXO', () => {
|
|
657
666
|
it('Finds the UTXO', async () => {
|
package/src/storage/Storage.ts
CHANGED
|
@@ -5,11 +5,11 @@ import type { Output } from '../../Output.js'
|
|
|
5
5
|
export class KnexStorage implements Storage {
|
|
6
6
|
knex: Knex
|
|
7
7
|
|
|
8
|
-
constructor(knex: Knex) {
|
|
8
|
+
constructor (knex: Knex) {
|
|
9
9
|
this.knex = knex
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
async findOutput(txid: string, outputIndex: number, topic?: string, spent?: boolean, includeBEEF: boolean = false): Promise<Output | null> {
|
|
12
|
+
async findOutput (txid: string, outputIndex: number, topic?: string, spent?: boolean, includeBEEF: boolean = false): Promise<Output | null> {
|
|
13
13
|
const search: {
|
|
14
14
|
'outputs.txid': string
|
|
15
15
|
'outputs.outputIndex': number
|
|
@@ -59,7 +59,7 @@ export class KnexStorage implements Storage {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
async findOutputsForTransaction(txid: string, includeBEEF: boolean = false): Promise<Output[]> {
|
|
62
|
+
async findOutputsForTransaction (txid: string, includeBEEF: boolean = false): Promise<Output[]> {
|
|
63
63
|
// Base query to get outputs
|
|
64
64
|
const query = this.knex('outputs').where({ 'outputs.txid': txid })
|
|
65
65
|
|
|
@@ -97,7 +97,7 @@ export class KnexStorage implements Storage {
|
|
|
97
97
|
}))
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
async findUTXOsForTopic(topic: string, since?: number, includeBEEF: boolean = false): Promise<Output[]> {
|
|
100
|
+
async findUTXOsForTopic (topic: string, since?: number, includeBEEF: boolean = false): Promise<Output[]> {
|
|
101
101
|
// Base query to get outputs
|
|
102
102
|
const query = this.knex('outputs').where({ 'outputs.topic': topic, 'outputs.spent': false })
|
|
103
103
|
|
|
@@ -141,7 +141,7 @@ export class KnexStorage implements Storage {
|
|
|
141
141
|
}))
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
async deleteOutput(txid: string, outputIndex: number, topic: string): Promise<void> {
|
|
144
|
+
async deleteOutput (txid: string, outputIndex: number, topic: string): Promise<void> {
|
|
145
145
|
await this.knex.transaction(async trx => {
|
|
146
146
|
// Delete the specific output
|
|
147
147
|
await trx('outputs').where({ txid, outputIndex }).del()
|
|
@@ -156,7 +156,7 @@ export class KnexStorage implements Storage {
|
|
|
156
156
|
})
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
async insertOutput(output: Output): Promise<void> {
|
|
159
|
+
async insertOutput (output: Output): Promise<void> {
|
|
160
160
|
const insertPromises = [this.knex('outputs').insert({
|
|
161
161
|
txid: output.txid,
|
|
162
162
|
outputIndex: Number(output.outputIndex),
|
|
@@ -181,7 +181,7 @@ export class KnexStorage implements Storage {
|
|
|
181
181
|
})
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
async markUTXOAsSpent(txid: string, outputIndex: number, topic?: string): Promise<void> {
|
|
184
|
+
async markUTXOAsSpent (txid: string, outputIndex: number, topic?: string): Promise<void> {
|
|
185
185
|
await this.knex('outputs').where({
|
|
186
186
|
txid,
|
|
187
187
|
outputIndex,
|
|
@@ -189,7 +189,7 @@ export class KnexStorage implements Storage {
|
|
|
189
189
|
}).update('spent', true)
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
async updateConsumedBy(txid: string, outputIndex: number, topic: string, consumedBy: Array<{ txid: string, outputIndex: number }>): Promise<void> {
|
|
192
|
+
async updateConsumedBy (txid: string, outputIndex: number, topic: string, consumedBy: Array<{ txid: string, outputIndex: number }>): Promise<void> {
|
|
193
193
|
await this.knex('outputs').where({
|
|
194
194
|
txid,
|
|
195
195
|
outputIndex,
|
|
@@ -197,13 +197,13 @@ export class KnexStorage implements Storage {
|
|
|
197
197
|
}).update('consumedBy', JSON.stringify(consumedBy))
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
async updateTransactionBEEF(txid: string, beef: number[]): Promise<void> {
|
|
200
|
+
async updateTransactionBEEF (txid: string, beef: number[]): Promise<void> {
|
|
201
201
|
await this.knex('transactions').where({
|
|
202
202
|
txid
|
|
203
203
|
}).update('beef', Buffer.from(beef))
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
async updateOutputBlockHeight(txid: string, outputIndex: number, topic: string, blockHeight: number): Promise<void> {
|
|
206
|
+
async updateOutputBlockHeight (txid: string, outputIndex: number, topic: string, blockHeight: number): Promise<void> {
|
|
207
207
|
await this.knex('outputs').where({
|
|
208
208
|
txid,
|
|
209
209
|
outputIndex,
|
|
@@ -211,14 +211,14 @@ export class KnexStorage implements Storage {
|
|
|
211
211
|
}).update('blockHeight', blockHeight)
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
async insertAppliedTransaction(tx: { txid: string, topic: string }): Promise<void> {
|
|
214
|
+
async insertAppliedTransaction (tx: { txid: string, topic: string }): Promise<void> {
|
|
215
215
|
await this.knex('applied_transactions').insert({
|
|
216
216
|
txid: tx.txid,
|
|
217
217
|
topic: tx.topic
|
|
218
218
|
})
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
async doesAppliedTransactionExist(tx: { txid: string, topic: string }): Promise<boolean> {
|
|
221
|
+
async doesAppliedTransactionExist (tx: { txid: string, topic: string }): Promise<boolean> {
|
|
222
222
|
const result = await this.knex('applied_transactions')
|
|
223
223
|
.where({ txid: tx.txid, topic: tx.topic })
|
|
224
224
|
.select(this.knex.raw('1'))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Knex } from 'knex'
|
|
2
2
|
|
|
3
|
-
export async function up(knex: Knex): Promise<void> {
|
|
3
|
+
export async function up (knex: Knex): Promise<void> {
|
|
4
4
|
await knex.schema.createTable('outputs', table => {
|
|
5
5
|
table.increments()
|
|
6
6
|
table.string('txid', 64)
|
|
@@ -24,7 +24,7 @@ export async function up(knex: Knex): Promise<void> {
|
|
|
24
24
|
})
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export async function down(knex: Knex): Promise<void> {
|
|
27
|
+
export async function down (knex: Knex): Promise<void> {
|
|
28
28
|
await knex.schema.dropTable('applied_transactions')
|
|
29
29
|
await knex.schema.dropTable('outputs')
|
|
30
30
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { Knex } from 'knex'
|
|
2
2
|
|
|
3
|
-
export async function up(knex: Knex): Promise<void> {
|
|
3
|
+
export async function up (knex: Knex): Promise<void> {
|
|
4
4
|
// Add new column for blockHeight associated with outputs
|
|
5
5
|
await knex.schema.table('outputs', table => {
|
|
6
6
|
table.integer('blockHeight').unsigned().nullable()
|
|
7
7
|
})
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export async function down(knex: Knex): Promise<void> {
|
|
10
|
+
export async function down (knex: Knex): Promise<void> {
|
|
11
11
|
// Remove the blockHeight column (rollback operation)
|
|
12
12
|
await knex.schema.table('outputs', table => {
|
|
13
13
|
table.dropColumn('blockHeight')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Knex } from 'knex'
|
|
2
2
|
|
|
3
|
-
export async function up(knex: Knex): Promise<void> {
|
|
3
|
+
export async function up (knex: Knex): Promise<void> {
|
|
4
4
|
// Create the new transactions table
|
|
5
5
|
await knex.schema.createTable('transactions', table => {
|
|
6
6
|
table.increments()
|
|
@@ -22,7 +22,7 @@ export async function up(knex: Knex): Promise<void> {
|
|
|
22
22
|
})
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export async function down(knex: Knex): Promise<void> {
|
|
25
|
+
export async function down (knex: Knex): Promise<void> {
|
|
26
26
|
// Add the beef column back to the outputs table
|
|
27
27
|
await knex.schema.table('outputs', table => {
|
|
28
28
|
table.binary('beef')
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Knex } from 'knex'
|
|
2
|
-
export async function up(knex: Knex): Promise<void> {
|
|
2
|
+
export async function up (knex: Knex): Promise<void> {
|
|
3
3
|
// Add index for applied_transactions table
|
|
4
4
|
await knex.schema.table('applied_transactions', function (table) {
|
|
5
5
|
table.index(['txid', 'topic'], 'idx_applied_transactions_txid_topic')
|
|
@@ -14,7 +14,7 @@ export async function up(knex: Knex): Promise<void> {
|
|
|
14
14
|
})
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export async function down(knex: Knex): Promise<void> {
|
|
17
|
+
export async function down (knex: Knex): Promise<void> {
|
|
18
18
|
// Drop index for applied_transactions table
|
|
19
19
|
await knex.schema.table('applied_transactions', function (table) {
|
|
20
20
|
table.dropIndex(['txid', 'topic'], 'idx_applied_transactions_txid_topic')
|