@ocap/tx-pipeline 1.18.164 → 1.18.165
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.
|
@@ -5,24 +5,27 @@ module.exports = function CreateTakeStateSnapshotPipe({ key = 'stateSnapshot' }
|
|
|
5
5
|
return async function TakeStateSnapshot(context, next) {
|
|
6
6
|
const { statedb, config } = context;
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
// feeVaultState and gasVaultState is usually add to context at the end, so we need to query it here
|
|
9
|
+
if (!context.feeVaultState) {
|
|
10
|
+
context.feeVaultState = await statedb.account.get(config.vaults.txFee, context);
|
|
11
|
+
}
|
|
12
|
+
if (context.gasVault && !context.gasVaultState) {
|
|
13
|
+
context.gasVaultState = await statedb.account.get(context.gasVault, context);
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
const statesMap = groupStatesByAddress(context);
|
|
17
|
+
|
|
15
18
|
// for acquire transactions, we should pre-fetch the account state in the mint hooks to verify their balance changes later
|
|
16
19
|
if (context.factoryState && ['fg:t:acquire_asset_v3', 'fg:t:acquire_asset_v2'].includes(context.txType)) {
|
|
17
20
|
const mintHook = context.factoryState.hooks?.find((x) => x.name === 'mint');
|
|
18
21
|
const states = await Promise.all(
|
|
19
22
|
(mintHook?.compiled || []).map((x) => {
|
|
20
23
|
const address = x.args.to;
|
|
21
|
-
return statesMap[address]
|
|
24
|
+
return statesMap[address] || statedb.account.get(address, context);
|
|
22
25
|
})
|
|
23
26
|
);
|
|
24
27
|
states.forEach((x) => {
|
|
25
|
-
statesMap[x.address] =
|
|
28
|
+
statesMap[x.address] = x;
|
|
26
29
|
});
|
|
27
30
|
}
|
|
28
31
|
|
|
@@ -15,24 +15,25 @@ const { pickBy } = require('lodash');
|
|
|
15
15
|
|
|
16
16
|
function groupStatesByAddress(context) {
|
|
17
17
|
/**
|
|
18
|
-
* a map of address -> state
|
|
19
|
-
* @type {Record<string,
|
|
18
|
+
* a map of address -> state
|
|
19
|
+
* @type {Record<string, any>}
|
|
20
20
|
*/
|
|
21
21
|
const statesMap = {};
|
|
22
22
|
|
|
23
|
-
for (const
|
|
23
|
+
for (const stateOrStates of Object.values(context)) {
|
|
24
24
|
const states = [].concat(stateOrStates).filter((x) => x && x.address && x.tokens && x.context);
|
|
25
25
|
|
|
26
26
|
for (const state of states) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const curStates = statesMap[state.address];
|
|
28
|
+
|
|
29
|
+
if (!curStates) {
|
|
30
|
+
statesMap[state.address] = state;
|
|
30
31
|
continue;
|
|
31
32
|
}
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
// Use the state that recently retrieved from database
|
|
34
|
+
if ((state._retrievedAt || 0) > (curStates._retrievedAt || 0)) {
|
|
35
|
+
statesMap[state.address] = state;
|
|
36
|
+
continue;
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
}
|
|
@@ -46,11 +47,11 @@ function findStates(address, statesMap) {
|
|
|
46
47
|
}
|
|
47
48
|
// Try to find state from migrated addresses
|
|
48
49
|
const matchedAddress = Object.keys(statesMap).find((x) => {
|
|
49
|
-
const state = statesMap[x]
|
|
50
|
+
const state = statesMap[x];
|
|
50
51
|
const relatedAddresses = getRelatedAddresses(state);
|
|
51
52
|
return !state.migratedTo?.length && relatedAddresses.some((y) => isSameDid(y, address));
|
|
52
53
|
});
|
|
53
|
-
return statesMap[matchedAddress]
|
|
54
|
+
return statesMap[matchedAddress];
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
function getStateTokens(state, txType) {
|
|
@@ -74,7 +75,7 @@ function mergeTokenChange(token1, token2, operator = 'add') {
|
|
|
74
75
|
* Update migrated addresses in receipts to their latest addresses
|
|
75
76
|
*/
|
|
76
77
|
function fixMigratedReceipts(receipts, statesMap) {
|
|
77
|
-
const states = Object.values(statesMap)
|
|
78
|
+
const states = Object.values(statesMap);
|
|
78
79
|
const fixedReceipts = receipts.map((receipt) => {
|
|
79
80
|
const state = states.find((x) => {
|
|
80
81
|
const relatedAddresses = getRelatedAddresses(x);
|
|
@@ -109,10 +110,10 @@ module.exports = function CreateVerifyStateDiffPipe({ snapshotKey = 'stateSnapsh
|
|
|
109
110
|
// verify: receipts -> state diff
|
|
110
111
|
// before tokens + receipt changes = after tokens
|
|
111
112
|
for (const [address, tokenChanges] of Object.entries(receiptChanges)) {
|
|
112
|
-
const beforeState = findStates(address, snapshotStates)
|
|
113
|
-
const
|
|
113
|
+
const beforeState = findStates(address, snapshotStates);
|
|
114
|
+
const afterState = findStates(address, contextStates);
|
|
114
115
|
|
|
115
|
-
if (!
|
|
116
|
+
if (!afterState) {
|
|
116
117
|
logger?.error('INVALID_RECEIPT', 'Changed state not found for receipt', {
|
|
117
118
|
address,
|
|
118
119
|
context,
|
|
@@ -126,14 +127,14 @@ module.exports = function CreateVerifyStateDiffPipe({ snapshotKey = 'stateSnapsh
|
|
|
126
127
|
const expectedTokens = beforeState
|
|
127
128
|
? mergeTokenChange(getStateTokens(beforeState, txState.type), tokenChanges)
|
|
128
129
|
: tokenChanges;
|
|
129
|
-
const
|
|
130
|
+
const isMatchExpected = isEqual(expectedTokens, getStateTokens(afterState, txState.type));
|
|
130
131
|
|
|
131
|
-
if (!
|
|
132
|
+
if (!isMatchExpected) {
|
|
132
133
|
logger?.error('INVALID_RECEIPT', 'Tx receipts does not match with state diff', {
|
|
133
134
|
txState,
|
|
134
135
|
expectedTokens,
|
|
135
136
|
beforeState,
|
|
136
|
-
|
|
137
|
+
afterState,
|
|
137
138
|
tokenChanges,
|
|
138
139
|
});
|
|
139
140
|
return next(new Error('INVALID_RECEIPT', 'Tx receipts does not match with state diff'));
|
|
@@ -142,45 +143,37 @@ module.exports = function CreateVerifyStateDiffPipe({ snapshotKey = 'stateSnapsh
|
|
|
142
143
|
|
|
143
144
|
// verify: state diff -> receipts
|
|
144
145
|
// after tokens - before tokens = receipt changes
|
|
145
|
-
for (const [address,
|
|
146
|
-
const beforeState = findStates(address, snapshotStates)[0];
|
|
147
|
-
const beforeTokens = beforeState ? getStateTokens(beforeState, txState.type) : {};
|
|
146
|
+
for (const [address, afterState] of Object.entries(contextStates)) {
|
|
148
147
|
const roleType = toTypeInfo(address).role;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
148
|
+
const beforeState = findStates(address, snapshotStates);
|
|
149
|
+
const beforeTokens = beforeState ? getStateTokens(beforeState, txState.type) : {};
|
|
150
|
+
const afterTokens = getStateTokens(afterState, txState.type);
|
|
151
|
+
|
|
152
|
+
if (!beforeState || !isEqual(afterTokens, beforeTokens)) {
|
|
153
|
+
const tokenChange = pickBy(
|
|
154
|
+
beforeState ? mergeTokenChange(afterTokens, beforeTokens, 'sub') : afterTokens,
|
|
155
|
+
(value) => value !== '0'
|
|
156
|
+
);
|
|
157
|
+
let expectedChange = pickBy(receiptChanges[address] || {}, (value) => value !== '0');
|
|
158
|
+
|
|
159
|
+
// revoke_stake only moves tokens from staked to revoked tokens and without generating any receipts
|
|
160
|
+
// after tokens - before tokens = before revoke tokens - after revoke tokens
|
|
161
|
+
if (txState.type === 'revoke_stake' && roleType === RoleType.ROLE_STAKE) {
|
|
162
|
+
expectedChange = pickBy(
|
|
163
|
+
mergeTokenChange(beforeState.revokedTokens, afterState.revokedTokens, 'sub'),
|
|
160
164
|
(value) => value !== '0'
|
|
161
165
|
);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (!isEqual(tokenChange, expectedChange)) {
|
|
174
|
-
logger?.error('INVALID_RECEIPT', 'State diff does not match with tx receipts', {
|
|
175
|
-
txState,
|
|
176
|
-
beforeState,
|
|
177
|
-
afterState,
|
|
178
|
-
afterStates,
|
|
179
|
-
tokenChange,
|
|
180
|
-
expectedChange,
|
|
181
|
-
});
|
|
182
|
-
return next(new Error('INVALID_RECEIPT', 'State diff does not match with tx receipts'));
|
|
183
|
-
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (!isEqual(tokenChange, expectedChange)) {
|
|
169
|
+
logger?.error('INVALID_RECEIPT', 'State diff does not match with tx receipts', {
|
|
170
|
+
txState,
|
|
171
|
+
beforeState,
|
|
172
|
+
afterState,
|
|
173
|
+
tokenChange,
|
|
174
|
+
expectedChange,
|
|
175
|
+
});
|
|
176
|
+
return next(new Error('INVALID_RECEIPT', 'State diff does not match with tx receipts'));
|
|
184
177
|
}
|
|
185
178
|
}
|
|
186
179
|
}
|
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.165",
|
|
7
7
|
"description": "Pipeline runner and common pipelines to process transactions",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -29,16 +29,16 @@
|
|
|
29
29
|
"elliptic": "6.5.3"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@arcblock/did": "1.18.
|
|
33
|
-
"@arcblock/did-util": "1.18.
|
|
34
|
-
"@ocap/mcrypto": "1.18.
|
|
35
|
-
"@ocap/message": "1.18.
|
|
36
|
-
"@ocap/state": "1.18.
|
|
37
|
-
"@ocap/util": "1.18.
|
|
38
|
-
"@ocap/wallet": "1.18.
|
|
32
|
+
"@arcblock/did": "1.18.165",
|
|
33
|
+
"@arcblock/did-util": "1.18.165",
|
|
34
|
+
"@ocap/mcrypto": "1.18.165",
|
|
35
|
+
"@ocap/message": "1.18.165",
|
|
36
|
+
"@ocap/state": "1.18.165",
|
|
37
|
+
"@ocap/util": "1.18.165",
|
|
38
|
+
"@ocap/wallet": "1.18.165",
|
|
39
39
|
"debug": "^4.3.6",
|
|
40
40
|
"empty-value": "^1.0.1",
|
|
41
41
|
"lodash": "^4.17.21"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "e1a9e9e807ca049f67ffbb5ac556b014461cb7a1"
|
|
44
44
|
}
|