@rosen-bridge/abstract-extractor 0.1.0-2afdd7
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/.eslintignore +1 -0
- package/README.md +24 -0
- package/dist/AbstractExtractor.d.ts +25 -0
- package/dist/AbstractExtractor.d.ts.map +1 -0
- package/dist/AbstractExtractor.js +3 -0
- package/dist/constants.d.ts +4 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +4 -0
- package/dist/ergo/AbstractErgoExtractor.d.ts +39 -0
- package/dist/ergo/AbstractErgoExtractor.d.ts.map +1 -0
- package/dist/ergo/AbstractErgoExtractor.js +57 -0
- package/dist/ergo/AbstractErgoExtractorAction.d.ts +27 -0
- package/dist/ergo/AbstractErgoExtractorAction.d.ts.map +1 -0
- package/dist/ergo/AbstractErgoExtractorAction.js +3 -0
- package/dist/ergo/index.d.ts +8 -0
- package/dist/ergo/index.d.ts.map +1 -0
- package/dist/ergo/index.js +8 -0
- package/dist/ergo/initializable/AbstractInitializable.d.ts +48 -0
- package/dist/ergo/initializable/AbstractInitializable.d.ts.map +1 -0
- package/dist/ergo/initializable/AbstractInitializable.js +84 -0
- package/dist/ergo/initializable/AbstractInitializableAction.d.ts +9 -0
- package/dist/ergo/initializable/AbstractInitializableAction.d.ts.map +1 -0
- package/dist/ergo/initializable/AbstractInitializableAction.js +4 -0
- package/dist/ergo/initializable/InitializableByAddress.d.ts +26 -0
- package/dist/ergo/initializable/InitializableByAddress.d.ts.map +1 -0
- package/dist/ergo/initializable/InitializableByAddress.js +38 -0
- package/dist/ergo/initializable/InitializableByToken.d.ts +26 -0
- package/dist/ergo/initializable/InitializableByToken.d.ts.map +1 -0
- package/dist/ergo/initializable/InitializableByToken.js +38 -0
- package/dist/ergo/initializable/index.d.ts +5 -0
- package/dist/ergo/initializable/index.d.ts.map +1 -0
- package/dist/ergo/initializable/index.js +5 -0
- package/dist/ergo/interfaces.d.ts +56 -0
- package/dist/ergo/interfaces.d.ts.map +1 -0
- package/dist/ergo/interfaces.js +6 -0
- package/dist/ergo/network/AbstractNetwork.d.ts +32 -0
- package/dist/ergo/network/AbstractNetwork.d.ts.map +1 -0
- package/dist/ergo/network/AbstractNetwork.js +3 -0
- package/dist/ergo/network/ExplorerNetwork.d.ts +35 -0
- package/dist/ergo/network/ExplorerNetwork.d.ts.map +1 -0
- package/dist/ergo/network/ExplorerNetwork.js +53 -0
- package/dist/ergo/network/NodeNetwork.d.ts +42 -0
- package/dist/ergo/network/NodeNetwork.d.ts.map +1 -0
- package/dist/ergo/network/NodeNetwork.js +71 -0
- package/dist/ergo/utils.d.ts +8 -0
- package/dist/ergo/utils.d.ts.map +1 -0
- package/dist/ergo/utils.js +16 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/interfaces.d.ts +12 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +2 -0
- package/lib/AbstractExtractor.ts +31 -0
- package/lib/constants.ts +3 -0
- package/lib/ergo/AbstractErgoExtractor.ts +107 -0
- package/lib/ergo/AbstractErgoExtractorAction.ts +39 -0
- package/lib/ergo/index.ts +7 -0
- package/lib/ergo/initializable/AbstractInitializable.ts +148 -0
- package/lib/ergo/initializable/AbstractInitializableAction.ts +11 -0
- package/lib/ergo/initializable/InitializableByAddress.ts +53 -0
- package/lib/ergo/initializable/InitializableByToken.ts +53 -0
- package/lib/ergo/initializable/index.ts +4 -0
- package/lib/ergo/interfaces.ts +64 -0
- package/lib/ergo/network/AbstractNetwork.ts +35 -0
- package/lib/ergo/network/ExplorerNetwork.ts +68 -0
- package/lib/ergo/network/NodeNetwork.ts +93 -0
- package/lib/ergo/utils.ts +15 -0
- package/lib/index.ts +3 -0
- package/lib/interfaces.ts +12 -0
- package/package.json +42 -0
- package/tests/AbstractExtractor.mock.ts +26 -0
- package/tests/AbstractExtractor.spec.ts +106 -0
- package/tests/initializable/AbstractInitializable.mock.ts +31 -0
- package/tests/initializable/AbstractInitializable.spec.ts +258 -0
- package/tests/initializable/testData.ts +59 -0
- package/tests/testData.ts +111 -0
- package/tsconfig.build.json +7 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +7 -0
- package/vitest.config.ts +17 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { V1 } from '@rosen-clients/ergo-explorer';
|
|
2
|
+
import { describe, it, expect, vitest } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
OutputBox,
|
|
6
|
+
ErgoExtractedData,
|
|
7
|
+
AbstractErgoExtractorAction,
|
|
8
|
+
} from '../lib';
|
|
9
|
+
import { block, extractedData, tx } from './testData';
|
|
10
|
+
import { MockedErgoExtractor } from './AbstractExtractor.mock';
|
|
11
|
+
|
|
12
|
+
describe('AbstractErgoExtractor', () => {
|
|
13
|
+
describe('processTransactions', () => {
|
|
14
|
+
/**
|
|
15
|
+
* @target processTransactions should initialize extractor with specified id and insert status into db
|
|
16
|
+
* @dependencies
|
|
17
|
+
* @scenario
|
|
18
|
+
* - mock extractor
|
|
19
|
+
* - mock `hasData` to return true for one box
|
|
20
|
+
* - spy `extractBoxData` and `insertBoxes`
|
|
21
|
+
* - run test (call `processTransactions`)
|
|
22
|
+
* @expected
|
|
23
|
+
* - to call `extractBoxData` for the specific box
|
|
24
|
+
* - to insert the extracted box to database
|
|
25
|
+
*/
|
|
26
|
+
it('should process boxes with data and insert data into database', async () => {
|
|
27
|
+
const extractor = new MockedErgoExtractor();
|
|
28
|
+
extractor.hasData = (box: V1.OutputInfo | OutputBox) => {
|
|
29
|
+
if (box.boxId == tx.outputs[0].boxId) return true;
|
|
30
|
+
return false;
|
|
31
|
+
};
|
|
32
|
+
const extractSpy = vitest.fn().mockReturnValue(extractedData);
|
|
33
|
+
extractor.extractBoxData = extractSpy;
|
|
34
|
+
const insertSpy = vitest.fn();
|
|
35
|
+
extractor['actions'] = {
|
|
36
|
+
insertBoxes: insertSpy,
|
|
37
|
+
} as unknown as AbstractErgoExtractorAction<ErgoExtractedData>;
|
|
38
|
+
extractor.processTransactions([tx], block);
|
|
39
|
+
|
|
40
|
+
expect(extractSpy).toBeCalledTimes(1);
|
|
41
|
+
expect(extractSpy).toBeCalledWith(
|
|
42
|
+
tx.outputs[0],
|
|
43
|
+
block.hash,
|
|
44
|
+
block.height
|
|
45
|
+
);
|
|
46
|
+
expect(insertSpy).toBeCalledWith([extractedData], 'Test');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @target processTransactions should extract spend info of transaction spend related boxes
|
|
51
|
+
* @dependencies
|
|
52
|
+
* @scenario
|
|
53
|
+
* - mock extractor
|
|
54
|
+
* - spy `extractBoxData`, `insertBoxes` and `spendBoxes`
|
|
55
|
+
* - run test (call `processTransactions`)
|
|
56
|
+
* @expected
|
|
57
|
+
* - not to call `extractBoxData` and `insertBoxes` when there is not any box with data
|
|
58
|
+
* - to extractor spend info of input boxes and call `spendBoxes`
|
|
59
|
+
*/
|
|
60
|
+
it('should extract spend info of transaction spend related boxes', async () => {
|
|
61
|
+
const extractor = new MockedErgoExtractor();
|
|
62
|
+
const extractSpy = vitest.fn();
|
|
63
|
+
extractor.extractBoxData = extractSpy;
|
|
64
|
+
const insertSpy = vitest.fn();
|
|
65
|
+
const spendSpy = vitest.fn();
|
|
66
|
+
extractor['actions'] = {
|
|
67
|
+
insertBoxes: insertSpy,
|
|
68
|
+
spendBoxes: spendSpy,
|
|
69
|
+
} as unknown as AbstractErgoExtractorAction<ErgoExtractedData>;
|
|
70
|
+
extractor.processTransactions([tx], block);
|
|
71
|
+
|
|
72
|
+
expect(extractSpy).not.toBeCalled();
|
|
73
|
+
expect(insertSpy).not.toBeCalled();
|
|
74
|
+
expect(spendSpy).toBeCalledWith(
|
|
75
|
+
[
|
|
76
|
+
{ boxId: tx.inputs[0].boxId, txId: tx.id, index: 1 },
|
|
77
|
+
{ boxId: tx.inputs[1].boxId, txId: tx.id, index: 2 },
|
|
78
|
+
],
|
|
79
|
+
block,
|
|
80
|
+
'Test'
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('forkBlock', () => {
|
|
86
|
+
/**
|
|
87
|
+
* @target forkBlock should remove all data extracted from the specified block
|
|
88
|
+
* @dependencies
|
|
89
|
+
* @scenario
|
|
90
|
+
* - mock extractor
|
|
91
|
+
* - spy `deleteBlockBoxes`
|
|
92
|
+
* - run test (call `forkBlock`)
|
|
93
|
+
* @expected
|
|
94
|
+
* - to call `deleteBlockBoxes` for the specific box
|
|
95
|
+
*/
|
|
96
|
+
it('should remove all data extracted from the specified block', async () => {
|
|
97
|
+
const extractor = new MockedErgoExtractor();
|
|
98
|
+
const removeSpy = vitest.fn();
|
|
99
|
+
extractor['actions'] = {
|
|
100
|
+
deleteBlockBoxes: removeSpy,
|
|
101
|
+
} as unknown as AbstractErgoExtractorAction<ErgoExtractedData>;
|
|
102
|
+
extractor.forkBlock(block.hash);
|
|
103
|
+
expect(removeSpy).toBeCalledWith(block.hash, 'Test');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { V1 } from '@rosen-clients/ergo-explorer';
|
|
2
|
+
import {
|
|
3
|
+
AbstractInitializableErgoExtractor,
|
|
4
|
+
AbstractInitializableErgoExtractorAction,
|
|
5
|
+
} from '../../lib/ergo/initializable';
|
|
6
|
+
import { OutputBox, ErgoExtractedData, BlockInfo } from '../../lib';
|
|
7
|
+
import { ergoBoxes } from './testData';
|
|
8
|
+
|
|
9
|
+
export class MockedInitializableErgoExtractor extends AbstractInitializableErgoExtractor<ErgoExtractedData> {
|
|
10
|
+
actions: AbstractInitializableErgoExtractorAction<ErgoExtractedData>;
|
|
11
|
+
|
|
12
|
+
getId = () => 'Test';
|
|
13
|
+
|
|
14
|
+
hasData = (box: V1.OutputInfo | OutputBox) => false;
|
|
15
|
+
|
|
16
|
+
getTxBlock = async (txId: string): Promise<BlockInfo> => {
|
|
17
|
+
return { hash: 'hash', height: 100 };
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
getBoxesWithOffsetLimit = (offset: number, limit: number) => {
|
|
21
|
+
return Promise.resolve({ boxes: ergoBoxes, hasNextBatch: true });
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
extractBoxData = (
|
|
25
|
+
box: V1.OutputInfo | OutputBox,
|
|
26
|
+
blockId: string,
|
|
27
|
+
height: number
|
|
28
|
+
) => {
|
|
29
|
+
return undefined;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { describe, it, expect, vitest } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { MockedInitializableErgoExtractor } from './AbstractInitializable.mock';
|
|
4
|
+
import { ergoBoxes, extractedData } from './testData';
|
|
5
|
+
import { OutputBox, ErgoExtractedData } from '../../lib';
|
|
6
|
+
import { AbstractInitializableErgoExtractorAction } from '../../lib/ergo/initializable';
|
|
7
|
+
|
|
8
|
+
describe('AbstractInitializableErgoExtractorAction', () => {
|
|
9
|
+
describe('fetchDataWithOffsetLimit', () => {
|
|
10
|
+
/**
|
|
11
|
+
* @target fetchDataWithOffsetLimit should extract unspent box data in the initial block
|
|
12
|
+
* @dependencies
|
|
13
|
+
* @scenario
|
|
14
|
+
* - mock extractor
|
|
15
|
+
* - mock `hasData` to return true for an unspent box in the init block
|
|
16
|
+
* - spy `extractData` and `getTxBlock`
|
|
17
|
+
* - run test (call `fetchDataWithOffsetLimit`)
|
|
18
|
+
* @expected
|
|
19
|
+
* - to call `extractData` with unspent box information
|
|
20
|
+
* - not to call `getTxBlock` since its unspent
|
|
21
|
+
* - return one extracted element (the unspent box) and api total
|
|
22
|
+
*/
|
|
23
|
+
it('should extract unspent box data in the initial block', async () => {
|
|
24
|
+
const extractor = new MockedInitializableErgoExtractor();
|
|
25
|
+
const unspentBox = ergoBoxes[0];
|
|
26
|
+
extractor.hasData = (box: OutputBox) => {
|
|
27
|
+
if (box.boxId == unspentBox.boxId) return true;
|
|
28
|
+
return false;
|
|
29
|
+
};
|
|
30
|
+
const extractSpy = vitest.fn().mockReturnValue(extractedData);
|
|
31
|
+
extractor.extractBoxData = extractSpy;
|
|
32
|
+
const txBlockSpy = vitest.fn();
|
|
33
|
+
extractor.getTxBlock = txBlockSpy;
|
|
34
|
+
const data = await extractor.fetchDataWithOffsetLimit(1252681, 0, 2);
|
|
35
|
+
expect(extractSpy).toHaveBeenCalledWith(
|
|
36
|
+
unspentBox,
|
|
37
|
+
unspentBox.blockId,
|
|
38
|
+
unspentBox.creationHeight
|
|
39
|
+
);
|
|
40
|
+
expect(txBlockSpy).not.toHaveBeenCalled();
|
|
41
|
+
expect(data).toEqual({
|
|
42
|
+
extractedBoxes: [
|
|
43
|
+
{ ...extractedData, spendBlock: undefined, spendHeight: undefined },
|
|
44
|
+
],
|
|
45
|
+
hasNextBatch: true,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @target fetchDataWithOffsetLimit should filter boxes created below the initial block
|
|
51
|
+
* @dependencies
|
|
52
|
+
* @scenario
|
|
53
|
+
* - mock extractor
|
|
54
|
+
* - mock `hasData` to return true for all boxes
|
|
55
|
+
* - spy `extractData` and `getTxBlock`
|
|
56
|
+
* - run test (call `fetchDataWithOffsetLimit`)
|
|
57
|
+
* @expected
|
|
58
|
+
* - to call `extractData` with spent box information
|
|
59
|
+
* - to call `getTxBlock` since box is spent
|
|
60
|
+
* - return one extracted element created bellow the initial block
|
|
61
|
+
*/
|
|
62
|
+
it('should filter boxes created below the initial block', async () => {
|
|
63
|
+
const extractor = new MockedInitializableErgoExtractor();
|
|
64
|
+
const spentBox = ergoBoxes[1];
|
|
65
|
+
extractor.hasData = (box: OutputBox) => true;
|
|
66
|
+
const extractSpy = vitest.fn().mockReturnValue(extractedData);
|
|
67
|
+
extractor.extractBoxData = extractSpy;
|
|
68
|
+
const txBlockSpy = vitest
|
|
69
|
+
.fn()
|
|
70
|
+
.mockResolvedValue({ id: 'hash', height: 1252690 });
|
|
71
|
+
extractor.getTxBlock = txBlockSpy;
|
|
72
|
+
const data = await extractor.fetchDataWithOffsetLimit(1252680, 0, 2);
|
|
73
|
+
expect(extractSpy).toHaveBeenCalledWith(
|
|
74
|
+
spentBox,
|
|
75
|
+
spentBox.blockId,
|
|
76
|
+
spentBox.creationHeight
|
|
77
|
+
);
|
|
78
|
+
expect(txBlockSpy).toHaveBeenCalledWith(spentBox.spentTransactionId);
|
|
79
|
+
expect(data).toEqual({
|
|
80
|
+
extractedBoxes: [
|
|
81
|
+
{ ...extractedData, spendBlock: undefined, spendHeight: undefined },
|
|
82
|
+
],
|
|
83
|
+
hasNextBatch: true,
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @target fetchDataWithOffsetLimit should extract spent box data created and spent below the initial block
|
|
89
|
+
* @dependencies
|
|
90
|
+
* @scenario
|
|
91
|
+
* - mock extractor
|
|
92
|
+
* - mock `hasData` to return true for an spent box created below the init block
|
|
93
|
+
* - spy `extractData` and `getTxBlock`
|
|
94
|
+
* - run test (call `fetchDataWithOffsetLimit`)
|
|
95
|
+
* @expected
|
|
96
|
+
* - to call `extractData` with spent box information
|
|
97
|
+
* - to call `getTxBlock` since box is spent
|
|
98
|
+
* - return one extracted element with spending information
|
|
99
|
+
*/
|
|
100
|
+
it('should extract spent box data created and spent below the initial block', async () => {
|
|
101
|
+
const extractor = new MockedInitializableErgoExtractor();
|
|
102
|
+
const spentBox = ergoBoxes[1];
|
|
103
|
+
extractor.hasData = (box: OutputBox) => {
|
|
104
|
+
if (box.boxId == spentBox.boxId) return true;
|
|
105
|
+
return false;
|
|
106
|
+
};
|
|
107
|
+
const extractSpy = vitest.fn().mockReturnValue(extractedData);
|
|
108
|
+
extractor.extractBoxData = extractSpy;
|
|
109
|
+
const txBlockSpy = vitest
|
|
110
|
+
.fn()
|
|
111
|
+
.mockResolvedValue({ hash: 'hash', height: 1252680 });
|
|
112
|
+
extractor.getTxBlock = txBlockSpy;
|
|
113
|
+
const data = await extractor.fetchDataWithOffsetLimit(1252681, 0, 2);
|
|
114
|
+
expect(extractSpy).toHaveBeenCalledWith(
|
|
115
|
+
spentBox,
|
|
116
|
+
spentBox.blockId,
|
|
117
|
+
spentBox.creationHeight
|
|
118
|
+
);
|
|
119
|
+
expect(txBlockSpy).toHaveBeenCalledWith(spentBox.spentTransactionId);
|
|
120
|
+
expect(data).toEqual({
|
|
121
|
+
extractedBoxes: [
|
|
122
|
+
{ ...extractedData, spendBlock: 'hash', spendHeight: 1252680 },
|
|
123
|
+
],
|
|
124
|
+
hasNextBatch: true,
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @target fetchDataWithOffsetLimit should extract spent box data created below the initial block but spent later
|
|
130
|
+
* @dependencies
|
|
131
|
+
* @scenario
|
|
132
|
+
* - mock extractor
|
|
133
|
+
* - mock `hasData` to return true for an spent box created below the init block
|
|
134
|
+
* - spy `extractData` and `getTxBlock`
|
|
135
|
+
* - run test (call `fetchDataWithOffsetLimit`)
|
|
136
|
+
* @expected
|
|
137
|
+
* - to call `extractData` with spent box information
|
|
138
|
+
* - to call `getTxBlock` since box is spent
|
|
139
|
+
* - return one extracted element without spending information
|
|
140
|
+
*/
|
|
141
|
+
it('should extract spent box data created below the initial block but spent later', async () => {
|
|
142
|
+
const extractor = new MockedInitializableErgoExtractor();
|
|
143
|
+
const spentBox = ergoBoxes[1];
|
|
144
|
+
extractor.hasData = (box: OutputBox) => {
|
|
145
|
+
if (box.boxId == spentBox.boxId) return true;
|
|
146
|
+
return false;
|
|
147
|
+
};
|
|
148
|
+
const extractSpy = vitest.fn().mockReturnValue(extractedData);
|
|
149
|
+
extractor.extractBoxData = extractSpy;
|
|
150
|
+
const txBlockSpy = vitest
|
|
151
|
+
.fn()
|
|
152
|
+
.mockResolvedValue({ hash: 'hash', height: 1252690 });
|
|
153
|
+
extractor.getTxBlock = txBlockSpy;
|
|
154
|
+
const data = await extractor.fetchDataWithOffsetLimit(1252681, 0, 2);
|
|
155
|
+
expect(extractSpy).toHaveBeenCalledWith(
|
|
156
|
+
spentBox,
|
|
157
|
+
spentBox.blockId,
|
|
158
|
+
spentBox.creationHeight
|
|
159
|
+
);
|
|
160
|
+
expect(txBlockSpy).toHaveBeenCalledWith(spentBox.spentTransactionId);
|
|
161
|
+
expect(data).toEqual({
|
|
162
|
+
extractedBoxes: [
|
|
163
|
+
{ ...extractedData, spendBlock: undefined, spendHeight: undefined },
|
|
164
|
+
],
|
|
165
|
+
hasNextBatch: true,
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('initializeBoxes', () => {
|
|
171
|
+
/**
|
|
172
|
+
* @target initializeBoxes should remove all data and reinsert the newly extracted data
|
|
173
|
+
* @dependencies
|
|
174
|
+
* @scenario
|
|
175
|
+
* - mock extractor
|
|
176
|
+
* - spy database functions
|
|
177
|
+
* - mock `fetchDataWithOffsetLimit` to return one extracted data
|
|
178
|
+
* - run test (call `initializeBoxes`)
|
|
179
|
+
* @expected
|
|
180
|
+
* - to call removeAllData once
|
|
181
|
+
* - to call insertBoxes once with extracted data
|
|
182
|
+
*/
|
|
183
|
+
it('should remove all data and reinsert the newly extracted data', async () => {
|
|
184
|
+
const extractor = new MockedInitializableErgoExtractor();
|
|
185
|
+
const removeSpy = vitest.fn();
|
|
186
|
+
const insertSpy = vitest.fn().mockResolvedValue(true);
|
|
187
|
+
extractor['actions'] = {
|
|
188
|
+
removeAllData: removeSpy,
|
|
189
|
+
insertBoxes: insertSpy,
|
|
190
|
+
} as unknown as AbstractInitializableErgoExtractorAction<ErgoExtractedData>;
|
|
191
|
+
extractor.fetchDataWithOffsetLimit = vitest.fn().mockResolvedValue({
|
|
192
|
+
extractedBoxes: [extractedData],
|
|
193
|
+
hasNextBatch: false,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
await extractor.initializeBoxes({ height: 100, hash: 'hash' });
|
|
197
|
+
expect(removeSpy).toBeCalledTimes(1);
|
|
198
|
+
expect(insertSpy).toBeCalledWith([extractedData], 'Test');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* @target initializeBoxes should iterate on api when data count is more than api limit
|
|
203
|
+
* @dependencies
|
|
204
|
+
* @scenario
|
|
205
|
+
* - mock extractor
|
|
206
|
+
* - spy database functions
|
|
207
|
+
* - mock `fetchDataWithOffsetLimit` to return total number 101 (greater than API_LIMIT)
|
|
208
|
+
* - run test (call `initializeBoxes`)
|
|
209
|
+
* @expected
|
|
210
|
+
* - to call removeAllData once
|
|
211
|
+
* - to call insertBoxes twice
|
|
212
|
+
*/
|
|
213
|
+
it('should iterate on api when data count is more than api limit', async () => {
|
|
214
|
+
const extractor = new MockedInitializableErgoExtractor();
|
|
215
|
+
const removeSpy = vitest.fn();
|
|
216
|
+
const insertSpy = vitest.fn().mockResolvedValue(true);
|
|
217
|
+
extractor['actions'] = {
|
|
218
|
+
removeAllData: removeSpy,
|
|
219
|
+
insertBoxes: insertSpy,
|
|
220
|
+
} as unknown as AbstractInitializableErgoExtractorAction<ErgoExtractedData>;
|
|
221
|
+
extractor.fetchDataWithOffsetLimit = vitest
|
|
222
|
+
.fn()
|
|
223
|
+
.mockResolvedValueOnce({
|
|
224
|
+
extractedBoxes: [extractedData],
|
|
225
|
+
hasNextBatch: true,
|
|
226
|
+
})
|
|
227
|
+
.mockResolvedValueOnce({ extractedBoxes: [], hasNextBatch: false });
|
|
228
|
+
|
|
229
|
+
await extractor.initializeBoxes({ height: 100, hash: 'hash' });
|
|
230
|
+
expect(removeSpy).toBeCalledTimes(1);
|
|
231
|
+
expect(insertSpy).toBeCalledTimes(2);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @target initializeBoxes should not run initialization when initialize flag is false
|
|
236
|
+
* @dependencies
|
|
237
|
+
* @scenario
|
|
238
|
+
* - mock extractor
|
|
239
|
+
* - spy database functions
|
|
240
|
+
* - run test (call `initializeBoxes`)
|
|
241
|
+
* @expected
|
|
242
|
+
* - not to call any functions
|
|
243
|
+
*/
|
|
244
|
+
it('should not run initialization when initialize flag is false', async () => {
|
|
245
|
+
const extractor = new MockedInitializableErgoExtractor(false);
|
|
246
|
+
const removeSpy = vitest.fn();
|
|
247
|
+
const insertSpy = vitest.fn();
|
|
248
|
+
extractor['actions'] = {
|
|
249
|
+
removeAllData: removeSpy,
|
|
250
|
+
insertBoxes: insertSpy,
|
|
251
|
+
} as unknown as AbstractInitializableErgoExtractorAction<ErgoExtractedData>;
|
|
252
|
+
|
|
253
|
+
await extractor.initializeBoxes({ height: 100, hash: 'hash' });
|
|
254
|
+
expect(removeSpy).not.toBeCalled();
|
|
255
|
+
expect(insertSpy).not.toBeCalled();
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export const ergoBoxes = [
|
|
2
|
+
{
|
|
3
|
+
boxId: '57d8334d8b6095393d9c6e471e25b477caba54adcc9757ea4f24d366fe72cdb3',
|
|
4
|
+
transactionId:
|
|
5
|
+
'793724eec1c6fa4ec68d93186c6403a071154cfc6e5931038791e447a69e1207',
|
|
6
|
+
blockId: '4674c0e9a4f26e24e083c8b5b3bbe0c63cd786c32a317f742be1228281b45b26',
|
|
7
|
+
value: 14948300000n,
|
|
8
|
+
index: 1,
|
|
9
|
+
creationHeight: 1252681,
|
|
10
|
+
ergoTree:
|
|
11
|
+
'0008cd03e5f5f63b27f9cdc47a9a8b799a26e5ee66a1e2a5d41d64640df3e64f4d050c18',
|
|
12
|
+
address: '9iD5jMoLjK9azTdigyT8z1QY6qHrA6gVrJamMF8MJ2qt45pJpDc',
|
|
13
|
+
assets: [
|
|
14
|
+
{
|
|
15
|
+
tokenId:
|
|
16
|
+
'e023c5f382b6e96fbd878f6811aac73345489032157ad5affb84aefd4956c297',
|
|
17
|
+
index: 0,
|
|
18
|
+
amount: 4983552n,
|
|
19
|
+
name: 'rsADA',
|
|
20
|
+
decimals: 6,
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
additionalRegisters: {},
|
|
24
|
+
spentTransactionId: undefined,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
boxId: '2708cc15be42eff988c7194c86912d305361c8c12cf9dae2b750dbf5c1519bd0',
|
|
28
|
+
transactionId:
|
|
29
|
+
'd18aaa53c20ff5a8989f6b26d2e84c9bd439abb7b61e9e53f48e73a6f311e712',
|
|
30
|
+
blockId: '95e73453f5824158e89946bf2efb6f7bf808c6c4b6d380d7f588e770a1de1ad0',
|
|
31
|
+
value: 14981300000n,
|
|
32
|
+
index: 2,
|
|
33
|
+
creationHeight: 1252677,
|
|
34
|
+
ergoTree:
|
|
35
|
+
'0008cd03e5f5f63b27f9cdc47a9a8b799a26e5ee66a1e2a5d41d64640df3e64f4d050c18',
|
|
36
|
+
address: '9iD5jMoLjK9azTdigyT8z1QY6qHrA6gVrJamMF8MJ2qt45pJpDc',
|
|
37
|
+
assets: [
|
|
38
|
+
{
|
|
39
|
+
tokenId:
|
|
40
|
+
'e023c5f382b6e96fbd878f6811aac73345489032157ad5affb84aefd4956c297',
|
|
41
|
+
index: 0,
|
|
42
|
+
amount: 4983552n,
|
|
43
|
+
name: 'rsADA',
|
|
44
|
+
decimals: 6,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
additionalRegisters: {},
|
|
48
|
+
spentTransactionId:
|
|
49
|
+
'b08fa920a6907d0e76eb0ad754439f1a26fa112b39f4de489620e4e6241930b7',
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
export const extractedData = {
|
|
54
|
+
boxId: 'boxId1',
|
|
55
|
+
address: 'address1',
|
|
56
|
+
serialized: 'serialized1',
|
|
57
|
+
blockId: 'blockId1',
|
|
58
|
+
height: 98,
|
|
59
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Block } from '../lib';
|
|
2
|
+
|
|
3
|
+
export const tx = {
|
|
4
|
+
id: '3b91fbd2b6f4f3f971098655ffa320841001b071908de057cdf8c425cd3b3e61',
|
|
5
|
+
inputs: [
|
|
6
|
+
{
|
|
7
|
+
boxId: '3df73b29204ffa2085c38a958d322c86bee0471a5a1296b031f137236e038c6d',
|
|
8
|
+
spendingProof: {
|
|
9
|
+
proofBytes:
|
|
10
|
+
'06fb1e785d12ac74886c0d3fa0e61db0aa4dfaef6b6a42ab7a908625f3721f35bbce8245876ab14113baf41ff7b479863513462a8b438ec3',
|
|
11
|
+
extension: {},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
boxId: '846f3cedf2fc4242898413558e73a69d057edda1df6f274a1eeea219b6dd62dd',
|
|
16
|
+
spendingProof: {
|
|
17
|
+
proofBytes:
|
|
18
|
+
'2c930f70ba11b35f32e3eb9023634e7a394a8714ebe794fd7134ab4cea9da753303f2f56e6bf4d1b0b0466b29fc8ce8c949ca602edf38895',
|
|
19
|
+
extension: {},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
dataInputs: [],
|
|
24
|
+
outputs: [
|
|
25
|
+
{
|
|
26
|
+
boxId: '03a6b9d06c50e8895a1e1c02365d1e2e4becd71efe188b341ca84b228ee26542',
|
|
27
|
+
value: BigInt(1000000000),
|
|
28
|
+
ergoTree:
|
|
29
|
+
'0008cd0399f5724bbc4d08c6e146d61449c05a3e0546868b1d4f83411f325187d5ca4f85',
|
|
30
|
+
assets: [
|
|
31
|
+
{
|
|
32
|
+
tokenId:
|
|
33
|
+
'3df73b29204ffa2085c38a958d322c86bee0471a5a1296b031f137236e038c6d',
|
|
34
|
+
amount: BigInt(100),
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
tokenId:
|
|
38
|
+
'ba698c3c943e06ad224d42c736826f8dc38981fb92814f577a89c0ad9361c367',
|
|
39
|
+
amount: BigInt(80),
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
additionalRegisters: {},
|
|
43
|
+
creationHeight: 262162,
|
|
44
|
+
transactionId:
|
|
45
|
+
'3b91fbd2b6f4f3f971098655ffa320841001b071908de057cdf8c425cd3b3e61',
|
|
46
|
+
index: 0,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
boxId: '8cb3beec9a17a3cb4b300cc4744fe16cbf5b27d4e660d55a55eb188d92f97c7a',
|
|
50
|
+
value: BigInt(14000000000),
|
|
51
|
+
ergoTree:
|
|
52
|
+
'0008cd024e06e6c6073e13a03fa4629882a69108cd60e0a9fbb2e0fcc898ce68a7051b66',
|
|
53
|
+
assets: [
|
|
54
|
+
{
|
|
55
|
+
tokenId:
|
|
56
|
+
'dd1d06937ec75aae076f91cacb2fb721d2495030ff2c8096a61bd2b608bdc311',
|
|
57
|
+
amount: BigInt(100),
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
additionalRegisters: {},
|
|
61
|
+
creationHeight: 262162,
|
|
62
|
+
transactionId:
|
|
63
|
+
'3b91fbd2b6f4f3f971098655ffa320841001b071908de057cdf8c425cd3b3e61',
|
|
64
|
+
index: 1,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
boxId: '7f4b8f4fd7f612e81ec1e544e9b0dcd711f4f4fcb6775abbb8c92f23739fb112',
|
|
68
|
+
value: BigInt(1100000),
|
|
69
|
+
ergoTree:
|
|
70
|
+
'1005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304',
|
|
71
|
+
assets: [],
|
|
72
|
+
additionalRegisters: {},
|
|
73
|
+
creationHeight: 262162,
|
|
74
|
+
transactionId:
|
|
75
|
+
'3b91fbd2b6f4f3f971098655ffa320841001b071908de057cdf8c425cd3b3e61',
|
|
76
|
+
index: 2,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
boxId: '46220fcb528daed856ce06f4225bd32fced8eac053922b77bee3e8e776252e28',
|
|
80
|
+
value: BigInt(6998900000),
|
|
81
|
+
ergoTree:
|
|
82
|
+
'0008cd0302e57ca7ebf8cfa1802d4bc79a455008307a936b4f50f0629d9bef484fdd5189',
|
|
83
|
+
assets: [
|
|
84
|
+
{
|
|
85
|
+
tokenId:
|
|
86
|
+
'ba698c3c943e06ad224d42c736826f8dc38981fb92814f577a89c0ad9361c367',
|
|
87
|
+
amount: BigInt(20),
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
additionalRegisters: {},
|
|
91
|
+
creationHeight: 262162,
|
|
92
|
+
transactionId:
|
|
93
|
+
'3b91fbd2b6f4f3f971098655ffa320841001b071908de057cdf8c425cd3b3e61',
|
|
94
|
+
index: 3,
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const extractedData = {
|
|
100
|
+
boxId: 'boxId1',
|
|
101
|
+
address: 'address1',
|
|
102
|
+
serialized: 'serialized1',
|
|
103
|
+
blockId: 'blockId1',
|
|
104
|
+
height: 98,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export const block: Block = {
|
|
108
|
+
hash: 'hash',
|
|
109
|
+
height: 100,
|
|
110
|
+
parentHash: 'parentHash',
|
|
111
|
+
} as Block;
|