@ocap/tx-protocols 1.13.67 → 1.13.71
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/index.js +8 -0
- package/lib/protocols/asset/acquire-v3.js +8 -8
- package/lib/protocols/governance/stake.js +9 -9
- package/lib/protocols/rollup/claim-reward.js +4 -1
- package/lib/protocols/rollup/create-block.js +59 -55
- package/lib/protocols/rollup/create.js +5 -8
- package/lib/protocols/rollup/migrate-contract.js +53 -0
- package/lib/protocols/rollup/migrate-token.js +66 -0
- package/lib/protocols/rollup/pause.js +52 -0
- package/lib/protocols/rollup/pipes/ensure-validator.js +10 -0
- package/lib/protocols/rollup/resume.js +52 -0
- package/lib/protocols/rollup/update.js +0 -1
- package/package.json +13 -13
package/lib/index.js
CHANGED
|
@@ -23,8 +23,12 @@ const createRollup = require('./protocols/rollup/create');
|
|
|
23
23
|
const updateRollup = require('./protocols/rollup/update');
|
|
24
24
|
const joinRollup = require('./protocols/rollup/join');
|
|
25
25
|
const leaveRollup = require('./protocols/rollup/leave');
|
|
26
|
+
const pauseRollup = require('./protocols/rollup/pause');
|
|
27
|
+
const resumeRollup = require('./protocols/rollup/resume');
|
|
26
28
|
const createRollupBlock = require('./protocols/rollup/create-block');
|
|
27
29
|
const claimBlockReward = require('./protocols/rollup/claim-reward');
|
|
30
|
+
const migrateRollupContract = require('./protocols/rollup/migrate-contract');
|
|
31
|
+
const migrateRollupToken = require('./protocols/rollup/migrate-token');
|
|
28
32
|
|
|
29
33
|
const executor = require('./execute');
|
|
30
34
|
|
|
@@ -67,8 +71,12 @@ const createExecutor = ({ filter, runAsLambda }) => {
|
|
|
67
71
|
updateRollup,
|
|
68
72
|
joinRollup,
|
|
69
73
|
leaveRollup,
|
|
74
|
+
pauseRollup,
|
|
75
|
+
resumeRollup,
|
|
70
76
|
createRollupBlock,
|
|
71
77
|
claimBlockReward,
|
|
78
|
+
migrateRollupContract,
|
|
79
|
+
migrateRollupToken,
|
|
72
80
|
};
|
|
73
81
|
|
|
74
82
|
const execute = executor({ filter, runAsLambda });
|
|
@@ -82,7 +82,7 @@ runner.use(
|
|
|
82
82
|
);
|
|
83
83
|
|
|
84
84
|
// 5. verify sender & signer & owner
|
|
85
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: '
|
|
85
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'OK', table: 'account' })); // prettier-ignore
|
|
86
86
|
runner.use(pipes.ExtractState({ from: 'senders', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
87
87
|
runner.use(pipes.ExtractState({ from: 'itx.owner', to: 'ownerState', status: 'OK', table: 'account' }));
|
|
88
88
|
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
@@ -152,7 +152,7 @@ runner.use(
|
|
|
152
152
|
);
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
-
const isAlsoSigner = !!signerUpdates[
|
|
155
|
+
const isAlsoSigner = !!signerUpdates[tx.from];
|
|
156
156
|
const owner = ownerState ? ownerState.address : itx.owner;
|
|
157
157
|
|
|
158
158
|
// Factory updates
|
|
@@ -166,12 +166,12 @@ runner.use(
|
|
|
166
166
|
|
|
167
167
|
const [newSenderState, newReceiverState, assetState, newSignerStates, newFactoryState, newAssetStates] =
|
|
168
168
|
await Promise.all([
|
|
169
|
-
//
|
|
170
|
-
statedb.account.
|
|
171
|
-
senderState
|
|
172
|
-
account.
|
|
169
|
+
// update sender
|
|
170
|
+
statedb.account.updateOrCreate(
|
|
171
|
+
senderState,
|
|
172
|
+
account.updateOrCreate(
|
|
173
173
|
senderState,
|
|
174
|
-
Object.assign({ nonce: tx.nonce, pk: tx.pk }, signerUpdates[
|
|
174
|
+
Object.assign({ address: tx.from, nonce: tx.nonce, pk: tx.pk }, signerUpdates[tx.from] || {}),
|
|
175
175
|
context
|
|
176
176
|
),
|
|
177
177
|
context
|
|
@@ -192,7 +192,7 @@ runner.use(
|
|
|
192
192
|
// Update signer state
|
|
193
193
|
Promise.all(
|
|
194
194
|
signerStates
|
|
195
|
-
.filter((x) => x.address !==
|
|
195
|
+
.filter((x) => x.address !== tx.from)
|
|
196
196
|
.map((x) =>
|
|
197
197
|
statedb.account.update(x.address, account.update(x, signerUpdates[x.address], context), context)
|
|
198
198
|
)
|
|
@@ -64,9 +64,9 @@ runner.use(pipes.VerifyMultiSigV2({ signersKey: 'senders' }));
|
|
|
64
64
|
runner.use(pipes.ExtractState({ from: 'itx.address', to: 'stakeState', status: 'OK', table: 'stake' }));
|
|
65
65
|
|
|
66
66
|
// 5. verify sender & signer & receiver
|
|
67
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: '
|
|
68
|
-
runner.use(pipes.ExtractState({ from: 'senders', to: 'signerStates', status: 'INVALID_SIGNER_STATE' }));
|
|
69
|
-
runner.use(pipes.ExtractState({ from: 'itx.receiver', to: 'receiverState', status: 'INVALID_RECEIVER_STATE' }));
|
|
67
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'OK', table: 'account' }));
|
|
68
|
+
runner.use(pipes.ExtractState({ from: 'senders', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
69
|
+
runner.use(pipes.ExtractState({ from: 'itx.receiver', to: 'receiverState', status: 'INVALID_RECEIVER_STATE' })); // can by any type
|
|
70
70
|
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
71
71
|
|
|
72
72
|
// 6. verify token state and balance
|
|
@@ -115,15 +115,15 @@ runner.use(
|
|
|
115
115
|
stakeUpdates.assets.push(...assetsList);
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
const isAlsoSigner = !!signerUpdates[
|
|
118
|
+
const isAlsoSigner = !!signerUpdates[tx.from];
|
|
119
119
|
|
|
120
120
|
const [newSenderState, newSignerStates, newStakeState, newAssetStates] = await Promise.all([
|
|
121
121
|
// Update sender state
|
|
122
|
-
statedb.account.
|
|
123
|
-
senderState
|
|
124
|
-
account.
|
|
122
|
+
statedb.account.updateOrCreate(
|
|
123
|
+
senderState,
|
|
124
|
+
account.updateOrCreate(
|
|
125
125
|
senderState,
|
|
126
|
-
Object.assign({ nonce: tx.nonce, pk: tx.pk }, signerUpdates[
|
|
126
|
+
Object.assign({ address: tx.from, nonce: tx.nonce, pk: tx.pk }, signerUpdates[tx.from] || {}),
|
|
127
127
|
context
|
|
128
128
|
),
|
|
129
129
|
context
|
|
@@ -132,7 +132,7 @@ runner.use(
|
|
|
132
132
|
// Update signer state
|
|
133
133
|
Promise.all(
|
|
134
134
|
signerStates
|
|
135
|
-
.filter((x) => x.address !==
|
|
135
|
+
.filter((x) => x.address !== tx.from)
|
|
136
136
|
.map((x) => statedb.account.update(x.address, account.update(x, signerUpdates[x.address], context), context))
|
|
137
137
|
),
|
|
138
138
|
|
|
@@ -264,7 +264,10 @@ runner.use(
|
|
|
264
264
|
),
|
|
265
265
|
]);
|
|
266
266
|
|
|
267
|
-
|
|
267
|
+
// to avoid this to be incorrectly indexed
|
|
268
|
+
delete context.stakeState;
|
|
269
|
+
|
|
270
|
+
context.stakeStates = newStakeStates.filter((x) => updates.stake[x.address]);
|
|
268
271
|
context.accountStates = newAccountStates;
|
|
269
272
|
context.blockState = newBlockState;
|
|
270
273
|
|
|
@@ -252,70 +252,74 @@ runner.use(
|
|
|
252
252
|
const { tx, itx, statedb, rollupState, senderState, stakeStates, txStates, formattedItx } = context;
|
|
253
253
|
const senderStates = context.senderStates || [];
|
|
254
254
|
|
|
255
|
-
const [newSenderState, newStakeStates, newSenderStates, newRollupState, rollupBlockState] =
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
),
|
|
275
|
-
|
|
276
|
-
// update tx owner states: those may get refund
|
|
277
|
-
Promise.all(
|
|
278
|
-
senderStates.map((x) =>
|
|
279
|
-
statedb.account.update(
|
|
280
|
-
x.address,
|
|
281
|
-
account.update(x, applyTokenChange(x, context.accountUpdates[x.address]), context),
|
|
282
|
-
context
|
|
255
|
+
const [newSenderState, newStakeStates, newSenderStates, newRollupState, rollupBlockState, newTxStates] =
|
|
256
|
+
await Promise.all([
|
|
257
|
+
// update sender(proposer) account
|
|
258
|
+
statedb.account.update(
|
|
259
|
+
senderState.address,
|
|
260
|
+
account.update(senderState, Object.assign({ nonce: tx.nonce }), context),
|
|
261
|
+
context
|
|
262
|
+
),
|
|
263
|
+
|
|
264
|
+
// update stake states
|
|
265
|
+
Promise.all(
|
|
266
|
+
stakeStates.map((x) =>
|
|
267
|
+
context.stakeUpdates[x.address]
|
|
268
|
+
? statedb.stake.update(
|
|
269
|
+
x.address,
|
|
270
|
+
stake.update(x, applyTokenChange(x, context.stakeUpdates[x.address]), context),
|
|
271
|
+
context
|
|
272
|
+
)
|
|
273
|
+
: Promise.resolve(x)
|
|
283
274
|
)
|
|
284
|
-
)
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
275
|
+
),
|
|
276
|
+
|
|
277
|
+
// update tx owner states: those may get refund
|
|
278
|
+
Promise.all(
|
|
279
|
+
senderStates.map((x) =>
|
|
280
|
+
statedb.account.update(
|
|
281
|
+
x.address,
|
|
282
|
+
account.update(x, applyTokenChange(x, context.accountUpdates[x.address]), context),
|
|
283
|
+
context
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
),
|
|
287
|
+
|
|
288
|
+
// Update rollup state
|
|
289
|
+
statedb.rollup.update(
|
|
290
|
+
rollupState.address,
|
|
291
|
+
rollup.update(rollupState, { blockHeight: itx.height, blockHash: itx.hash }, context),
|
|
292
|
+
context
|
|
293
|
+
),
|
|
294
|
+
|
|
295
|
+
// Create rollup block
|
|
296
|
+
statedb.rollupBlock.create(
|
|
297
|
+
itx.hash,
|
|
298
|
+
rollupBlock.create(
|
|
299
|
+
{
|
|
300
|
+
...formattedItx,
|
|
301
|
+
...['rewardAmount', 'mintedAmount', 'burnedAmount'].reduce((acc, x) => {
|
|
302
|
+
acc[x] = context[x].toString(10);
|
|
303
|
+
return acc;
|
|
304
|
+
}, {}),
|
|
305
|
+
},
|
|
306
|
+
context
|
|
307
|
+
),
|
|
305
308
|
context
|
|
306
309
|
),
|
|
307
|
-
context
|
|
308
|
-
),
|
|
309
310
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
311
|
+
// Update tx states: mark as finalized
|
|
312
|
+
Promise.all(
|
|
313
|
+
txStates.map((x) => statedb.tx.update(x.hash, Tx.update(x, { finalized: true, tx: x.tx }), context))
|
|
314
|
+
),
|
|
315
|
+
]);
|
|
313
316
|
|
|
314
317
|
context.senderState = newSenderState;
|
|
315
|
-
context.stakeStates = newStakeStates;
|
|
318
|
+
context.stakeStates = newStakeStates.filter((x) => context.stakeUpdates[x.address]);
|
|
316
319
|
context.newSenderStates = newSenderStates;
|
|
317
320
|
context.rollupState = newRollupState;
|
|
318
321
|
context.rollupBlockState = rollupBlockState;
|
|
322
|
+
context.txStates = newTxStates;
|
|
319
323
|
|
|
320
324
|
context.updatedAccounts = [...Object.values(context.stakeUpdates), ...Object.values(context.accountUpdates)];
|
|
321
325
|
|
|
@@ -58,6 +58,7 @@ runner.use(
|
|
|
58
58
|
|
|
59
59
|
// Save for later use
|
|
60
60
|
context.rollupData = itx.data;
|
|
61
|
+
context.seedValidators = itx.seedValidatorsList.map((x) => x.address);
|
|
61
62
|
|
|
62
63
|
return toRollupAddress(itx) === context.itx.address;
|
|
63
64
|
},
|
|
@@ -65,11 +66,10 @@ runner.use(
|
|
|
65
66
|
])
|
|
66
67
|
);
|
|
67
68
|
|
|
68
|
-
// 1. ensure sender exist
|
|
69
|
-
runner.use(
|
|
70
|
-
|
|
71
|
-
);
|
|
72
|
-
runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
|
|
69
|
+
// 1. ensure sender & validators exist
|
|
70
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
71
|
+
runner.use(pipes.ExtractState({ from: 'seedValidators', to: 'validatorStates', status: 'INVALID_VALIDATOR_STATE', table: 'account' })); // prettier-ignore
|
|
72
|
+
runner.use(pipes.VerifyAccountMigration({ signerKey: 'validatorStates', senderKey: 'senderState' }));
|
|
73
73
|
|
|
74
74
|
// 2. ensure token exist and match
|
|
75
75
|
runner.use(pipes.ExtractState({ from: 'itx.tokenAddress', to: 'tokenState', status: 'INVALID_TOKEN', table: 'token' }));
|
|
@@ -125,9 +125,6 @@ runner.use(
|
|
|
125
125
|
rollup.create(
|
|
126
126
|
{
|
|
127
127
|
...formattedItx,
|
|
128
|
-
paused: false,
|
|
129
|
-
blockHeight: 0,
|
|
130
|
-
blockHash: '',
|
|
131
128
|
issuer: senderState.address,
|
|
132
129
|
validators: formattedItx.seedValidators,
|
|
133
130
|
data: rollupData,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const Error = require('@ocap/util/lib/error');
|
|
2
|
+
const Joi = require('@ocap/validator');
|
|
3
|
+
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
4
|
+
const { account, rollup } = require('@ocap/state');
|
|
5
|
+
|
|
6
|
+
const VerifySigners = require('./pipes/verify-signers');
|
|
7
|
+
const EnsureValidator = require('./pipes/ensure-validator');
|
|
8
|
+
|
|
9
|
+
const runner = new Runner();
|
|
10
|
+
|
|
11
|
+
// 1. verify itx
|
|
12
|
+
const schema = Joi.object({
|
|
13
|
+
rollup: Joi.DID().role('ROLE_ROLLUP').required(),
|
|
14
|
+
to: Joi.DID().wallet('ethereum').required(),
|
|
15
|
+
data: Joi.any().optional(),
|
|
16
|
+
}).options({ stripUnknown: true, noDefaults: false });
|
|
17
|
+
runner.use(({ itx }, next) => {
|
|
18
|
+
const { error } = schema.validate(itx);
|
|
19
|
+
return next(error ? new Error('INVALID_TX', `Invalid itx: ${error.message}`) : null);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// 2. verify rollup
|
|
23
|
+
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
24
|
+
runner.use(EnsureValidator(true));
|
|
25
|
+
|
|
26
|
+
// 3. verify tx signers and signatures
|
|
27
|
+
runner.use(VerifySigners({ signersKey: 'tx.signaturesList', allowSender: true }));
|
|
28
|
+
runner.use(pipes.VerifyMultiSigV2({ signersKey: 'signers' }));
|
|
29
|
+
|
|
30
|
+
// 4. verify sender and signer states
|
|
31
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
32
|
+
runner.use(pipes.ExtractState({ from: 'signers', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
33
|
+
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
34
|
+
|
|
35
|
+
// 5. update rollup state
|
|
36
|
+
runner.use(
|
|
37
|
+
async (context, next) => {
|
|
38
|
+
const { tx, itx, rollupState, statedb, senderState } = context;
|
|
39
|
+
|
|
40
|
+
const [newSenderState, newRollupState] = await Promise.all([
|
|
41
|
+
statedb.account.update(senderState.address, account.update(senderState, { nonce: tx.nonce }, context), context),
|
|
42
|
+
statedb.rollup.update(itx.rollup, rollup.migrate(rollupState, itx.to, context), context),
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
context.senderState = newSenderState;
|
|
46
|
+
context.rollupState = newRollupState;
|
|
47
|
+
|
|
48
|
+
next();
|
|
49
|
+
},
|
|
50
|
+
{ persistError: true }
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
module.exports = runner;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const Error = require('@ocap/util/lib/error');
|
|
2
|
+
const Joi = require('@ocap/validator');
|
|
3
|
+
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
4
|
+
const { account } = require('@ocap/state');
|
|
5
|
+
|
|
6
|
+
const VerifySigners = require('./pipes/verify-signers');
|
|
7
|
+
const EnsureValidator = require('./pipes/ensure-validator');
|
|
8
|
+
|
|
9
|
+
const runner = new Runner();
|
|
10
|
+
|
|
11
|
+
// 1. verify itx
|
|
12
|
+
const schema = Joi.object({
|
|
13
|
+
rollup: Joi.DID().role('ROLE_ROLLUP').required(),
|
|
14
|
+
from: Joi.DID().wallet('ethereum').required(),
|
|
15
|
+
to: Joi.DID().wallet('ethereum').required(),
|
|
16
|
+
token: Joi.object({
|
|
17
|
+
address: Joi.DID().wallet('ethereum').required(),
|
|
18
|
+
value: Joi.BN().positive().required(),
|
|
19
|
+
}),
|
|
20
|
+
data: Joi.any().optional(),
|
|
21
|
+
}).options({ stripUnknown: true, noDefaults: false });
|
|
22
|
+
runner.use(({ itx }, next) => {
|
|
23
|
+
const { error } = schema.validate(itx);
|
|
24
|
+
return next(error ? new Error('INVALID_TX', `Invalid itx: ${error.message}`) : null);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// 2. verify rollup
|
|
28
|
+
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
29
|
+
runner.use(EnsureValidator(true));
|
|
30
|
+
runner.use(({ itx, rollupState }, next) => {
|
|
31
|
+
if (rollupState.migrateHistory.includes(itx.from) === false) {
|
|
32
|
+
return next(new Error('INVALID_MIGRATE_ATTEMPT', 'itx.from must exist in rollup migrate history'));
|
|
33
|
+
}
|
|
34
|
+
if (itx.to !== rollupState.contractAddress) {
|
|
35
|
+
return next(new Error('INVALID_MIGRATE_ATTEMPT', 'itx.to must equal to latest rollup contract address'));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return next();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// 3. verify tx signers and signatures
|
|
42
|
+
runner.use(VerifySigners({ signersKey: 'tx.signaturesList', allowSender: true }));
|
|
43
|
+
runner.use(pipes.VerifyMultiSigV2({ signersKey: 'signers' }));
|
|
44
|
+
|
|
45
|
+
// 4. verify sender and signer states
|
|
46
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
47
|
+
runner.use(pipes.ExtractState({ from: 'signers', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
48
|
+
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
49
|
+
|
|
50
|
+
// 5. update state
|
|
51
|
+
runner.use(
|
|
52
|
+
async (context, next) => {
|
|
53
|
+
const { tx, statedb, senderState } = context;
|
|
54
|
+
|
|
55
|
+
const [newSenderState] = await Promise.all([
|
|
56
|
+
statedb.account.update(senderState.address, account.update(senderState, { nonce: tx.nonce }, context), context),
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
context.senderState = newSenderState;
|
|
60
|
+
|
|
61
|
+
next();
|
|
62
|
+
},
|
|
63
|
+
{ persistError: true }
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
module.exports = runner;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const Error = require('@ocap/util/lib/error');
|
|
2
|
+
const Joi = require('@ocap/validator');
|
|
3
|
+
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
4
|
+
const { account, rollup } = require('@ocap/state');
|
|
5
|
+
|
|
6
|
+
const VerifySigners = require('./pipes/verify-signers');
|
|
7
|
+
const EnsureValidator = require('./pipes/ensure-validator');
|
|
8
|
+
|
|
9
|
+
const runner = new Runner();
|
|
10
|
+
|
|
11
|
+
// 1. verify itx
|
|
12
|
+
const schema = Joi.object({
|
|
13
|
+
rollup: Joi.DID().role('ROLE_ROLLUP').required(),
|
|
14
|
+
data: Joi.any().optional(),
|
|
15
|
+
}).options({ stripUnknown: true, noDefaults: false });
|
|
16
|
+
runner.use(({ itx }, next) => {
|
|
17
|
+
const { error } = schema.validate(itx);
|
|
18
|
+
return next(error ? new Error('INVALID_TX', `Invalid itx: ${error.message}`) : null);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// 2. verify rollup
|
|
22
|
+
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
23
|
+
runner.use(EnsureValidator(true));
|
|
24
|
+
|
|
25
|
+
// 3. verify tx signers and signatures
|
|
26
|
+
runner.use(VerifySigners({ signersKey: 'tx.signaturesList', allowSender: true }));
|
|
27
|
+
runner.use(pipes.VerifyMultiSigV2({ signersKey: 'signers' }));
|
|
28
|
+
|
|
29
|
+
// 4. verify sender and signer states
|
|
30
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
31
|
+
runner.use(pipes.ExtractState({ from: 'signers', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
32
|
+
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
33
|
+
|
|
34
|
+
// 5. update rollup state
|
|
35
|
+
runner.use(
|
|
36
|
+
async (context, next) => {
|
|
37
|
+
const { tx, itx, rollupState, statedb, senderState } = context;
|
|
38
|
+
|
|
39
|
+
const [newSenderState, newRollupState] = await Promise.all([
|
|
40
|
+
statedb.account.update(senderState.address, account.update(senderState, { nonce: tx.nonce }, context), context),
|
|
41
|
+
statedb.rollup.update(itx.rollup, rollup.pause(rollupState, context), context),
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
context.senderState = newSenderState;
|
|
45
|
+
context.rollupState = newRollupState;
|
|
46
|
+
|
|
47
|
+
next();
|
|
48
|
+
},
|
|
49
|
+
{ persistError: true }
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
module.exports = runner;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module.exports = (isSeed) => async (context, next) => {
|
|
2
|
+
const { rollupState, tx } = context;
|
|
3
|
+
|
|
4
|
+
const validators = isSeed ? rollupState.seedValidators : rollupState.validators;
|
|
5
|
+
if (validators.some((x) => x.address === tx.from) === false) {
|
|
6
|
+
return next(new Error('INVALID_TX', 'Tx sender is not an expected validator'));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return next();
|
|
10
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const Error = require('@ocap/util/lib/error');
|
|
2
|
+
const Joi = require('@ocap/validator');
|
|
3
|
+
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
4
|
+
const { account, rollup } = require('@ocap/state');
|
|
5
|
+
|
|
6
|
+
const VerifySigners = require('./pipes/verify-signers');
|
|
7
|
+
const EnsureValidator = require('./pipes/ensure-validator');
|
|
8
|
+
|
|
9
|
+
const runner = new Runner();
|
|
10
|
+
|
|
11
|
+
// 1. verify itx
|
|
12
|
+
const schema = Joi.object({
|
|
13
|
+
rollup: Joi.DID().role('ROLE_ROLLUP').required(),
|
|
14
|
+
data: Joi.any().optional(),
|
|
15
|
+
}).options({ stripUnknown: true, noDefaults: false });
|
|
16
|
+
runner.use(({ itx }, next) => {
|
|
17
|
+
const { error } = schema.validate(itx);
|
|
18
|
+
return next(error ? new Error('INVALID_TX', `Invalid itx: ${error.message}`) : null);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// 2. verify rollup
|
|
22
|
+
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
23
|
+
runner.use(EnsureValidator(true));
|
|
24
|
+
|
|
25
|
+
// 3. verify tx signers and signatures
|
|
26
|
+
runner.use(VerifySigners({ signersKey: 'tx.signaturesList', allowSender: true }));
|
|
27
|
+
runner.use(pipes.VerifyMultiSigV2({ signersKey: 'signers' }));
|
|
28
|
+
|
|
29
|
+
// 4. verify sender and signer states
|
|
30
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
31
|
+
runner.use(pipes.ExtractState({ from: 'signers', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
32
|
+
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
33
|
+
|
|
34
|
+
// 5. update rollup state
|
|
35
|
+
runner.use(
|
|
36
|
+
async (context, next) => {
|
|
37
|
+
const { tx, itx, rollupState, statedb, senderState } = context;
|
|
38
|
+
|
|
39
|
+
const [newSenderState, newRollupState] = await Promise.all([
|
|
40
|
+
statedb.account.update(senderState.address, account.update(senderState, { nonce: tx.nonce }, context), context),
|
|
41
|
+
statedb.rollup.update(itx.rollup, rollup.resume(rollupState, context), context),
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
context.senderState = newSenderState;
|
|
45
|
+
context.rollupState = newRollupState;
|
|
46
|
+
|
|
47
|
+
next();
|
|
48
|
+
},
|
|
49
|
+
{ persistError: true }
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
module.exports = runner;
|
|
@@ -15,7 +15,6 @@ const runner = new Runner();
|
|
|
15
15
|
// 1. verify itx: client must use previous rollup state to construct this itx
|
|
16
16
|
const schema = Joi.object({
|
|
17
17
|
rollup: Joi.DID().role('ROLE_ROLLUP').required(),
|
|
18
|
-
paused: Joi.boolean().required(),
|
|
19
18
|
|
|
20
19
|
minStakeAmount: Joi.BN().greater(0).required(),
|
|
21
20
|
maxStakeAmount: Joi.BN().greater(Joi.ref('minStakeAmount')).required(),
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.13.
|
|
6
|
+
"version": "1.13.71",
|
|
7
7
|
"description": "Predefined tx pipeline sets to execute certain type of transactions",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,17 +19,17 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@arcblock/did": "1.13.
|
|
23
|
-
"@arcblock/did-util": "1.13.
|
|
24
|
-
"@ocap/asset": "1.13.
|
|
25
|
-
"@ocap/mcrypto": "1.13.
|
|
26
|
-
"@ocap/merkle-tree": "1.13.
|
|
27
|
-
"@ocap/message": "1.13.
|
|
28
|
-
"@ocap/state": "1.13.
|
|
29
|
-
"@ocap/tx-pipeline": "1.13.
|
|
30
|
-
"@ocap/util": "1.13.
|
|
31
|
-
"@ocap/validator": "1.13.
|
|
32
|
-
"@ocap/wallet": "1.13.
|
|
22
|
+
"@arcblock/did": "1.13.71",
|
|
23
|
+
"@arcblock/did-util": "1.13.71",
|
|
24
|
+
"@ocap/asset": "1.13.71",
|
|
25
|
+
"@ocap/mcrypto": "1.13.71",
|
|
26
|
+
"@ocap/merkle-tree": "1.13.71",
|
|
27
|
+
"@ocap/message": "1.13.71",
|
|
28
|
+
"@ocap/state": "1.13.71",
|
|
29
|
+
"@ocap/tx-pipeline": "1.13.71",
|
|
30
|
+
"@ocap/util": "1.13.71",
|
|
31
|
+
"@ocap/validator": "1.13.71",
|
|
32
|
+
"@ocap/wallet": "1.13.71",
|
|
33
33
|
"debug": "^4.3.2",
|
|
34
34
|
"empty-value": "^1.0.1",
|
|
35
35
|
"lodash": "^4.17.21",
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"jest": "^27.3.1"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "82321f1dcd59ae272e87372bafaacc562e99c9ee"
|
|
46
46
|
}
|