@ocap/tx-protocols 1.18.34 → 1.18.36
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 +4 -4
- package/lib/protocols/rollup/claim-reward.js +4 -0
- package/lib/protocols/rollup/{migrate-token.js → close.js} +36 -18
- package/lib/protocols/rollup/create-block.js +76 -35
- package/lib/protocols/rollup/create.js +1 -1
- package/lib/protocols/rollup/join.js +2 -2
- package/lib/protocols/rollup/leave.js +4 -2
- package/lib/protocols/rollup/{migrate-contract.js → migrate.js} +14 -3
- package/lib/protocols/rollup/pause.js +2 -0
- package/lib/protocols/rollup/pipes/ensure-validator.js +3 -1
- package/lib/protocols/rollup/pipes/verify-status.js +30 -0
- package/lib/protocols/rollup/resume.js +2 -0
- package/lib/protocols/rollup/update.js +4 -0
- package/lib/protocols/token/deposit-v2.js +2 -2
- package/lib/protocols/token/withdraw-v2.js +2 -2
- package/lib/util.js +32 -29
- package/package.json +14 -14
- package/lib/protocols/rollup/pipes/verify-paused.js +0 -10
package/lib/index.js
CHANGED
|
@@ -25,11 +25,11 @@ const updateRollup = require('./protocols/rollup/update');
|
|
|
25
25
|
const joinRollup = require('./protocols/rollup/join');
|
|
26
26
|
const leaveRollup = require('./protocols/rollup/leave');
|
|
27
27
|
const pauseRollup = require('./protocols/rollup/pause');
|
|
28
|
+
const closeRollup = require('./protocols/rollup/close');
|
|
28
29
|
const resumeRollup = require('./protocols/rollup/resume');
|
|
29
30
|
const createRollupBlock = require('./protocols/rollup/create-block');
|
|
30
31
|
const claimBlockReward = require('./protocols/rollup/claim-reward');
|
|
31
|
-
const
|
|
32
|
-
const migrateRollupToken = require('./protocols/rollup/migrate-token');
|
|
32
|
+
const migrateRollup = require('./protocols/rollup/migrate');
|
|
33
33
|
|
|
34
34
|
const executor = require('./execute');
|
|
35
35
|
|
|
@@ -74,11 +74,11 @@ const createExecutor = ({ filter, runAsLambda }) => {
|
|
|
74
74
|
joinRollup,
|
|
75
75
|
leaveRollup,
|
|
76
76
|
pauseRollup,
|
|
77
|
+
closeRollup,
|
|
77
78
|
resumeRollup,
|
|
78
79
|
createRollupBlock,
|
|
79
80
|
claimBlockReward,
|
|
80
|
-
|
|
81
|
-
migrateRollupToken,
|
|
81
|
+
migrateRollup,
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
const execute = executor({ filter, runAsLambda });
|
|
@@ -12,6 +12,8 @@ const debug = require('debug')(`${require('../../../package.json').name}:claim-b
|
|
|
12
12
|
|
|
13
13
|
const { toStakeAddress } = require('@arcblock/did-util');
|
|
14
14
|
const VerifySigners = require('./pipes/verify-signers');
|
|
15
|
+
const VerifyStatus = require('./pipes/verify-status');
|
|
16
|
+
const EnsureValidator = require('./pipes/ensure-validator');
|
|
15
17
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
16
18
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
17
19
|
const { applyTokenChange, splitTxFee, getBNSum, getRewardLocker, RATE_BASE } = require('../../util');
|
|
@@ -58,6 +60,8 @@ runner.use(({ evidenceSeen, blockClaimed }, next) => {
|
|
|
58
60
|
|
|
59
61
|
// 3. verify rollup and block state
|
|
60
62
|
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
63
|
+
runner.use(EnsureValidator());
|
|
64
|
+
runner.use(VerifyStatus({ closed: false }));
|
|
61
65
|
runner.use(pipes.ExtractState({ from: 'itx.blockHash', to: 'blockState', status: 'INVALID_ROLLUP_BLOCK', table: 'rollupBlock' })); // prettier-ignore
|
|
62
66
|
runner.use((context, next) => {
|
|
63
67
|
const { blockState, rollupState, itx } = context;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
const { CustomError: Error } = require('@ocap/util/lib/error');
|
|
2
2
|
const { Joi } = require('@arcblock/validator');
|
|
3
3
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
4
|
-
const { account } = require('@ocap/state');
|
|
4
|
+
const { account, rollup, stake } = require('@ocap/state');
|
|
5
5
|
|
|
6
|
+
const { toStakeAddress } = require('@arcblock/did-util');
|
|
6
7
|
const VerifySigners = require('./pipes/verify-signers');
|
|
8
|
+
const VerifyStatus = require('./pipes/verify-status');
|
|
7
9
|
const EnsureValidator = require('./pipes/ensure-validator');
|
|
8
10
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
9
11
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
@@ -13,8 +15,7 @@ const runner = new Runner();
|
|
|
13
15
|
// 1. verify itx
|
|
14
16
|
const schema = Joi.object({
|
|
15
17
|
rollup: Joi.DID().prefix().role('ROLE_ROLLUP').required(),
|
|
16
|
-
|
|
17
|
-
to: Joi.DID().prefix().wallet('ethereum').required(),
|
|
18
|
+
message: Joi.string().trim().min(1).max(512).required(),
|
|
18
19
|
token: Joi.object({
|
|
19
20
|
address: Joi.DID().prefix().wallet('ethereum').required(),
|
|
20
21
|
value: Joi.BN().positive().required(),
|
|
@@ -29,16 +30,7 @@ runner.use(({ itx }, next) => {
|
|
|
29
30
|
// 2. verify rollup
|
|
30
31
|
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
31
32
|
runner.use(EnsureValidator(true));
|
|
32
|
-
runner.use(({
|
|
33
|
-
if (rollupState.migrateHistory.includes(itx.from) === false) {
|
|
34
|
-
return next(new Error('INVALID_MIGRATE_ATTEMPT', 'itx.from must exist in rollup migrate history'));
|
|
35
|
-
}
|
|
36
|
-
if (itx.to !== rollupState.contractAddress) {
|
|
37
|
-
return next(new Error('INVALID_MIGRATE_ATTEMPT', 'itx.to must equal to latest rollup contract address'));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return next();
|
|
41
|
-
});
|
|
33
|
+
runner.use(VerifyStatus({ paused: true, closed: false }));
|
|
42
34
|
|
|
43
35
|
// 3. verify tx signers and signatures
|
|
44
36
|
runner.use(VerifySigners({ signersKey: 'tx.signaturesList', allowSender: true }));
|
|
@@ -49,25 +41,51 @@ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INV
|
|
|
49
41
|
runner.use(pipes.ExtractState({ from: 'signers', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
50
42
|
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
51
43
|
|
|
52
|
-
//
|
|
53
|
-
runner.use(
|
|
44
|
+
// 5. extract validator stake stakes
|
|
45
|
+
runner.use((context, next) => {
|
|
46
|
+
const { validators, address } = context.rollupState;
|
|
47
|
+
context.stakes = validators.map((x) => toStakeAddress(x.address, address));
|
|
48
|
+
return next();
|
|
49
|
+
});
|
|
50
|
+
runner.use(pipes.ExtractState({ from: 'stakes', to: 'stakeStates', status: 'INVALID_STAKE_STATE', table: 'stake' }));
|
|
51
|
+
|
|
52
|
+
// 6. Ensure tx fee and gas
|
|
53
|
+
runner.use(EnsureTxGas((context) => ({ create: 0, update: context.stakeStates.length + 2, payment: 0 })));
|
|
54
54
|
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
55
55
|
|
|
56
|
-
//
|
|
56
|
+
// 7. update rollup state
|
|
57
57
|
runner.use(
|
|
58
58
|
async (context, next) => {
|
|
59
|
-
const { tx, statedb, senderState, senderUpdates, updateVaults } = context;
|
|
59
|
+
const { tx, itx, rollupState, statedb, senderState, stakeStates, senderUpdates, updateVaults } = context;
|
|
60
60
|
|
|
61
|
-
const [newSenderState] = await Promise.all([
|
|
61
|
+
const [newSenderState, newRollupState, newStakeStates] = await Promise.all([
|
|
62
|
+
// update sender state
|
|
62
63
|
statedb.account.update(
|
|
63
64
|
senderState.address,
|
|
64
65
|
account.update(senderState, { nonce: tx.nonce, ...senderUpdates }, context),
|
|
65
66
|
context
|
|
66
67
|
),
|
|
68
|
+
|
|
69
|
+
// update rollup
|
|
70
|
+
statedb.rollup.update(itx.rollup, rollup.close(rollupState, context), context),
|
|
71
|
+
|
|
72
|
+
// update stake states
|
|
73
|
+
Promise.all(
|
|
74
|
+
stakeStates.map((x) =>
|
|
75
|
+
statedb.stake.update(
|
|
76
|
+
x.address,
|
|
77
|
+
stake.update(x, { revocable: true, leaveWaitingPeriod: rollupState.leaveWaitingPeriod }, context),
|
|
78
|
+
context
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
),
|
|
82
|
+
|
|
67
83
|
updateVaults(),
|
|
68
84
|
]);
|
|
69
85
|
|
|
70
86
|
context.senderState = newSenderState;
|
|
87
|
+
context.rollupState = newRollupState;
|
|
88
|
+
context.stakeStates = newStakeStates;
|
|
71
89
|
|
|
72
90
|
next();
|
|
73
91
|
},
|
|
@@ -14,7 +14,8 @@ const debug = require('debug')(`${require('../../../package.json').name}:create-
|
|
|
14
14
|
|
|
15
15
|
const VerifySigners = require('./pipes/verify-signers');
|
|
16
16
|
const VerifyEvidence = require('./pipes/verify-evidence');
|
|
17
|
-
const
|
|
17
|
+
const VerifyStatus = require('./pipes/verify-status');
|
|
18
|
+
const EnsureValidator = require('./pipes/ensure-validator');
|
|
18
19
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
19
20
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
20
21
|
|
|
@@ -38,6 +39,7 @@ const schema = Joi.object({
|
|
|
38
39
|
signaturesList: schemas.multiSig.min(1).required(),
|
|
39
40
|
rollup: Joi.DID().prefix().role('ROLE_ROLLUP').required(),
|
|
40
41
|
minReward: Joi.BN().min(0).required(),
|
|
42
|
+
governance: Joi.boolean().default(false),
|
|
41
43
|
data: Joi.any().optional(),
|
|
42
44
|
}).options({ stripUnknown: true, noDefaults: false });
|
|
43
45
|
|
|
@@ -81,31 +83,43 @@ runner.use((context, next) => {
|
|
|
81
83
|
|
|
82
84
|
// 2. verify rollup state & height
|
|
83
85
|
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
84
|
-
runner.use(
|
|
86
|
+
runner.use(EnsureValidator());
|
|
87
|
+
runner.use(VerifyStatus({ closed: false }));
|
|
85
88
|
runner.use((context, next) => {
|
|
86
89
|
const { itx, rollupState } = context;
|
|
90
|
+
|
|
87
91
|
if (itx.height !== rollupState.blockHeight + 1) {
|
|
88
92
|
return next(
|
|
89
93
|
new Error('INVALID_TX', `Expect new block height to be ${rollupState.blockHeight + 1}, got ${itx.height}`)
|
|
90
94
|
);
|
|
91
95
|
}
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
if (itx.governance) {
|
|
98
|
+
// ensure minReward for governance block
|
|
99
|
+
if (itx.minReward !== '0') {
|
|
100
|
+
return next(new Error('INVALID_TX', 'itx.minReward should be 0 for governance block'));
|
|
101
|
+
}
|
|
102
|
+
// ensure blockSize for governance block
|
|
103
|
+
if (itx.txsList.length !== 1) {
|
|
104
|
+
return next(new Error('INVALID_TX', 'itx.txs should contain only 1 tx for governance block'));
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
if (rollupState.paused) {
|
|
108
|
+
return next(new Error('INVALID_TX', 'Normal block is only allowed when rollup is not paused'));
|
|
109
|
+
}
|
|
97
110
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
// ensure block size
|
|
112
|
+
const blockSize = itx.txsList.length;
|
|
113
|
+
if (blockSize < rollupState.minBlockSize) {
|
|
114
|
+
return next(
|
|
115
|
+
new Error('INVALID_TX', `Expect at least ${rollupState.minBlockSize} tx in the block, got ${blockSize}`)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
if (blockSize > rollupState.maxBlockSize) {
|
|
119
|
+
return next(
|
|
120
|
+
new Error('INVALID_TX', `Expect at most ${rollupState.maxBlockSize} tx in the block, got ${blockSize}`)
|
|
121
|
+
);
|
|
122
|
+
}
|
|
109
123
|
}
|
|
110
124
|
|
|
111
125
|
return next();
|
|
@@ -146,13 +160,18 @@ runner.use((context, next) => {
|
|
|
146
160
|
);
|
|
147
161
|
}
|
|
148
162
|
|
|
149
|
-
// ensure minBlockInterval
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
163
|
+
// ensure minBlockInterval for normal blocks
|
|
164
|
+
if (itx.governance === false) {
|
|
165
|
+
const minBlockTime = +new Date(previousBlock.context.genesisTime) + rollupState.minBlockInterval * 1000;
|
|
166
|
+
const newBlockTime = +new Date(txTime);
|
|
167
|
+
if (newBlockTime < minBlockTime) {
|
|
168
|
+
return next(
|
|
169
|
+
new Error(
|
|
170
|
+
'INVALID_TX',
|
|
171
|
+
`Block does not comply with minBlockInterval: ${new Date(minBlockTime).toISOString()}`
|
|
172
|
+
)
|
|
173
|
+
);
|
|
174
|
+
}
|
|
156
175
|
}
|
|
157
176
|
}
|
|
158
177
|
|
|
@@ -177,6 +196,9 @@ runner.use(
|
|
|
177
196
|
// 8. verify txs
|
|
178
197
|
runner.use(pipes.ExtractState({ from: 'itx.txsList', to: 'txStates', status: 'INVALID_TX', table: 'tx' }));
|
|
179
198
|
runner.use(({ itx, txStates }, next) => {
|
|
199
|
+
const normalTxTypes = ['deposit_token_v2', 'withdraw_token_v2'];
|
|
200
|
+
const governanceTxTypes = ['pause_rollup', 'resume_rollup', 'migrate_rollup'];
|
|
201
|
+
|
|
180
202
|
// ensure not finalized
|
|
181
203
|
const finalizedTx = txStates.some((x) => x.finalized);
|
|
182
204
|
if (finalizedTx) {
|
|
@@ -189,10 +211,19 @@ runner.use(({ itx, txStates }, next) => {
|
|
|
189
211
|
return next(new Error('INVALID_TX', 'Rollup block can only include successful executed transactions'));
|
|
190
212
|
}
|
|
191
213
|
|
|
192
|
-
// ensure tx
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
214
|
+
// ensure governance block only contains governance tx
|
|
215
|
+
if (itx.governance) {
|
|
216
|
+
if (txStates.some((x) => governanceTxTypes.includes(x.type) === false)) {
|
|
217
|
+
return next(
|
|
218
|
+
new Error('INVALID_TX', `Governance block can only include governance txs: ${governanceTxTypes.join(',')}`)
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
// ensure tx type for normal block
|
|
223
|
+
const invalidTypeTx = txStates.some((x) => normalTxTypes.includes(x.type) === false);
|
|
224
|
+
if (invalidTypeTx) {
|
|
225
|
+
return next(new Error('INVALID_TX', `Rollup block can only include normal txs: ${normalTxTypes.join(',')}`));
|
|
226
|
+
}
|
|
196
227
|
}
|
|
197
228
|
|
|
198
229
|
// ensure rollup belonging
|
|
@@ -201,15 +232,25 @@ runner.use(({ itx, txStates }, next) => {
|
|
|
201
232
|
return next(new Error('INVALID_TX', `Rollup block can only include tx from rollup ${itx.rollup}`));
|
|
202
233
|
}
|
|
203
234
|
|
|
204
|
-
// ensure merkleRoot
|
|
235
|
+
// ensure merkleRoot: deposit_token tx not included in the merkleTree
|
|
205
236
|
const merkleTree = MerkleTree.getBlockMerkleTree(
|
|
206
237
|
txStates
|
|
207
|
-
.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
238
|
+
.map((x) => {
|
|
239
|
+
if (x.type === 'withdraw_token_v2') {
|
|
240
|
+
return { hash: x.hash, to: x.tx.itxJson.to, amount: x.tx.itxJson.token.value };
|
|
241
|
+
}
|
|
242
|
+
if (x.type === 'pause_rollup') {
|
|
243
|
+
return { hash: x.hash, to: MerkleTree.BLACK_HOLE, amount: '0' };
|
|
244
|
+
}
|
|
245
|
+
if (x.type === 'resume_rollup') {
|
|
246
|
+
return { hash: x.hash, to: MerkleTree.BLACK_HOLE, amount: '0' };
|
|
247
|
+
}
|
|
248
|
+
if (x.type === 'migrate_rollup') {
|
|
249
|
+
return { hash: x.hash, to: x.tx.itxJson.to, amount: '0' };
|
|
250
|
+
}
|
|
251
|
+
return null;
|
|
252
|
+
})
|
|
253
|
+
.filter(Boolean)
|
|
213
254
|
);
|
|
214
255
|
if (merkleTree.getHexRoot() !== itx.merkleRoot) {
|
|
215
256
|
return next(new Error('INVALID_TX', 'Invalid rollup block merkle root'));
|
|
@@ -144,7 +144,7 @@ runner.use(
|
|
|
144
144
|
]);
|
|
145
145
|
|
|
146
146
|
// FIXME: create-rollup 的时候不能校验 stake,还是在这里创建 stake?如果在这里创建 stake,是否需要多签?
|
|
147
|
-
// FIXME:
|
|
147
|
+
// FIXME: account migration 也需要测试下
|
|
148
148
|
|
|
149
149
|
context.senderState = newSenderState;
|
|
150
150
|
context.rollupState = rollupState;
|
|
@@ -14,7 +14,7 @@ const debug = require('debug')(`${require('../../../package.json').name}:join-ro
|
|
|
14
14
|
|
|
15
15
|
const VerifySigners = require('./pipes/verify-signers');
|
|
16
16
|
const VerifyEvidence = require('./pipes/verify-evidence');
|
|
17
|
-
const
|
|
17
|
+
const VerifyStatus = require('./pipes/verify-status');
|
|
18
18
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
19
19
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
20
20
|
|
|
@@ -39,7 +39,7 @@ runner.use(({ itx }, next) => {
|
|
|
39
39
|
|
|
40
40
|
// 2. verify rollup
|
|
41
41
|
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
42
|
-
runner.use(
|
|
42
|
+
runner.use(VerifyStatus({ paused: false }));
|
|
43
43
|
|
|
44
44
|
// 3. verify new validator
|
|
45
45
|
runner.use((context, next) => {
|
|
@@ -11,7 +11,8 @@ const debug = require('debug')(`${require('../../../package.json').name}:leave-r
|
|
|
11
11
|
|
|
12
12
|
const VerifySigners = require('./pipes/verify-signers');
|
|
13
13
|
const VerifyEvidence = require('./pipes/verify-evidence');
|
|
14
|
-
const
|
|
14
|
+
const VerifyStatus = require('./pipes/verify-status');
|
|
15
|
+
const EnsureValidator = require('./pipes/ensure-validator');
|
|
15
16
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
16
17
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
17
18
|
|
|
@@ -33,7 +34,8 @@ runner.use(({ itx }, next) => {
|
|
|
33
34
|
|
|
34
35
|
// 2. verify rollup
|
|
35
36
|
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
36
|
-
runner.use(
|
|
37
|
+
runner.use(EnsureValidator());
|
|
38
|
+
runner.use(VerifyStatus({ paused: false }));
|
|
37
39
|
|
|
38
40
|
// 3. verify evidence signers, signatures, state
|
|
39
41
|
runner.use((context, next) => {
|
|
@@ -4,6 +4,7 @@ const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
|
4
4
|
const { account, rollup } = require('@ocap/state');
|
|
5
5
|
|
|
6
6
|
const VerifySigners = require('./pipes/verify-signers');
|
|
7
|
+
const VerifyStatus = require('./pipes/verify-status');
|
|
7
8
|
const EnsureValidator = require('./pipes/ensure-validator');
|
|
8
9
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
9
10
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
@@ -14,6 +15,8 @@ const runner = new Runner();
|
|
|
14
15
|
const schema = Joi.object({
|
|
15
16
|
rollup: Joi.DID().prefix().role('ROLE_ROLLUP').required(),
|
|
16
17
|
to: Joi.DID().prefix().wallet('ethereum').required(),
|
|
18
|
+
type: Joi.string().trim().valid('vault', 'contract').required(),
|
|
19
|
+
message: Joi.string().trim().min(1).max(512).required(),
|
|
17
20
|
data: Joi.any().optional(),
|
|
18
21
|
}).options({ stripUnknown: true, noDefaults: false });
|
|
19
22
|
runner.use(({ itx }, next) => {
|
|
@@ -24,6 +27,7 @@ runner.use(({ itx }, next) => {
|
|
|
24
27
|
// 2. verify rollup
|
|
25
28
|
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
26
29
|
runner.use(EnsureValidator(true));
|
|
30
|
+
runner.use(VerifyStatus({ paused: true, closed: false }));
|
|
27
31
|
|
|
28
32
|
// 3. verify tx signers and signatures
|
|
29
33
|
runner.use(VerifySigners({ signersKey: 'tx.signaturesList', allowSender: true }));
|
|
@@ -38,10 +42,17 @@ runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey:
|
|
|
38
42
|
runner.use(EnsureTxGas(() => ({ create: 0, update: 2, payment: 0 })));
|
|
39
43
|
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
40
44
|
|
|
41
|
-
// 5. update
|
|
45
|
+
// 5. update state
|
|
42
46
|
runner.use(
|
|
43
47
|
async (context, next) => {
|
|
44
|
-
const { tx, itx,
|
|
48
|
+
const { tx, itx, statedb, rollupState, senderState, senderUpdates, updateVaults } = context;
|
|
49
|
+
let updates = {};
|
|
50
|
+
if (itx.type === 'vault') {
|
|
51
|
+
updates = rollup.migrateVault(rollupState, itx.to, context);
|
|
52
|
+
}
|
|
53
|
+
if (itx.type === 'contract') {
|
|
54
|
+
updates = rollup.migrateContract(rollupState, itx.to, context);
|
|
55
|
+
}
|
|
45
56
|
|
|
46
57
|
const [newSenderState, newRollupState] = await Promise.all([
|
|
47
58
|
statedb.account.update(
|
|
@@ -49,7 +60,7 @@ runner.use(
|
|
|
49
60
|
account.update(senderState, { nonce: tx.nonce, ...senderUpdates }, context),
|
|
50
61
|
context
|
|
51
62
|
),
|
|
52
|
-
statedb.rollup.update(itx.rollup,
|
|
63
|
+
statedb.rollup.update(itx.rollup, updates, context),
|
|
53
64
|
updateVaults(),
|
|
54
65
|
]);
|
|
55
66
|
|
|
@@ -4,6 +4,7 @@ const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
|
4
4
|
const { account, rollup } = require('@ocap/state');
|
|
5
5
|
|
|
6
6
|
const VerifySigners = require('./pipes/verify-signers');
|
|
7
|
+
const VerifyStatus = require('./pipes/verify-status');
|
|
7
8
|
const EnsureValidator = require('./pipes/ensure-validator');
|
|
8
9
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
9
10
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
@@ -23,6 +24,7 @@ runner.use(({ itx }, next) => {
|
|
|
23
24
|
// 2. verify rollup
|
|
24
25
|
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
25
26
|
runner.use(EnsureValidator(true));
|
|
27
|
+
runner.use(VerifyStatus({ paused: false }));
|
|
26
28
|
|
|
27
29
|
// 3. verify tx signers and signatures
|
|
28
30
|
runner.use(VerifySigners({ signersKey: 'tx.signaturesList', allowSender: true }));
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
const { CustomError: Error } = require('@ocap/util/lib/error');
|
|
2
|
+
|
|
3
|
+
module.exports = (isSeed) => (context, next) => {
|
|
2
4
|
const { rollupState, tx } = context;
|
|
3
5
|
|
|
4
6
|
const validators = isSeed ? rollupState.seedValidators : rollupState.validators;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const { pipes } = require('@ocap/tx-pipeline');
|
|
2
|
+
|
|
3
|
+
module.exports = ({ paused, closed } = {}) => {
|
|
4
|
+
const fns = [];
|
|
5
|
+
if (paused === false) {
|
|
6
|
+
fns.push({
|
|
7
|
+
error: 'INVALID_TX',
|
|
8
|
+
message: 'The rollup is paused',
|
|
9
|
+
fn: (context) => !context.rollupState.paused,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (paused === true) {
|
|
14
|
+
fns.push({
|
|
15
|
+
error: 'INVALID_TX',
|
|
16
|
+
message: 'The rollup is not paused',
|
|
17
|
+
fn: (context) => context.rollupState.paused,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (closed === false) {
|
|
22
|
+
fns.push({
|
|
23
|
+
error: 'INVALID_TX',
|
|
24
|
+
message: 'The rollup is closed',
|
|
25
|
+
fn: (context) => !context.rollupState.closed,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return pipes.VerifyInfo(fns);
|
|
30
|
+
};
|
|
@@ -4,6 +4,7 @@ const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
|
4
4
|
const { account, rollup } = require('@ocap/state');
|
|
5
5
|
|
|
6
6
|
const VerifySigners = require('./pipes/verify-signers');
|
|
7
|
+
const VerifyStatus = require('./pipes/verify-status');
|
|
7
8
|
const EnsureValidator = require('./pipes/ensure-validator');
|
|
8
9
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
9
10
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
@@ -23,6 +24,7 @@ runner.use(({ itx }, next) => {
|
|
|
23
24
|
// 2. verify rollup
|
|
24
25
|
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
25
26
|
runner.use(EnsureValidator(true));
|
|
27
|
+
runner.use(VerifyStatus({ paused: true, closed: false }));
|
|
26
28
|
|
|
27
29
|
// 3. verify tx signers and signatures
|
|
28
30
|
runner.use(VerifySigners({ signersKey: 'tx.signaturesList', allowSender: true }));
|
|
@@ -7,6 +7,8 @@ const { account, rollup } = require('@ocap/state');
|
|
|
7
7
|
const debug = require('debug')(`${require('../../../package.json').name}:update-rollup`);
|
|
8
8
|
|
|
9
9
|
const VerifySigners = require('./pipes/verify-signers');
|
|
10
|
+
const VerifyStatus = require('./pipes/verify-status');
|
|
11
|
+
const EnsureValidator = require('./pipes/ensure-validator');
|
|
10
12
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
11
13
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
12
14
|
|
|
@@ -62,6 +64,8 @@ runner.use(
|
|
|
62
64
|
|
|
63
65
|
// 2. verify rollup
|
|
64
66
|
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
67
|
+
runner.use(EnsureValidator(true));
|
|
68
|
+
runner.use(VerifyStatus({ paused: false }));
|
|
65
69
|
|
|
66
70
|
// 3. verify tx signers and signatures
|
|
67
71
|
runner.use(VerifySigners({ signersKey: 'tx.signaturesList', allowSender: true }));
|
|
@@ -14,7 +14,7 @@ const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
|
14
14
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
15
15
|
|
|
16
16
|
const VerifySigners = require('../rollup/pipes/verify-signers');
|
|
17
|
-
const
|
|
17
|
+
const VerifyStatus = require('../rollup/pipes/verify-status');
|
|
18
18
|
const { applyTokenUpdates, applyTokenChange, getTxFee, getBNSum, getRewardLocker } = require('../../util');
|
|
19
19
|
|
|
20
20
|
const schema = Joi.object({
|
|
@@ -58,7 +58,7 @@ runner.use(({ tx, itx }, next) => {
|
|
|
58
58
|
|
|
59
59
|
// 2. verify rollup against itx
|
|
60
60
|
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
61
|
-
runner.use(
|
|
61
|
+
runner.use(VerifyStatus({ paused: false }));
|
|
62
62
|
runner.use((context, next) => {
|
|
63
63
|
const { itx, rollupState } = context;
|
|
64
64
|
if (rollupState.tokenAddress !== itx.token.address) {
|
|
@@ -12,8 +12,8 @@ const debug = require('debug')(`${require('../../../package.json').name}:withdra
|
|
|
12
12
|
|
|
13
13
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
14
14
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
15
|
+
const VerifyStatus = require('../rollup/pipes/verify-status');
|
|
15
16
|
|
|
16
|
-
const VerifyPaused = require('../rollup/pipes/verify-paused');
|
|
17
17
|
const { applyTokenUpdates, getTxFee, getBNSum, getRewardLocker, applyTokenChange } = require('../../util');
|
|
18
18
|
|
|
19
19
|
const verifyMultiSigV2 = pipes.VerifyMultiSigV2({ signersKey: 'signers' });
|
|
@@ -46,7 +46,7 @@ runner.use(({ tx, itx }, next) => {
|
|
|
46
46
|
|
|
47
47
|
// 2. verify rollup against itx
|
|
48
48
|
runner.use(pipes.ExtractState({ from: 'itx.rollup', to: 'rollupState', status: 'INVALID_ROLLUP', table: 'rollup' }));
|
|
49
|
-
runner.use(
|
|
49
|
+
runner.use(VerifyStatus({ paused: false }));
|
|
50
50
|
runner.use((context, next) => {
|
|
51
51
|
const { itx, rollupState } = context;
|
|
52
52
|
if (rollupState.tokenAddress !== itx.token.address) {
|
package/lib/util.js
CHANGED
|
@@ -184,6 +184,7 @@ const splitTxFee = ({ total, shares = {}, stringify = true }) => {
|
|
|
184
184
|
|
|
185
185
|
const getRewardLocker = (rollupAddress) => toStakeAddress(rollupAddress, rollupAddress);
|
|
186
186
|
const getBNSum = (...args) => flattenDeep(args).reduce((sum, x) => sum.add(new BN(x)), new BN(0)).toString(10); // prettier-ignore
|
|
187
|
+
const isGovernanceTx = (x) => ['pause_rollup', 'resume_rollup', 'migrate_rollup'].includes(x.type);
|
|
187
188
|
const isFixedFee = (x) => !x.tx.itxJson.maxFee || new BN(x.tx.itxJson.maxFee).isZero();
|
|
188
189
|
|
|
189
190
|
const ensureBlockReward = (rollupState, minReward, txStates) => {
|
|
@@ -207,10 +208,10 @@ const ensureBlockReward = (rollupState, minReward, txStates) => {
|
|
|
207
208
|
}
|
|
208
209
|
|
|
209
210
|
// 1. find dynamic reward tx
|
|
210
|
-
const dynamicFeeTxs = txStates.filter((x) => isFixedFee(x) === false);
|
|
211
|
+
const dynamicFeeTxs = txStates.filter((x) => isGovernanceTx(x) === false && isFixedFee(x) === false);
|
|
211
212
|
const totalDynamicFee = dynamicFeeTxs.reduce((sum, x) => sum.add(new BN(x.tx.itxJson.maxFee)), new BN(0));
|
|
212
213
|
|
|
213
|
-
const fixedFeeTxs = txStates.filter((x) => isFixedFee(x));
|
|
214
|
+
const fixedFeeTxs = txStates.filter((x) => isGovernanceTx(x) === false && isFixedFee(x));
|
|
214
215
|
const totalFixedFee = fixedFeeTxs.reduce((sum, x) => sum.add(new BN(x.tx.itxJson.actualFee)), new BN(0));
|
|
215
216
|
|
|
216
217
|
const totalMissingFee = minRequiredReward.sub(totalFixedFee);
|
|
@@ -270,33 +271,35 @@ const ensureBlockReward = (rollupState, minReward, txStates) => {
|
|
|
270
271
|
});
|
|
271
272
|
|
|
272
273
|
// 3. bur/mint tokens, update stakes
|
|
273
|
-
txStates
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
274
|
+
txStates
|
|
275
|
+
.filter((x) => isGovernanceTx(x) === false)
|
|
276
|
+
.forEach((x) => {
|
|
277
|
+
const user = x.tx.itxJson.token.value;
|
|
278
|
+
const fee = x.tx.itxJson.actualFee;
|
|
279
|
+
const total = getBNSum(user, fee);
|
|
280
|
+
|
|
281
|
+
if (x.type === 'deposit_token_v2') {
|
|
282
|
+
result.rewardAmount = result.rewardAmount.add(new BN(fee));
|
|
283
|
+
result.mintedAmount = result.mintedAmount.add(new BN(total));
|
|
284
|
+
|
|
285
|
+
// mint tokens for deposit proposer
|
|
286
|
+
changes.stake.push({
|
|
287
|
+
address: toStakeAddress(x.tx.itxJson.proposer, address),
|
|
288
|
+
delta: total,
|
|
289
|
+
action: 'mint',
|
|
290
|
+
});
|
|
291
|
+
} else if (x.type === 'withdraw_token_v2') {
|
|
292
|
+
result.rewardAmount = result.rewardAmount.add(new BN(fee));
|
|
293
|
+
result.burnedAmount = result.burnedAmount.add(new BN(user));
|
|
294
|
+
|
|
295
|
+
// burn tokens from locked withdraws: user amount
|
|
296
|
+
changes.stake.push({
|
|
297
|
+
address: toStakeAddress(x.tx.from, address),
|
|
298
|
+
delta: `-${user}`,
|
|
299
|
+
action: 'burn',
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
});
|
|
300
303
|
|
|
301
304
|
const grouped = {
|
|
302
305
|
stake: groupBy(changes.stake, 'address'),
|
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.36",
|
|
7
7
|
"description": "Predefined tx pipeline sets to execute certain type of transactions",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -21,18 +21,18 @@
|
|
|
21
21
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@arcblock/did": "1.18.
|
|
25
|
-
"@arcblock/did-util": "1.18.
|
|
26
|
-
"@arcblock/jwt": "1.18.
|
|
27
|
-
"@arcblock/validator": "1.18.
|
|
28
|
-
"@ocap/asset": "1.18.
|
|
29
|
-
"@ocap/mcrypto": "1.18.
|
|
30
|
-
"@ocap/merkle-tree": "1.18.
|
|
31
|
-
"@ocap/message": "1.18.
|
|
32
|
-
"@ocap/state": "1.18.
|
|
33
|
-
"@ocap/tx-pipeline": "1.18.
|
|
34
|
-
"@ocap/util": "1.18.
|
|
35
|
-
"@ocap/wallet": "1.18.
|
|
24
|
+
"@arcblock/did": "1.18.36",
|
|
25
|
+
"@arcblock/did-util": "1.18.36",
|
|
26
|
+
"@arcblock/jwt": "1.18.36",
|
|
27
|
+
"@arcblock/validator": "1.18.36",
|
|
28
|
+
"@ocap/asset": "1.18.36",
|
|
29
|
+
"@ocap/mcrypto": "1.18.36",
|
|
30
|
+
"@ocap/merkle-tree": "1.18.36",
|
|
31
|
+
"@ocap/message": "1.18.36",
|
|
32
|
+
"@ocap/state": "1.18.36",
|
|
33
|
+
"@ocap/tx-pipeline": "1.18.36",
|
|
34
|
+
"@ocap/util": "1.18.36",
|
|
35
|
+
"@ocap/wallet": "1.18.36",
|
|
36
36
|
"debug": "^4.3.4",
|
|
37
37
|
"deep-diff": "^1.0.2",
|
|
38
38
|
"empty-value": "^1.0.1",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"jest": "^27.5.1",
|
|
48
48
|
"start-server-and-test": "^1.14.0"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "507eaab0fc94d92a88c49c2e3441c5f6b0e3788f"
|
|
51
51
|
}
|