@ocap/state 1.18.137 → 1.18.138
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/states/tx.js +109 -0
- package/package.json +14 -10
package/lib/states/tx.js
CHANGED
|
@@ -7,8 +7,12 @@ const camelCase = require('lodash/camelCase');
|
|
|
7
7
|
const { fromTypeUrl, formatMessage, decodeAny } = require('@ocap/message');
|
|
8
8
|
const { toBase64, BN, isBN } = require('@ocap/util');
|
|
9
9
|
const { getListField } = require('@ocap/util/lib/get-list-field');
|
|
10
|
+
const { CustomError: Error } = require('@ocap/util/lib/error');
|
|
11
|
+
const { getRelatedAddresses } = require('@ocap/util/lib/get-related-addr');
|
|
12
|
+
const { toTypeInfo, types } = require('@arcblock/did');
|
|
10
13
|
|
|
11
14
|
const ZERO = new BN(0);
|
|
15
|
+
const { RoleType } = types;
|
|
12
16
|
|
|
13
17
|
// Receiver = Whose asset have net gain
|
|
14
18
|
const getTxReceiver = ({ tx, itx, typeUrl }) => {
|
|
@@ -323,6 +327,106 @@ const mergeTxReceipts = (receipts) => {
|
|
|
323
327
|
return Object.values(merged);
|
|
324
328
|
};
|
|
325
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Get list of accounts with migration history
|
|
332
|
+
* @param {Object} ctx - transaction execution context
|
|
333
|
+
* @returns {Promise<string[][]>} adress[][]
|
|
334
|
+
*/
|
|
335
|
+
const getAccountMigrationsFromContext = (ctx) => {
|
|
336
|
+
const migrationAddresses = [];
|
|
337
|
+
for (const [key, state] of Object.entries(ctx)) {
|
|
338
|
+
if (key.endsWith('State') && state?.address) {
|
|
339
|
+
migrationAddresses.push(getRelatedAddresses(state));
|
|
340
|
+
}
|
|
341
|
+
if (key.endsWith('States') && Array.isArray(state)) {
|
|
342
|
+
state.forEach((x) => {
|
|
343
|
+
if (x?.address) {
|
|
344
|
+
migrationAddresses.push(getRelatedAddresses(x));
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return migrationAddresses;
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Group receipts by target
|
|
354
|
+
* @param {Object[]} receipts - transaction receipts
|
|
355
|
+
* @returns {Record<string, { address: string, value: BN, action: string }[]>}
|
|
356
|
+
*/
|
|
357
|
+
const groupReceiptsByTarget = (receipts) => {
|
|
358
|
+
const targets = {};
|
|
359
|
+
|
|
360
|
+
for (const { address, changes } of receipts) {
|
|
361
|
+
for (const { target, value, action } of changes) {
|
|
362
|
+
if (!targets[target]) {
|
|
363
|
+
targets[target] = [];
|
|
364
|
+
}
|
|
365
|
+
targets[target].push({ address, value: new BN(value), action });
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return targets;
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Verify transaction receipts
|
|
373
|
+
* @param {Object[]} receipts - transaction receipts
|
|
374
|
+
* @param {String} typeUrl - transaction type
|
|
375
|
+
* @param {Object} ctx - transaction execution context
|
|
376
|
+
* @returns {Promise<boolean>}
|
|
377
|
+
*/
|
|
378
|
+
const verifyTxReceipts = (receipts, typeUrl, ctx = {}) => {
|
|
379
|
+
const targets = groupReceiptsByTarget(receipts);
|
|
380
|
+
const accountsWithMigration = getAccountMigrationsFromContext(ctx);
|
|
381
|
+
const skipActions =
|
|
382
|
+
{
|
|
383
|
+
MintAssetTx: ['mint', 'consume'],
|
|
384
|
+
AcquireAssetV2Tx: ['mint', 'consume'],
|
|
385
|
+
AcquireAssetV3Tx: ['mint', 'consume'],
|
|
386
|
+
CreateAssetTx: ['create'],
|
|
387
|
+
CreateTokenTx: ['mint'],
|
|
388
|
+
CreateRollupBlockTx: ['burn', 'mint'],
|
|
389
|
+
}[typeUrl] || [];
|
|
390
|
+
|
|
391
|
+
for (const [target, changes] of Object.entries(targets)) {
|
|
392
|
+
// These actions will skip zero-sum calculation
|
|
393
|
+
const filteredChanges = changes.filter(({ action }) => {
|
|
394
|
+
if (!skipActions.includes(action)) return true;
|
|
395
|
+
if (action === 'consume' && toTypeInfo(target).role !== RoleType.ROLE_ASSET) return true;
|
|
396
|
+
return false;
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// Ensure token/asset amounts are zero-sum
|
|
400
|
+
const sum = filteredChanges.reduce((prev, current) => prev.add(current.value), new BN(0));
|
|
401
|
+
if (!sum.eq(ZERO)) {
|
|
402
|
+
throw new Error('INVALID_RECEIPTS_VALUE', `Receipts are not zero-sum, target: ${target}, sum: ${sum}`);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Ensure address is unique
|
|
406
|
+
const accountValue = {};
|
|
407
|
+
for (const { address, value, action } of filteredChanges) {
|
|
408
|
+
const accounts = accountsWithMigration.find((x) => x.includes(address)) || [address];
|
|
409
|
+
for (const account of accounts) {
|
|
410
|
+
const key = `${action}-${account}`;
|
|
411
|
+
const existingValue = accountValue[key];
|
|
412
|
+
if (
|
|
413
|
+
existingValue &&
|
|
414
|
+
((existingValue.gt(ZERO) && value.lt(ZERO)) || (existingValue.lt(ZERO) && value.gt(ZERO)))
|
|
415
|
+
) {
|
|
416
|
+
throw new Error(
|
|
417
|
+
'INVALID_RECEIPTS_ADDRESS',
|
|
418
|
+
`Duplicate accounts in receipts, target: ${target}, address: ${address}, action: ${action}`
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
accountValue[key] = value;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return true;
|
|
428
|
+
};
|
|
429
|
+
|
|
326
430
|
/**
|
|
327
431
|
* Create transaction receipts, each receipt has following properties:
|
|
328
432
|
*
|
|
@@ -440,6 +544,10 @@ const create = (context, code = 'OK') => {
|
|
|
440
544
|
|
|
441
545
|
result.receipts = getTxReceipts(result, context);
|
|
442
546
|
|
|
547
|
+
if (code === 'OK') {
|
|
548
|
+
verifyTxReceipts(result.receipts, typeUrl, context);
|
|
549
|
+
}
|
|
550
|
+
|
|
443
551
|
// determine gasPaid
|
|
444
552
|
attachPaidTxGas(result);
|
|
445
553
|
|
|
@@ -475,4 +583,5 @@ module.exports = {
|
|
|
475
583
|
getTxReceipts,
|
|
476
584
|
mergeTxReceipts,
|
|
477
585
|
attachPaidTxGas,
|
|
586
|
+
verifyTxReceipts,
|
|
478
587
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.18.
|
|
6
|
+
"version": "1.18.138",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -12,24 +12,28 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"lint": "eslint tests lib",
|
|
14
14
|
"lint:fix": "eslint --fix tests lib",
|
|
15
|
+
"start": "node tools/start-chain.js",
|
|
15
16
|
"test": "jest --forceExit --detectOpenHandles",
|
|
16
|
-
"
|
|
17
|
+
"test:ci": "jest --forceExit --detectOpenHandles --coverage",
|
|
18
|
+
"coverage": "start-server-and-test start http://127.0.0.1:4001 test:ci"
|
|
17
19
|
},
|
|
18
20
|
"dependencies": {
|
|
19
|
-
"@arcblock/did": "1.18.
|
|
20
|
-
"@arcblock/validator": "1.18.
|
|
21
|
-
"@ocap/contract": "1.18.
|
|
22
|
-
"@ocap/mcrypto": "1.18.
|
|
23
|
-
"@ocap/message": "1.18.
|
|
24
|
-
"@ocap/util": "1.18.
|
|
21
|
+
"@arcblock/did": "1.18.138",
|
|
22
|
+
"@arcblock/validator": "1.18.138",
|
|
23
|
+
"@ocap/contract": "1.18.138",
|
|
24
|
+
"@ocap/mcrypto": "1.18.138",
|
|
25
|
+
"@ocap/message": "1.18.138",
|
|
26
|
+
"@ocap/util": "1.18.138",
|
|
27
|
+
"@ocap/wallet": "1.18.138",
|
|
25
28
|
"bloom-filters": "^1.3.9",
|
|
26
29
|
"lodash": "^4.17.21"
|
|
27
30
|
},
|
|
28
31
|
"devDependencies": {
|
|
29
|
-
"jest": "^29.7.0"
|
|
32
|
+
"jest": "^29.7.0",
|
|
33
|
+
"start-server-and-test": "^1.14.0"
|
|
30
34
|
},
|
|
31
35
|
"keywords": [],
|
|
32
36
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
33
37
|
"license": "MIT",
|
|
34
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "61ab154a7f575a2e3eb1c9ce86e1cdd2ce18e928"
|
|
35
39
|
}
|