@rosen-bridge/abstract-extractor 1.0.1 → 2.0.0-181e9e8f
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/CHANGELOG.md +14 -0
- package/dist/AbstractExtractor.d.ts +2 -2
- package/dist/AbstractExtractor.d.ts.map +1 -1
- package/dist/AbstractExtractor.js +1 -1
- package/dist/ergo/AbstractErgoExtractor.d.ts +22 -4
- package/dist/ergo/AbstractErgoExtractor.d.ts.map +1 -1
- package/dist/ergo/AbstractErgoExtractor.js +28 -8
- package/dist/ergo/AbstractErgoExtractorAction.d.ts +36 -4
- package/dist/ergo/AbstractErgoExtractorAction.d.ts.map +1 -1
- package/dist/ergo/AbstractErgoExtractorAction.js +105 -33
- package/dist/ergo/initializable/AbstractInitializable.d.ts +2 -2
- package/dist/ergo/initializable/AbstractInitializable.d.ts.map +1 -1
- package/dist/ergo/initializable/AbstractInitializable.js +2 -2
- package/dist/ergo/interfaces.d.ts +7 -40
- package/dist/ergo/interfaces.d.ts.map +1 -1
- package/dist/ergo/interfaces.js +1 -6
- package/dist/ergo/network/ExplorerNetwork.d.ts +2 -2
- package/dist/ergo/network/ExplorerNetwork.d.ts.map +1 -1
- package/dist/ergo/network/ExplorerNetwork.js +8 -4
- package/dist/ergo/network/NodeNetwork.d.ts +1 -1
- package/dist/ergo/network/NodeNetwork.d.ts.map +1 -1
- package/dist/ergo/network/NodeNetwork.js +2 -1
- package/dist/ergo/utils.d.ts +1 -1
- package/dist/ergo/utils.d.ts.map +1 -1
- package/dist/ergo/utils.js +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/lib/{AbstractExtractor.ts → abstractExtractor.ts} +1 -1
- package/lib/ergo/AbstractErgoExtractor.ts +46 -11
- package/lib/ergo/AbstractErgoExtractorAction.ts +147 -47
- package/lib/ergo/initializable/AbstractInitializable.ts +2 -6
- package/lib/ergo/interfaces.ts +4 -46
- package/lib/ergo/network/ExplorerNetwork.ts +12 -9
- package/lib/ergo/network/NodeNetwork.ts +3 -2
- package/lib/ergo/utils.ts +1 -1
- package/lib/index.ts +1 -2
- package/package.json +3 -2
- package/tests/AbstractErgoExtractor.mock.ts +2 -2
- package/tests/AbstractErgoExtractor.spec.ts +7 -3
- package/tests/AbstractErgoExtractorAction.mock.ts +1 -1
- package/tests/initializable/AbstractInitializable.mock.ts +3 -6
- package/tests/initializable/AbstractInitializable.spec.ts +1 -1
- package/tests/initializable/AbstractInitializableAction.mock.ts +1 -1
- package/tests/network/testData.ts +11 -18
- package/tests/testData.ts +4 -11
- package/tsconfig.build.json +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.json +2 -1
- package/lib/interfaces.ts +0 -12
|
@@ -2,18 +2,22 @@ import { AbstractLogger, DummyLogger } from '@rosen-bridge/abstract-logger';
|
|
|
2
2
|
import JsonBigInt from '@rosen-bridge/json-bigint';
|
|
3
3
|
import { Mutex } from 'await-semaphore';
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
-
|
|
6
|
-
import { AbstractExtractor } from '../AbstractExtractor';
|
|
7
|
-
import { AbstractErgoExtractorAction } from './AbstractErgoExtractorAction';
|
|
8
|
-
import { BlockInfo } from '../interfaces';
|
|
9
5
|
import {
|
|
10
6
|
Transaction,
|
|
11
7
|
OutputBox,
|
|
8
|
+
InputExtension,
|
|
9
|
+
BlockInfo,
|
|
10
|
+
} from '@rosen-bridge/scanner-interfaces';
|
|
11
|
+
|
|
12
|
+
import { AbstractExtractor } from '../abstractExtractor';
|
|
13
|
+
import { AbstractErgoExtractorAction } from './AbstractErgoExtractorAction';
|
|
14
|
+
import {
|
|
12
15
|
AbstractBoxData,
|
|
13
16
|
SpendInfo,
|
|
14
17
|
CallbackType,
|
|
15
18
|
CallbackMap,
|
|
16
19
|
CallbackDataMap,
|
|
20
|
+
TxExtra,
|
|
17
21
|
} from './interfaces';
|
|
18
22
|
import { AbstractErgoExtractorEntity } from './AbstractErgoExtractorEntity';
|
|
19
23
|
|
|
@@ -99,9 +103,14 @@ export abstract class AbstractErgoExtractor<
|
|
|
99
103
|
/**
|
|
100
104
|
* extract box data to proper format (not including spending information)
|
|
101
105
|
* @param box
|
|
106
|
+
* @param inputExtensions all input box extensions in transaction
|
|
102
107
|
* @return extracted data in proper format
|
|
103
108
|
*/
|
|
104
|
-
abstract extractBoxData: (
|
|
109
|
+
abstract extractBoxData: (
|
|
110
|
+
box: OutputBox,
|
|
111
|
+
inputExtensions: InputExtension[],
|
|
112
|
+
txExtra?: TxExtra
|
|
113
|
+
) => ExtractedData | undefined;
|
|
105
114
|
|
|
106
115
|
/**
|
|
107
116
|
* check proper data format in the box
|
|
@@ -110,6 +119,31 @@ export abstract class AbstractErgoExtractor<
|
|
|
110
119
|
*/
|
|
111
120
|
abstract hasData: (box: OutputBox) => boolean;
|
|
112
121
|
|
|
122
|
+
/**
|
|
123
|
+
* create spend info array for the transaction
|
|
124
|
+
* @param tx
|
|
125
|
+
* @returns spend info array of the transaction
|
|
126
|
+
*/
|
|
127
|
+
getTransactionSpendInfo = (tx: Transaction) => {
|
|
128
|
+
let boxIndex = 1;
|
|
129
|
+
const spendInfoArray = [];
|
|
130
|
+
for (const input of tx.inputs) {
|
|
131
|
+
spendInfoArray.push({ txId: tx.id, boxId: input.boxId, index: boxIndex });
|
|
132
|
+
boxIndex += 1;
|
|
133
|
+
}
|
|
134
|
+
return spendInfoArray;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* extract transaction extra information
|
|
139
|
+
* override this function if there is extra needed information
|
|
140
|
+
* @param tx
|
|
141
|
+
* @returns
|
|
142
|
+
*/
|
|
143
|
+
getTransactionExtraData = (tx: Transaction): TxExtra => {
|
|
144
|
+
return {};
|
|
145
|
+
};
|
|
146
|
+
|
|
113
147
|
/**
|
|
114
148
|
* process a list of transactions in a block and store required information
|
|
115
149
|
* @param txs list of transactions in the block
|
|
@@ -124,12 +158,17 @@ export abstract class AbstractErgoExtractor<
|
|
|
124
158
|
const boxes: Array<ExtractedData> = [];
|
|
125
159
|
const spentInfos: Array<SpendInfo> = [];
|
|
126
160
|
for (const tx of txs) {
|
|
161
|
+
const inputExtensions = tx.inputs.map((input) => input.extension || {});
|
|
127
162
|
for (const output of tx.outputs) {
|
|
128
163
|
if (!this.hasData(output)) {
|
|
129
164
|
continue;
|
|
130
165
|
}
|
|
131
166
|
this.logger.debug(`Trying to extract data from box ${output.boxId}`);
|
|
132
|
-
const extractedData = this.extractBoxData(
|
|
167
|
+
const extractedData = this.extractBoxData(
|
|
168
|
+
output,
|
|
169
|
+
inputExtensions,
|
|
170
|
+
this.getTransactionExtraData(tx)
|
|
171
|
+
);
|
|
133
172
|
if (extractedData) {
|
|
134
173
|
this.logger.debug(
|
|
135
174
|
`Extracted data ${JsonBigInt.stringify(extractedData)} from box ${
|
|
@@ -139,11 +178,7 @@ export abstract class AbstractErgoExtractor<
|
|
|
139
178
|
boxes.push(extractedData);
|
|
140
179
|
}
|
|
141
180
|
}
|
|
142
|
-
|
|
143
|
-
for (const input of tx.inputs) {
|
|
144
|
-
spentInfos.push({ txId: tx.id, boxId: input.boxId, index: boxIndex });
|
|
145
|
-
boxIndex += 1;
|
|
146
|
-
}
|
|
181
|
+
spentInfos.push(...this.getTransactionSpendInfo(tx));
|
|
147
182
|
}
|
|
148
183
|
|
|
149
184
|
if (boxes.length > 0) {
|
|
@@ -5,12 +5,13 @@ import {
|
|
|
5
5
|
Not,
|
|
6
6
|
EntityTarget,
|
|
7
7
|
FindOptionsWhere,
|
|
8
|
+
QueryRunner,
|
|
8
9
|
} from 'typeorm';
|
|
9
10
|
import { chunk, difference, pick } from 'lodash-es';
|
|
10
11
|
import { AbstractLogger, DummyLogger } from '@rosen-bridge/abstract-logger';
|
|
11
12
|
import JsonBigInt from '@rosen-bridge/json-bigint';
|
|
13
|
+
import { BlockInfo } from '@rosen-bridge/scanner-interfaces';
|
|
12
14
|
|
|
13
|
-
import { BlockInfo } from '../interfaces';
|
|
14
15
|
import { AbstractBoxData, BoxInfo, SpendInfo } from './interfaces';
|
|
15
16
|
import { DB_CHUNK_SIZE } from '../constants';
|
|
16
17
|
import { AbstractErgoExtractorEntity } from './AbstractErgoExtractorEntity';
|
|
@@ -38,18 +39,122 @@ export abstract class AbstractErgoExtractorAction<
|
|
|
38
39
|
/**
|
|
39
40
|
* create the database entity from extracted data and block information
|
|
40
41
|
*/
|
|
41
|
-
protected
|
|
42
|
+
protected createEntity = (
|
|
42
43
|
data: ExtractedData[],
|
|
43
44
|
block: BlockInfo,
|
|
44
45
|
extractor: string
|
|
45
|
-
)
|
|
46
|
+
): Array<Omit<ExtractorEntity, 'id'>> => {
|
|
47
|
+
throw Error(
|
|
48
|
+
'You must implement `createEntity` or override `insertEntities` and `updateEntities`'
|
|
49
|
+
);
|
|
50
|
+
};
|
|
46
51
|
|
|
47
52
|
/**
|
|
48
53
|
* convert the database entity back to raw data
|
|
49
54
|
*/
|
|
50
|
-
protected
|
|
55
|
+
protected convertEntityToData = (
|
|
51
56
|
entities: ExtractorEntity[]
|
|
52
|
-
)
|
|
57
|
+
): ExtractedData[] => {
|
|
58
|
+
throw Error(
|
|
59
|
+
'You must implement `convertEntityToData` or override `deleteBlockEntities`'
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* insert entities extracted from a block to database
|
|
65
|
+
* @param queryRunner
|
|
66
|
+
* @param boxesToInsert
|
|
67
|
+
* @param block
|
|
68
|
+
* @param extractor
|
|
69
|
+
*/
|
|
70
|
+
protected insertEntities = async (
|
|
71
|
+
queryRunner: QueryRunner,
|
|
72
|
+
boxesToInsert: Array<ExtractedData>,
|
|
73
|
+
block: BlockInfo,
|
|
74
|
+
extractor: string
|
|
75
|
+
) => {
|
|
76
|
+
const repository = queryRunner.manager.getRepository(this.repo);
|
|
77
|
+
await repository.insert(
|
|
78
|
+
this.createEntity(boxesToInsert, block, extractor) as any
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* update entities related to a box
|
|
84
|
+
* @param queryRunner
|
|
85
|
+
* @param updateBox
|
|
86
|
+
* @param block
|
|
87
|
+
* @param extractor
|
|
88
|
+
*/
|
|
89
|
+
protected updateEntity = async (
|
|
90
|
+
queryRunner: QueryRunner,
|
|
91
|
+
updateBox: ExtractedData,
|
|
92
|
+
block: BlockInfo,
|
|
93
|
+
extractor: string
|
|
94
|
+
) => {
|
|
95
|
+
const repository = queryRunner.manager.getRepository(this.repo);
|
|
96
|
+
const box = this.createEntity([updateBox], block, extractor)[0];
|
|
97
|
+
await repository.update(
|
|
98
|
+
{
|
|
99
|
+
boxId: box.boxId,
|
|
100
|
+
extractor: extractor,
|
|
101
|
+
} as FindOptionsWhere<ExtractorEntity>,
|
|
102
|
+
box as any
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* delete all data extracted from a block
|
|
108
|
+
* @param queryRunner
|
|
109
|
+
* @param extractor
|
|
110
|
+
* @param block
|
|
111
|
+
* @returns
|
|
112
|
+
*/
|
|
113
|
+
protected deleteBlockEntities = async (
|
|
114
|
+
queryRunner: QueryRunner,
|
|
115
|
+
extractor: string,
|
|
116
|
+
block: string
|
|
117
|
+
): Promise<ExtractedData[]> => {
|
|
118
|
+
const repository = queryRunner.manager.getRepository(this.repo);
|
|
119
|
+
const deletedData = await repository.find({
|
|
120
|
+
where: { extractor: extractor, block: block } as any,
|
|
121
|
+
});
|
|
122
|
+
await repository.delete({
|
|
123
|
+
extractor: extractor,
|
|
124
|
+
block: block,
|
|
125
|
+
} as any);
|
|
126
|
+
return this.convertEntityToData(deletedData);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* delete all data extracted from a block
|
|
131
|
+
* @param queryRunner
|
|
132
|
+
* @param extractor
|
|
133
|
+
* @param block
|
|
134
|
+
* @returns
|
|
135
|
+
*/
|
|
136
|
+
protected updateBlockEntities = async (
|
|
137
|
+
queryRunner: QueryRunner,
|
|
138
|
+
extractor: string,
|
|
139
|
+
block: string
|
|
140
|
+
): Promise<ExtractorEntity[]> => {
|
|
141
|
+
const repository = queryRunner.manager.getRepository(this.repo);
|
|
142
|
+
const updatedData = await repository.find({
|
|
143
|
+
where: {
|
|
144
|
+
extractor: extractor,
|
|
145
|
+
spendBlock: block,
|
|
146
|
+
block: Not(block),
|
|
147
|
+
} as any,
|
|
148
|
+
});
|
|
149
|
+
await repository.update(
|
|
150
|
+
{
|
|
151
|
+
spendBlock: block,
|
|
152
|
+
extractor: extractor,
|
|
153
|
+
} as FindOptionsWhere<ExtractorEntity>,
|
|
154
|
+
{ spendBlock: null, spendHeight: 0 } as any
|
|
155
|
+
);
|
|
156
|
+
return updatedData;
|
|
157
|
+
};
|
|
53
158
|
|
|
54
159
|
/**
|
|
55
160
|
* insert all extracted box data in an atomic transaction
|
|
@@ -65,7 +170,6 @@ export abstract class AbstractErgoExtractorAction<
|
|
|
65
170
|
block: BlockInfo,
|
|
66
171
|
extractor: string
|
|
67
172
|
): Promise<boolean> => {
|
|
68
|
-
let success = true;
|
|
69
173
|
let boxesToInsert: ExtractedData[] = [],
|
|
70
174
|
boxesToUpdate: ExtractedData[] = [];
|
|
71
175
|
const queryRunner = this.datasource.createQueryRunner();
|
|
@@ -87,9 +191,7 @@ export abstract class AbstractErgoExtractorAction<
|
|
|
87
191
|
|
|
88
192
|
if (boxesToInsert.length > 0) {
|
|
89
193
|
this.logger.debug(`Inserting boxes`);
|
|
90
|
-
await
|
|
91
|
-
this.createEntity(boxesToInsert, block, extractor) as any
|
|
92
|
-
);
|
|
194
|
+
await this.insertEntities(queryRunner, boxesToInsert, block, extractor);
|
|
93
195
|
}
|
|
94
196
|
if (boxesToUpdate.length > 0)
|
|
95
197
|
this.logger.info(
|
|
@@ -97,27 +199,21 @@ export abstract class AbstractErgoExtractorAction<
|
|
|
97
199
|
.map((col) => col.boxId)
|
|
98
200
|
.join(', ')}]`
|
|
99
201
|
);
|
|
100
|
-
for (const box of
|
|
202
|
+
for (const box of boxesToUpdate) {
|
|
101
203
|
this.logger.debug(
|
|
102
204
|
`Updating boxes in database [${JsonBigInt.stringify(box)}]`
|
|
103
205
|
);
|
|
104
|
-
await
|
|
105
|
-
{
|
|
106
|
-
boxId: box.boxId,
|
|
107
|
-
extractor: extractor,
|
|
108
|
-
} as FindOptionsWhere<ExtractorEntity>,
|
|
109
|
-
box as any
|
|
110
|
-
);
|
|
206
|
+
await this.updateEntity(queryRunner, box, block, extractor);
|
|
111
207
|
}
|
|
112
208
|
await queryRunner.commitTransaction();
|
|
209
|
+
return true;
|
|
113
210
|
} catch (e) {
|
|
114
211
|
this.logger.error(`An error occurred during store boxes action: ${e}`);
|
|
115
212
|
await queryRunner.rollbackTransaction();
|
|
116
|
-
|
|
213
|
+
return false;
|
|
117
214
|
} finally {
|
|
118
215
|
await queryRunner.release();
|
|
119
216
|
}
|
|
120
|
-
return success;
|
|
121
217
|
};
|
|
122
218
|
|
|
123
219
|
/**
|
|
@@ -176,33 +272,37 @@ export abstract class AbstractErgoExtractorAction<
|
|
|
176
272
|
block: string,
|
|
177
273
|
extractor: string
|
|
178
274
|
): Promise<{ deletedData: ExtractedData[]; updatedData: BoxInfo[] }> => {
|
|
179
|
-
this.
|
|
180
|
-
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
block
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
{
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
275
|
+
const queryRunner = this.datasource.createQueryRunner();
|
|
276
|
+
await queryRunner.connect();
|
|
277
|
+
await queryRunner.startTransaction();
|
|
278
|
+
try {
|
|
279
|
+
this.logger.info(
|
|
280
|
+
`Deleting boxes in block ${block} and extractor ${extractor}`
|
|
281
|
+
);
|
|
282
|
+
const updatedData = await this.updateBlockEntities(
|
|
283
|
+
queryRunner,
|
|
284
|
+
extractor,
|
|
285
|
+
block
|
|
286
|
+
);
|
|
287
|
+
const deletedData = await this.deleteBlockEntities(
|
|
288
|
+
queryRunner,
|
|
289
|
+
extractor,
|
|
290
|
+
block
|
|
291
|
+
);
|
|
292
|
+
await queryRunner.commitTransaction();
|
|
293
|
+
return {
|
|
294
|
+
deletedData,
|
|
295
|
+
updatedData: updatedData.map((data) => pick(data, 'boxId')),
|
|
296
|
+
};
|
|
297
|
+
} catch (error) {
|
|
298
|
+
await queryRunner.rollbackTransaction();
|
|
299
|
+
this.logger.error(
|
|
300
|
+
`An error occurred while deleting data extracted from block ${block}`,
|
|
301
|
+
error
|
|
302
|
+
);
|
|
303
|
+
throw error;
|
|
304
|
+
} finally {
|
|
305
|
+
await queryRunner.release();
|
|
306
|
+
}
|
|
207
307
|
};
|
|
208
308
|
}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { AbstractLogger } from '@rosen-bridge/abstract-logger';
|
|
2
2
|
import { groupBy, sortBy } from 'lodash-es';
|
|
3
|
+
import { BlockInfo, ErgoNetworkType } from '@rosen-bridge/scanner-interfaces';
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
-
AbstractBoxData,
|
|
6
|
-
ErgoNetworkType,
|
|
7
|
-
ExtendedTransaction,
|
|
8
|
-
} from '../interfaces';
|
|
5
|
+
import { AbstractBoxData, ExtendedTransaction } from '../interfaces';
|
|
9
6
|
import { API_LIMIT, RETRIAL_COUNT } from '../../constants';
|
|
10
7
|
import { AbstractErgoExtractor } from '../AbstractErgoExtractor';
|
|
11
8
|
import { AbstractInitializableErgoExtractorAction } from './AbstractInitializableAction';
|
|
12
|
-
import { BlockInfo } from '../../interfaces';
|
|
13
9
|
import { ExplorerNetwork } from '../network/ExplorerNetwork';
|
|
14
10
|
import { NodeNetwork } from '../network/NodeNetwork';
|
|
15
11
|
import { AbstractErgoExtractorEntity } from '../AbstractErgoExtractorEntity';
|
package/lib/ergo/interfaces.ts
CHANGED
|
@@ -1,40 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Explorer = 'explorer',
|
|
3
|
-
Node = 'node',
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export type InputBox = {
|
|
7
|
-
boxId: string;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export type DataInput = {
|
|
11
|
-
boxId: string;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export type Asset = {
|
|
15
|
-
tokenId: string;
|
|
16
|
-
amount: bigint;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type AdditionalRegisters = {
|
|
20
|
-
R4?: string;
|
|
21
|
-
R5?: string;
|
|
22
|
-
R6?: string;
|
|
23
|
-
R7?: string;
|
|
24
|
-
R8?: string;
|
|
25
|
-
R9?: string;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export type OutputBox = {
|
|
29
|
-
boxId: string;
|
|
30
|
-
value: bigint;
|
|
31
|
-
ergoTree: string;
|
|
32
|
-
creationHeight: number;
|
|
33
|
-
assets?: Array<Asset>;
|
|
34
|
-
additionalRegisters?: AdditionalRegisters;
|
|
35
|
-
transactionId: string;
|
|
36
|
-
index: bigint | number;
|
|
37
|
-
};
|
|
1
|
+
import { OutputBox, Transaction } from '@rosen-bridge/scanner-interfaces';
|
|
38
2
|
|
|
39
3
|
export interface ErgoBox extends OutputBox {
|
|
40
4
|
blockId: string;
|
|
@@ -45,14 +9,6 @@ export interface ErgoBox extends OutputBox {
|
|
|
45
9
|
spentIndex?: number;
|
|
46
10
|
}
|
|
47
11
|
|
|
48
|
-
export type Transaction = {
|
|
49
|
-
id: string;
|
|
50
|
-
inputs: Array<InputBox>;
|
|
51
|
-
dataInputs: Array<DataInput>;
|
|
52
|
-
outputs: Array<OutputBox>;
|
|
53
|
-
size?: bigint;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
12
|
export interface ExtendedTransaction extends Transaction {
|
|
57
13
|
inclusionHeight: number;
|
|
58
14
|
blockId: string;
|
|
@@ -62,7 +18,7 @@ export interface SpendInfo {
|
|
|
62
18
|
boxId: string;
|
|
63
19
|
txId: string;
|
|
64
20
|
index: number;
|
|
65
|
-
extras?: string
|
|
21
|
+
extras?: { [key: string]: string };
|
|
66
22
|
}
|
|
67
23
|
|
|
68
24
|
export interface AbstractBoxData {
|
|
@@ -91,3 +47,5 @@ export type CallbackDataMap<ExtractedData extends AbstractBoxData> = {
|
|
|
91
47
|
export type CallbackMap<ExtractedData extends AbstractBoxData> = {
|
|
92
48
|
[K in CallbackType]: (data: CallbackDataMap<ExtractedData>[K]) => void;
|
|
93
49
|
};
|
|
50
|
+
|
|
51
|
+
export type TxExtra = { [key: string]: string };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import ergoExplorerClientFactory from '@rosen-clients/ergo-explorer';
|
|
2
2
|
import { AbstractNetwork } from './AbstractNetwork';
|
|
3
3
|
import { V1 } from '@rosen-clients/ergo-explorer';
|
|
4
|
+
import { BlockInfo, Transaction } from '@rosen-bridge/scanner-interfaces';
|
|
4
5
|
|
|
5
|
-
import {
|
|
6
|
-
import { ErgoBox, ExtendedTransaction, Transaction } from '../interfaces';
|
|
6
|
+
import { ErgoBox, ExtendedTransaction } from '../interfaces';
|
|
7
7
|
import { mapValues, pick } from 'lodash-es';
|
|
8
8
|
import { API_LIMIT } from '../../constants';
|
|
9
9
|
|
|
@@ -59,7 +59,8 @@ export class ExplorerNetwork extends AbstractNetwork {
|
|
|
59
59
|
box.additionalRegisters,
|
|
60
60
|
'serializedValue'
|
|
61
61
|
),
|
|
62
|
-
assets:
|
|
62
|
+
assets:
|
|
63
|
+
box.assets?.map((asset) => pick(asset, ['tokenId', 'amount'])) ?? [],
|
|
63
64
|
spentHeight: spendInfo?.height,
|
|
64
65
|
spentBlockId: spendInfo?.hash,
|
|
65
66
|
spentTransactionId: box.spentTransactionId,
|
|
@@ -82,6 +83,7 @@ export class ExplorerNetwork extends AbstractNetwork {
|
|
|
82
83
|
tx.dataInputs?.map((dataInput) => ({
|
|
83
84
|
boxId: dataInput.boxId,
|
|
84
85
|
})) ?? [],
|
|
86
|
+
// TODO: Add input extension to explorer local/ergo/rosen-bridge/scanner/-/issues/156
|
|
85
87
|
inputs: tx.inputs?.map((input) => ({ boxId: input.boxId })) ?? [],
|
|
86
88
|
outputs:
|
|
87
89
|
tx.outputs?.map((output) => ({
|
|
@@ -91,9 +93,9 @@ export class ExplorerNetwork extends AbstractNetwork {
|
|
|
91
93
|
output.additionalRegisters,
|
|
92
94
|
'serializedValue'
|
|
93
95
|
),
|
|
94
|
-
assets:
|
|
95
|
-
pick(asset, ['tokenId', 'amount'])
|
|
96
|
-
|
|
96
|
+
assets:
|
|
97
|
+
output.assets?.map((asset) => pick(asset, ['tokenId', 'amount'])) ??
|
|
98
|
+
[],
|
|
97
99
|
ergoTree: output.ergoTree,
|
|
98
100
|
creationHeight: output.creationHeight,
|
|
99
101
|
index: output.index,
|
|
@@ -113,15 +115,16 @@ export class ExplorerNetwork extends AbstractNetwork {
|
|
|
113
115
|
tx.dataInputs?.map((dataInput) => ({
|
|
114
116
|
boxId: dataInput.id,
|
|
115
117
|
})) ?? [],
|
|
118
|
+
// TODO: Add input extension local/ergo/rosen-bridge/scanner/-/issues/156
|
|
116
119
|
inputs: tx.inputs?.map((input) => ({ boxId: input.id })) ?? [],
|
|
117
120
|
outputs:
|
|
118
121
|
tx.outputs?.map((output) => ({
|
|
119
122
|
boxId: output.id,
|
|
120
123
|
transactionId: output.txId,
|
|
121
124
|
additionalRegisters: output.additionalRegisters,
|
|
122
|
-
assets:
|
|
123
|
-
pick(asset, ['tokenId', 'amount'])
|
|
124
|
-
|
|
125
|
+
assets:
|
|
126
|
+
output.assets?.map((asset) => pick(asset, ['tokenId', 'amount'])) ??
|
|
127
|
+
[],
|
|
125
128
|
ergoTree: output.ergoTree,
|
|
126
129
|
creationHeight: output.creationHeight,
|
|
127
130
|
index: output.index,
|
|
@@ -2,8 +2,8 @@ import ergoNodeClientFactory, {
|
|
|
2
2
|
IndexedErgoBox,
|
|
3
3
|
IndexedErgoTransaction,
|
|
4
4
|
} from '@rosen-clients/ergo-node';
|
|
5
|
+
import { BlockInfo } from '@rosen-bridge/scanner-interfaces';
|
|
5
6
|
|
|
6
|
-
import { BlockInfo } from '../../interfaces';
|
|
7
7
|
import { ErgoBox, ExtendedTransaction } from '../interfaces';
|
|
8
8
|
import { AbstractNetwork } from './AbstractNetwork';
|
|
9
9
|
|
|
@@ -64,7 +64,8 @@ export class NodeNetwork extends AbstractNetwork {
|
|
|
64
64
|
additionalRegisters: output.additionalRegisters,
|
|
65
65
|
boxId: output.boxId || '',
|
|
66
66
|
})),
|
|
67
|
-
|
|
67
|
+
// TODO: Add input extension local/ergo/rosen-bridge/scanner/-/issues/156
|
|
68
|
+
inputs: tx.inputs.map((input) => ({ boxId: input.boxId! })) ?? [],
|
|
68
69
|
dataInputs: tx.dataInputs,
|
|
69
70
|
};
|
|
70
71
|
};
|
package/lib/ergo/utils.ts
CHANGED
package/lib/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rosen-bridge/abstract-extractor",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-181e9e8f",
|
|
4
4
|
"description": "Rosen Bridge extractor interfaces to work with scanner",
|
|
5
5
|
"repository": "",
|
|
6
6
|
"license": "GPL-3.0",
|
|
@@ -38,8 +38,9 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@rosen-bridge/abstract-logger": "^2.0.1",
|
|
40
40
|
"@rosen-bridge/json-bigint": "^0.1.0",
|
|
41
|
+
"@rosen-bridge/scanner-interfaces": "^0.1.0",
|
|
41
42
|
"@rosen-clients/ergo-explorer": "^1.1.2",
|
|
42
|
-
"@rosen-clients/ergo-node": "^1.
|
|
43
|
+
"@rosen-clients/ergo-node": "^1.2.0",
|
|
43
44
|
"lodash-es": "^4.17.21",
|
|
44
45
|
"typeorm": "^0.3.20",
|
|
45
46
|
"uuid": "^9.0.0"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { V1 } from '@rosen-clients/ergo-explorer';
|
|
2
|
+
import { BlockInfo, OutputBox } from '@rosen-bridge/scanner-interfaces';
|
|
3
|
+
|
|
2
4
|
import {
|
|
3
5
|
AbstractErgoExtractor,
|
|
4
|
-
BlockInfo,
|
|
5
|
-
OutputBox,
|
|
6
6
|
AbstractBoxData,
|
|
7
7
|
AbstractErgoExtractorAction,
|
|
8
8
|
AbstractErgoExtractorEntity,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { V1 } from '@rosen-clients/ergo-explorer';
|
|
2
2
|
import { describe, it, expect, vitest } from 'vitest';
|
|
3
|
+
import { OutputBox } from '@rosen-bridge/scanner-interfaces';
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
|
-
OutputBox,
|
|
6
6
|
AbstractBoxData,
|
|
7
7
|
AbstractErgoExtractorAction,
|
|
8
8
|
CallbackType,
|
|
@@ -22,7 +22,7 @@ describe('AbstractErgoExtractor', () => {
|
|
|
22
22
|
* - spy `extractBoxData` and `storeBoxes`
|
|
23
23
|
* - run test (call `processTransactions`)
|
|
24
24
|
* @expected
|
|
25
|
-
* - to call `extractBoxData` for the specific box
|
|
25
|
+
* - to call `extractBoxData` for the specific box and all input extensions
|
|
26
26
|
* - to insert the extracted box to database
|
|
27
27
|
* - to return true when total procedure is successful
|
|
28
28
|
* - to trigger `INSERT` callbacks with correct data
|
|
@@ -49,7 +49,11 @@ describe('AbstractErgoExtractor', () => {
|
|
|
49
49
|
const result = await extractor.processTransactions([tx], block);
|
|
50
50
|
|
|
51
51
|
expect(extractSpy).toBeCalledTimes(1);
|
|
52
|
-
expect(extractSpy).toBeCalledWith(
|
|
52
|
+
expect(extractSpy).toBeCalledWith(
|
|
53
|
+
tx.outputs[0],
|
|
54
|
+
[tx.inputs[0].extension, {}],
|
|
55
|
+
{}
|
|
56
|
+
);
|
|
53
57
|
expect(storeSpy).toBeCalledWith([extractedData], block, 'Test');
|
|
54
58
|
expect(result).toEqual(true);
|
|
55
59
|
expect(triggerCallbacks).toBeCalledWith(CallbackType.Insert, [
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { DataSource } from 'typeorm';
|
|
2
2
|
import { pick } from 'lodash-es';
|
|
3
|
+
import { BlockInfo } from '@rosen-bridge/scanner-interfaces';
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
AbstractErgoExtractorAction,
|
|
6
7
|
AbstractErgoExtractorEntity,
|
|
7
|
-
BlockInfo,
|
|
8
8
|
AbstractBoxData,
|
|
9
9
|
} from '../lib';
|
|
10
10
|
import { TestEntity } from './testUtils';
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { V1 } from '@rosen-clients/ergo-explorer';
|
|
2
|
+
import { BlockInfo, OutputBox } from '@rosen-bridge/scanner-interfaces';
|
|
3
|
+
|
|
2
4
|
import {
|
|
3
5
|
AbstractInitializableErgoExtractor,
|
|
4
6
|
AbstractInitializableErgoExtractorAction,
|
|
5
7
|
} from '../../lib/ergo/initializable';
|
|
6
|
-
import {
|
|
7
|
-
OutputBox,
|
|
8
|
-
AbstractBoxData,
|
|
9
|
-
BlockInfo,
|
|
10
|
-
AbstractErgoExtractorEntity,
|
|
11
|
-
} from '../../lib';
|
|
8
|
+
import { AbstractBoxData, AbstractErgoExtractorEntity } from '../../lib';
|
|
12
9
|
import { ergoBoxes } from './testData';
|
|
13
10
|
|
|
14
11
|
export class MockedInitializableErgoExtractor extends AbstractInitializableErgoExtractor<
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DataSource } from 'typeorm';
|
|
2
2
|
import { pick } from 'lodash-es';
|
|
3
|
+
import { BlockInfo } from '@rosen-bridge/scanner-interfaces';
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
AbstractErgoExtractorEntity,
|
|
6
|
-
BlockInfo,
|
|
7
7
|
AbstractBoxData,
|
|
8
8
|
AbstractInitializableErgoExtractorAction,
|
|
9
9
|
} from '../../lib';
|