@ocap/resolver 1.6.5 → 1.6.10
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/lib/hooks.js +308 -0
- package/lib/index.js +719 -177
- package/lib/token-cache.js +38 -0
- package/package.json +15 -10
package/lib/hooks.js
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/* eslint-disable consistent-return */
|
|
2
|
+
// Purpose of these hooks: update indexdb to speed up subsequent queries
|
|
3
|
+
// RULE: do not try to update statedb in these hooks
|
|
4
|
+
|
|
5
|
+
const merge = require('lodash/merge');
|
|
6
|
+
const pick = require('lodash/pick');
|
|
7
|
+
const { BN } = require('@ocap/util');
|
|
8
|
+
const { toStakeAddress } = require('@arcblock/did-util');
|
|
9
|
+
|
|
10
|
+
const debug = require('debug')(require('../package.json').name);
|
|
11
|
+
|
|
12
|
+
const onCreateRollup = async (rollup, ctx, indexdb) => {
|
|
13
|
+
rollup.seedValidators.forEach(async (x) => {
|
|
14
|
+
const { pk, address, endpoint } = x;
|
|
15
|
+
try {
|
|
16
|
+
const account = await indexdb.account.get(address);
|
|
17
|
+
|
|
18
|
+
await indexdb.rollupValidator.insert({
|
|
19
|
+
rollup: rollup.address,
|
|
20
|
+
|
|
21
|
+
pk,
|
|
22
|
+
address,
|
|
23
|
+
endpoint,
|
|
24
|
+
moniker: account.moniker,
|
|
25
|
+
|
|
26
|
+
joinTime: rollup.genesisTime,
|
|
27
|
+
leaveTime: '',
|
|
28
|
+
genesisTime: account.genesisTime,
|
|
29
|
+
renaissanceTime: account.renaissanceTime,
|
|
30
|
+
|
|
31
|
+
totalStake: '0',
|
|
32
|
+
revokedStake: '0',
|
|
33
|
+
availableStake: '0',
|
|
34
|
+
|
|
35
|
+
totalGain: '0',
|
|
36
|
+
|
|
37
|
+
proposedBlockCount: 0,
|
|
38
|
+
verifiedBlockCount: 0,
|
|
39
|
+
|
|
40
|
+
latestBlockHeight: 0,
|
|
41
|
+
latestBlockHash: '',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
debug('create rollup validator', address);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.error('create rollup validator error', err);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const ensureRollupValidator = async (address, rollupAddress, ctx, indexdb, upsert = true) => {
|
|
52
|
+
const doc = await indexdb.rollupValidator.get(address);
|
|
53
|
+
if (doc) {
|
|
54
|
+
if (!doc.pk || !doc.endpoint) {
|
|
55
|
+
const rollup = await indexdb.rollup.get(rollupAddress);
|
|
56
|
+
const validator = rollup.validators.find((v) => v.address === address);
|
|
57
|
+
doc.pk = validator.pk;
|
|
58
|
+
doc.endpoint = validator.endpoint;
|
|
59
|
+
doc.rollup = rollup.address;
|
|
60
|
+
return indexdb.rollupValidator.update(address, doc);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return doc;
|
|
64
|
+
}
|
|
65
|
+
if (upsert === false) {
|
|
66
|
+
throw new Error('Rollup validator not found and upsert is disabled');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const stakeAddress = toStakeAddress(address, rollupAddress);
|
|
70
|
+
const [rollup, stake, account] = await Promise.all([
|
|
71
|
+
indexdb.rollup.get(rollupAddress),
|
|
72
|
+
indexdb.stake.get(stakeAddress),
|
|
73
|
+
indexdb.account.get(address),
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
const token = stake.tokens.find((t) => t.address === rollup.tokenAddress);
|
|
77
|
+
const validator = rollup.validators.find((v) => v.address === address);
|
|
78
|
+
|
|
79
|
+
debug('ensure rollup validator', { txType: ctx.txType, address, rollupAddress, validator, token });
|
|
80
|
+
|
|
81
|
+
return indexdb.rollupValidator.insert({
|
|
82
|
+
rollup: rollup.address,
|
|
83
|
+
|
|
84
|
+
address,
|
|
85
|
+
pk: validator ? validator.pk : '',
|
|
86
|
+
endpoint: validator ? validator.endpoint : '',
|
|
87
|
+
moniker: account.moniker,
|
|
88
|
+
|
|
89
|
+
joinTime: '',
|
|
90
|
+
leaveTime: '',
|
|
91
|
+
genesisTime: ctx.txState.time,
|
|
92
|
+
renaissanceTime: ctx.txState.time,
|
|
93
|
+
|
|
94
|
+
totalStake: token.amount,
|
|
95
|
+
revokedStake: '0',
|
|
96
|
+
availableStake: '0',
|
|
97
|
+
|
|
98
|
+
totalGain: '0',
|
|
99
|
+
|
|
100
|
+
proposedBlockCount: 0,
|
|
101
|
+
verifiedBlockCount: 0,
|
|
102
|
+
|
|
103
|
+
latestBlockHeight: 0,
|
|
104
|
+
latestBlockHash: '',
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const onCreateRollupBlock = async (block, ctx, indexdb) => {
|
|
109
|
+
const { validators, proposer } = block;
|
|
110
|
+
const { rollupState, txStates } = ctx;
|
|
111
|
+
|
|
112
|
+
validators.forEach(async (address) => {
|
|
113
|
+
try {
|
|
114
|
+
const doc = await ensureRollupValidator(address, rollupState.address, ctx, indexdb);
|
|
115
|
+
|
|
116
|
+
doc.rollup = rollupState.address;
|
|
117
|
+
doc.renaissanceTime = block.genesisTime;
|
|
118
|
+
doc.verifiedBlockCount += 1;
|
|
119
|
+
if (address === proposer) {
|
|
120
|
+
doc.latestBlockHeight = block.height;
|
|
121
|
+
doc.latestBlockHash = block.hash;
|
|
122
|
+
doc.proposedBlockCount += 1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
await indexdb.rollupValidator.update(address, doc);
|
|
126
|
+
debug('update rollup validator on new block', address);
|
|
127
|
+
} catch (err) {
|
|
128
|
+
console.error('update rollup validator error', err);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Withdraw tx.actualFee needs to be reindexed
|
|
133
|
+
if (Array.isArray(txStates)) {
|
|
134
|
+
txStates
|
|
135
|
+
.filter((x) => x.type === 'withdraw_token_v2')
|
|
136
|
+
.forEach(async (x) => {
|
|
137
|
+
try {
|
|
138
|
+
const doc = await indexdb.tx.get(x.hash);
|
|
139
|
+
const updates = merge(doc, pick(x, ['tx.itxJson.actualFee']));
|
|
140
|
+
await indexdb.tx.update(x.hash, updates);
|
|
141
|
+
debug('update tx on new block', x.hash);
|
|
142
|
+
} catch (err) {
|
|
143
|
+
console.error('update tx on new block error', err);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const updateRollupStats = async (address, value, key, indexdb) => {
|
|
150
|
+
try {
|
|
151
|
+
const doc = await indexdb.rollup.get(address);
|
|
152
|
+
doc[key] = new BN(doc[key] || '0').add(new BN(value)).toString(10);
|
|
153
|
+
await indexdb.rollup.update(address, doc);
|
|
154
|
+
debug('update rollup', address);
|
|
155
|
+
} catch (err) {
|
|
156
|
+
console.error('update rollup error', err);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const onDepositTokenV2 = async (tx, ctx, indexdb) => {
|
|
161
|
+
const { signatures } = tx.tx;
|
|
162
|
+
const { rollupState } = ctx;
|
|
163
|
+
signatures.forEach(async ({ signer: address }) => {
|
|
164
|
+
try {
|
|
165
|
+
const doc = await ensureRollupValidator(address, rollupState.address, ctx, indexdb);
|
|
166
|
+
doc.renaissanceTime = tx.time;
|
|
167
|
+
|
|
168
|
+
await indexdb.rollupValidator.update(address, doc);
|
|
169
|
+
debug('update rollup validator on deposit', address);
|
|
170
|
+
} catch (err) {
|
|
171
|
+
console.error('update rollup validator error', err);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// totalDepositAmount should include txFee
|
|
176
|
+
const amount = new BN(tx.tx.itxJson.token.value).add(new BN(tx.tx.itxJson.actualFee));
|
|
177
|
+
await updateRollupStats(ctx.rollupState.address, amount.toString(), 'totalDepositAmount', indexdb);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const onClaimBlockReward = async (tx, ctx, indexdb) => {
|
|
181
|
+
const { rollupState, blockState } = ctx;
|
|
182
|
+
const { signatures } = blockState;
|
|
183
|
+
// TODO: delegation is not supported here
|
|
184
|
+
signatures.forEach(async ({ signer }) => {
|
|
185
|
+
try {
|
|
186
|
+
const doc = await ensureRollupValidator(signer, rollupState.address, ctx, indexdb);
|
|
187
|
+
|
|
188
|
+
const receipt = tx.receipts.find((x) => x.address === signer);
|
|
189
|
+
if (receipt) {
|
|
190
|
+
const change = receipt.changes.find((x) => x.target === rollupState.tokenAddress);
|
|
191
|
+
doc.totalGain = new BN(doc.totalGain).add(new BN(change.value).abs()).toString(10);
|
|
192
|
+
await indexdb.rollupValidator.update(signer, doc);
|
|
193
|
+
debug('update rollup validator on claim reward', signer);
|
|
194
|
+
}
|
|
195
|
+
} catch (err) {
|
|
196
|
+
console.error('update rollup validator on claim reward error', err);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const onJoinRollup = async (tx, ctx, indexdb) => {
|
|
202
|
+
try {
|
|
203
|
+
const address = tx.tx.from;
|
|
204
|
+
const doc = await ensureRollupValidator(address, tx.tx.itxJson.rollup, ctx, indexdb);
|
|
205
|
+
|
|
206
|
+
doc.endpoint = tx.tx.itxJson.endpoint;
|
|
207
|
+
doc.joinTime = tx.time;
|
|
208
|
+
doc.renaissanceTime = tx.time;
|
|
209
|
+
doc.leaveTime = '';
|
|
210
|
+
|
|
211
|
+
await indexdb.rollupValidator.update(address, doc);
|
|
212
|
+
debug('join rollup validator', address);
|
|
213
|
+
} catch (err) {
|
|
214
|
+
console.error('join rollup validator error', err);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const onLeaveRollup = async (tx, ctx, indexdb) => {
|
|
219
|
+
try {
|
|
220
|
+
const address = tx.tx.from;
|
|
221
|
+
const doc = await ensureRollupValidator(address, tx.tx.itxJson.rollup, ctx, indexdb);
|
|
222
|
+
|
|
223
|
+
doc.leaveTime = tx.time;
|
|
224
|
+
doc.renaissanceTime = tx.time;
|
|
225
|
+
|
|
226
|
+
await indexdb.rollupValidator.update(address, doc);
|
|
227
|
+
debug('leave rollup validator', address);
|
|
228
|
+
} catch (err) {
|
|
229
|
+
console.error('leave rollup validator error', err);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const onStake = async (tx, ctx, indexdb) => {
|
|
234
|
+
try {
|
|
235
|
+
const rollup = await indexdb.rollup.get(tx.tx.itxJson.receiver);
|
|
236
|
+
if (!rollup) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const address = tx.tx.from;
|
|
241
|
+
if (rollup.validators.find((x) => x.address === address) === undefined) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const stakeAddress = toStakeAddress(address, rollup.address);
|
|
246
|
+
const doc = await ensureRollupValidator(address, rollup.address, ctx, indexdb);
|
|
247
|
+
|
|
248
|
+
const receipt = ctx.txState.receipts.find((x) => x.address === stakeAddress);
|
|
249
|
+
const change = receipt.changes.find((x) => x.target === rollup.tokenAddress);
|
|
250
|
+
doc.totalStake = new BN(doc.totalStake).add(new BN(change.value).abs()).toString(10);
|
|
251
|
+
doc.renaissanceTime = tx.time;
|
|
252
|
+
|
|
253
|
+
await indexdb.rollupValidator.update(address, doc);
|
|
254
|
+
debug('stake rollup validator', address);
|
|
255
|
+
} catch (err) {
|
|
256
|
+
console.error('stake rollup validator error', err);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const onClaimStake = async (tx, ctx, indexdb) => {
|
|
261
|
+
try {
|
|
262
|
+
const stake = await indexdb.stake.get(tx.tx.itxJson.address);
|
|
263
|
+
const rollup = await indexdb.rollup.get(stake.receiver);
|
|
264
|
+
if (!rollup) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const address = tx.tx.from;
|
|
269
|
+
const doc = await ensureRollupValidator(address, rollup.address, ctx, indexdb, false);
|
|
270
|
+
const receipt = ctx.txState.receipts.find((x) => x.address === stake.address);
|
|
271
|
+
const change = receipt.changes.find((x) => x.target === rollup.tokenAddress);
|
|
272
|
+
|
|
273
|
+
doc.renaissanceTime = tx.time;
|
|
274
|
+
doc.revokedStake = new BN(doc.revokedStake).add(new BN(change.value).abs()).toString(10);
|
|
275
|
+
|
|
276
|
+
await indexdb.rollupValidator.update(address, doc);
|
|
277
|
+
debug('revoke-stake rollup validator', address);
|
|
278
|
+
} catch (err) {
|
|
279
|
+
console.error('revoke-stake rollup validator error', err);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const onCreateTx = async (tx, ctx, indexdb) => {
|
|
284
|
+
if (tx.code !== 'OK') {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
switch (tx.tx.itxJson.type_url) {
|
|
289
|
+
case 'fg:t:stake':
|
|
290
|
+
return onStake(tx, ctx, indexdb);
|
|
291
|
+
case 'fg:t:claim_stake':
|
|
292
|
+
return onClaimStake(tx, ctx, indexdb);
|
|
293
|
+
case 'fg:t:join_rollup':
|
|
294
|
+
return onJoinRollup(tx, ctx, indexdb);
|
|
295
|
+
case 'fg:t:leave_rollup':
|
|
296
|
+
return onLeaveRollup(tx, ctx, indexdb);
|
|
297
|
+
case 'fg:t:deposit_token_v2':
|
|
298
|
+
return onDepositTokenV2(tx, ctx, indexdb);
|
|
299
|
+
case 'fg:t:claim_block_reward':
|
|
300
|
+
return onClaimBlockReward(tx, ctx, indexdb);
|
|
301
|
+
case 'fg:t:withdraw_token_v2':
|
|
302
|
+
// totalWithdrawAmount does not include txFee
|
|
303
|
+
return updateRollupStats(ctx.rollupState.address, tx.tx.itxJson.token.value, 'totalWithdrawAmount', indexdb);
|
|
304
|
+
default:
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
module.exports = { onCreateRollup, onCreateTx, onCreateRollupBlock };
|