trac-msb 0.2.26 → 0.3.0-beta.2

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.
Files changed (136) hide show
  1. package/SECURITY.md +2 -2
  2. package/cli/commandHandler.js +317 -20
  3. package/cli/handlers.js +9 -1
  4. package/cli/interactive.js +4 -3
  5. package/cli/tokenSupplyAudit.js +90 -0
  6. package/msb.mjs +1 -0
  7. package/package.json +15 -6
  8. package/rpc/create_server.js +12 -3
  9. package/rpc/handlers.js +121 -0
  10. package/rpc/routes/v1.js +12 -0
  11. package/src/codecs/apply/applyOperationCodec.js +334 -0
  12. package/src/codecs/apply/applyOperations.generated.cjs +6380 -0
  13. package/src/codecs/consensus/v1/consensusV1.generated.cjs +3508 -0
  14. package/src/codecs/consensus/v1/consensusV1OperationCodec.js +161 -0
  15. package/src/codecs/consensus/v1/vdfConfigCodec.js +83 -0
  16. package/src/{utils/protobuf → codecs/network/v1}/networkV1.generated.cjs +664 -393
  17. package/src/codecs/network/v1/networkV1OperationCodec.js +25 -0
  18. package/src/codecs/protobufRuntime.cjs +95 -0
  19. package/src/codecs/state/escrowEntryCodec.js +45 -0
  20. package/src/codecs/state/state.generated.cjs +659 -0
  21. package/src/config/args.js +0 -1
  22. package/src/config/config.js +41 -7
  23. package/src/config/env.js +33 -9
  24. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionError.js +55 -0
  25. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionOperations.js +118 -0
  26. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelector.js +1042 -0
  27. package/src/core/consensus/epochAppenderSelection/createEpochAppenderSelector.js +23 -0
  28. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionLedgerReader.js +274 -0
  29. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionState.js +488 -0
  30. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionStorage.js +93 -0
  31. package/src/core/consensus/quorum.js +11 -0
  32. package/src/core/consensus/services/EpochCoordinationRound.js +839 -0
  33. package/src/core/consensus/services/EpochCoordinatorOperations.js +211 -0
  34. package/src/core/consensus/services/EpochCoordinatorService.js +335 -0
  35. package/src/core/consensus/services/EpochRoundListeners.js +116 -0
  36. package/src/core/consensus/services/EpochStateMachine.js +141 -0
  37. package/src/core/consensus/services/VDFBare.js +291 -0
  38. package/src/core/consensus/services/VDFNode.js +111 -0
  39. package/src/core/consensus/services/VDFProgressWatchdog.js +79 -0
  40. package/src/core/consensus/services/VDFService.js +87 -0
  41. package/src/core/consensus/services/VDFServiceManager.js +147 -0
  42. package/src/core/consensus/services/createVDFService.js +16 -0
  43. package/src/core/consensus/services/vdf-guardian.js +32 -0
  44. package/src/core/consensus/services/vdf-worker.js +90 -0
  45. package/src/core/network/Network.js +327 -238
  46. package/src/core/network/protocols/consensus/IndexerMessages.js +72 -0
  47. package/src/core/network/protocols/consensus/v1/ConsensusV1ConnectionPolicy.js +57 -0
  48. package/src/core/network/protocols/consensus/v1/ConsensusV1MessageRouter.js +147 -0
  49. package/src/core/network/protocols/consensus/v1/ConsensusV1Protocol.js +72 -0
  50. package/src/core/network/protocols/consensus/v1/IndexerPendingRequestService.js +108 -0
  51. package/src/core/network/protocols/consensus/v1/V1ConsensusProtocolError.js +29 -0
  52. package/src/core/network/protocols/consensus/v1/handlers/V1EpochAppendOperationHandler.js +68 -0
  53. package/src/core/network/protocols/consensus/v1/handlers/V1EpochProofProposalOperationHandler.js +226 -0
  54. package/src/core/network/protocols/consensus/v1/validators/ConsensusValidationSchema.js +192 -0
  55. package/src/core/network/protocols/consensus/v1/validators/V1BaseConsensusOperation.js +428 -0
  56. package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendReply.js +47 -0
  57. package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendRequest.js +17 -0
  58. package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalApproval.js +116 -0
  59. package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalRequest.js +152 -0
  60. package/src/core/network/protocols/consensus/v1/validators/consensusValidationSchemaHelpers.js +145 -0
  61. package/src/core/network/protocols/shared/ConnectionOperationHandler.js +27 -0
  62. package/src/core/network/protocols/{NetworkMessages.js → validators/ValidatorMessages.js} +24 -14
  63. package/src/core/network/protocols/{ProtocolSession.js → validators/ValidatorProtocolSession.js} +22 -25
  64. package/src/core/network/protocols/{legacy/NetworkMessageRouter.js → validators/legacy/ValidatorLegacyMessageRouter.js} +6 -6
  65. package/src/core/network/protocols/{LegacyProtocol.js → validators/legacy/ValidatorLegacyProtocol.js} +9 -7
  66. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/BaseStateOperationHandler.js +1 -1
  67. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyGetRequestHandler.js +5 -5
  68. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyRoleOperationHandler.js +5 -5
  69. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacySubnetworkOperationHandler.js +5 -5
  70. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyTransferOperationHandler.js +5 -5
  71. package/src/core/network/protocols/{ProtocolInterface.js → validators/shared/ValidatorProtocolInterface.js} +5 -5
  72. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialBootstrapDeploymentValidator.js +1 -1
  73. package/src/core/network/protocols/validators/shared/validators/PartialHtlcValidator.js +325 -0
  74. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialOperationValidator.js +44 -21
  75. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialRoleAccessValidator.js +3 -3
  76. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransactionValidator.js +3 -3
  77. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransferValidator.js +4 -4
  78. package/src/core/network/protocols/{v1 → validators/v1}/V1ProtocolError.js +1 -1
  79. package/src/core/network/{services/PendingRequestService.js → protocols/validators/v1/ValidatorPendingRequestService.js} +19 -82
  80. package/src/core/network/protocols/{v1/NetworkMessageRouter.js → validators/v1/ValidatorV1MessageRouter.js} +9 -9
  81. package/src/core/network/protocols/{V1Protocol.js → validators/v1/ValidatorV1Protocol.js} +10 -8
  82. package/src/core/network/protocols/{connectionPolicies.js → validators/v1/connectionPolicies.js} +1 -1
  83. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BaseOperationHandler.js +6 -23
  84. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BroadcastTransactionOperationHandler.js +14 -9
  85. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1LivenessOperationHandler.js +5 -4
  86. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionErrorMapper.js +3 -3
  87. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionOperationStrategies.js +44 -1
  88. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionPayloadUtils.js +1 -1
  89. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BaseOperation.js +19 -15
  90. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionRequest.js +2 -2
  91. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionResponse.js +34 -18
  92. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1ValidationSchema.js +3 -3
  93. package/src/core/network/services/IndexerConnectionManager.js +88 -0
  94. package/src/core/network/services/TransactionPoolService.js +11 -18
  95. package/src/core/network/services/TransactionRateLimiterService.js +1 -1
  96. package/src/core/network/services/ValidatorConnectionManager.js +163 -0
  97. package/src/core/network/services/{MessageOrchestrator.js → ValidatorMessageOrchestrator.js} +34 -42
  98. package/src/core/network/services/ValidatorObserverService.js +21 -36
  99. package/src/core/network/shared/BasePendingRequestService.js +67 -0
  100. package/src/core/network/shared/PeerConnectionManager.js +185 -0
  101. package/src/core/state/State.js +1803 -159
  102. package/src/core/state/StateEventQueue.js +69 -0
  103. package/src/core/state/utils/address.js +10 -6
  104. package/src/core/state/utils/epochProof.js +109 -0
  105. package/src/core/state/utils/escrowEntry.js +178 -0
  106. package/src/core/state/validators/StateValidationSchema.js +757 -0
  107. package/src/core/state/validators/stateValidationRules.js +312 -0
  108. package/src/index.js +280 -67
  109. package/src/messages/consensus/v1/ConsensusMessageBuilder.js +368 -0
  110. package/src/messages/consensus/v1/ConsensusMessageDirector.js +142 -0
  111. package/src/messages/consensus/v1/consensusMessageFactory.js +12 -0
  112. package/src/messages/consensus/v1/epochAppendMessage.js +58 -0
  113. package/src/messages/network/v1/NetworkMessageBuilder.js +15 -7
  114. package/src/messages/state/ApplyStateMessageBuilder.js +499 -13
  115. package/src/messages/state/ApplyStateMessageDirector.js +261 -2
  116. package/src/utils/StateMachine.js +125 -0
  117. package/src/utils/applyOperations.js +45 -2
  118. package/src/utils/buffer.js +239 -59
  119. package/src/utils/consensusConfig.js +76 -0
  120. package/src/utils/constants.js +174 -73
  121. package/src/utils/helpers.js +0 -25
  122. package/src/utils/htlcLock.js +122 -0
  123. package/src/utils/logger.js +10 -4
  124. package/src/utils/migrationUtils.js +2 -1
  125. package/src/utils/normalizers.js +113 -0
  126. package/src/utils/scheduler/SchedulableService.js +107 -0
  127. package/src/utils/{Scheduler.js → scheduler/Scheduler.js} +56 -17
  128. package/src/core/network/services/ConnectionManager.js +0 -406
  129. package/src/utils/check.js +0 -525
  130. package/src/utils/protobuf/applyOperations.cjs +0 -1373
  131. package/src/utils/protobuf/operationHelpers.js +0 -81
  132. /package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyResponseHandler.js +0 -0
  133. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/ValidatorResponse.js +0 -0
  134. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/base/BaseResponse.js +0 -0
  135. /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessRequest.js +0 -0
  136. /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessResponse.js +0 -0
@@ -0,0 +1,757 @@
1
+ import Validator from 'fastest-validator';
2
+ import b4a from 'b4a';
3
+
4
+ import {
5
+ OperationType,
6
+ WRITER_BYTE_LENGTH,
7
+ NONCE_BYTE_LENGTH,
8
+ SIGNATURE_BYTE_LENGTH,
9
+ HASH_BYTE_LENGTH,
10
+ BOOTSTRAP_BYTE_LENGTH,
11
+ CHANNEL_BYTE_LENGTH,
12
+ AMOUNT_BYTE_LENGTH,
13
+ EPOCH_BYTE_LENGTH,
14
+ CONSENSUS_CONFIG_SCHEMA_VERSION_BYTE_LENGTH,
15
+ CONSENSUS_CONFIG_DATA_MAX_SIZE,
16
+ SET_EPOCH_DATA_MAX_SIZE,
17
+ HTLC_LOCK_ID_BYTE_LENGTH,
18
+ HTLC_MAX_SIGNERS,
19
+ HTLC_PREIMAGE_BYTE_LENGTH,
20
+ HTLC_THRESHOLD_BYTE_LENGTH,
21
+ PUBLIC_KEY_LENGTH,
22
+ HTLC_METADATA_MAX_BYTE_LENGTH,
23
+ } from '../../../utils/constants.js';
24
+ import {
25
+ boundedHtlcBufferArray,
26
+ registerStrictTypeRules,
27
+ bufferRule,
28
+ bufferMaxLengthRule,
29
+ bufferAmountRule,
30
+ createProofDataRule,
31
+ createProofProposalApprovalRule
32
+ } from './stateValidationRules.js';
33
+
34
+ class StateValidationSchema {
35
+ #validator;
36
+ #validateCoreAdminOperationSchema;
37
+ #validateAdminControlOperationSchema;
38
+ #validateRoleAccessOperationSchema;
39
+ #validateBootstrapDeploymentSchema;
40
+ #validateTransactionOperationSchema;
41
+ #validateTransferOperationSchema;
42
+ #validateBalanceInitializationSchema;
43
+ #validateSetEpochOperationSchema;
44
+ #validateEpochProofV1Schema;
45
+ #validateConsensusControlOperationSchema;
46
+ #validateHtlcClaimOperationSchema;
47
+ #validateHtlcLockOperationSchema;
48
+ #validateHtlcRefundOperationSchema;
49
+ #config;
50
+
51
+ /**
52
+ * @param {Config} config
53
+ **/
54
+ constructor(config) {
55
+ this.#config = config;
56
+
57
+ this.#validator = new Validator({
58
+ useNewCustomCheckerFunction: true,
59
+ messages: {
60
+ buffer: "The '{field}' field must be a Buffer! Actual: {actual}",
61
+ bufferLength: "The '{field}' field must be a Buffer with length {expected}! Actual: {actual}",
62
+ bufferMaxLength: "The '{field}' field must be a Buffer no longer than {expected} bytes! Actual: {actual}",
63
+ nonZeroBuffer: "The '{field}' field must not be an empty or zero-filled Buffer!",
64
+ emptyBuffer: "The '{field}' field must not be an empty Buffer!",
65
+ proofData: "The '{field}' field must be an encoded ProofProposal buffer.",
66
+ proofProposalApproval: "The '{field}' field must be an encoded ProofProposalApproval buffer.",
67
+ },
68
+ });
69
+
70
+ registerStrictTypeRules(this.#validator);
71
+ this.#validator.add('buffer', bufferRule);
72
+ this.#validator.add('buffer_max_length', bufferMaxLengthRule);
73
+ this.#validator.add('buffer_amount', bufferAmountRule);
74
+ this.#validator.add('proof_data', createProofDataRule(config.addressLength));
75
+ this.#validator.add('proof_proposal_approval', createProofProposalApprovalRule(config.addressLength));
76
+
77
+ this.#validateCoreAdminOperationSchema = this.#compileCoreAdminOperationSchema();
78
+ this.#validateAdminControlOperationSchema = this.#compileAdminControlOperationSchema();
79
+ this.#validateRoleAccessOperationSchema = this.#compileRoleAccessOperationSchema();
80
+ this.#validateBootstrapDeploymentSchema = this.#compileBootstrapDeploymentSchema();
81
+ this.#validateTransactionOperationSchema = this.#compileTransactionOperationSchema();
82
+ this.#validateTransferOperationSchema = this.#compileTransferOperationSchema();
83
+ this.#validateBalanceInitializationSchema = this.#compileBalanceInitializationSchema();
84
+ this.#validateSetEpochOperationSchema = this.#compileSetEpochOperationSchema();
85
+ this.#validateEpochProofV1Schema = this.#compileEpochProofV1Schema();
86
+ this.#validateConsensusControlOperationSchema = this.#compileConsensusControlOperationSchema();
87
+ this.#validateHtlcClaimOperationSchema = this.#compileHtlcClaimOperationSchema();
88
+ this.#validateHtlcLockOperationSchema = this.#compileHtlcLockOperationSchema();
89
+ this.#validateHtlcRefundOperationSchema = this.#compileHtlcRefundOperationSchema();
90
+ }
91
+
92
+ #getOperationTypeName(operationType) {
93
+ for (const [name, value] of Object.entries(OperationType)) {
94
+ if (value === operationType) return name;
95
+ }
96
+
97
+ return undefined;
98
+ }
99
+
100
+ #operationTypeDomain(...values) {
101
+ return {
102
+ type: 'number',
103
+ required: true,
104
+ custom: (value, errors) => {
105
+ if (typeof value !== 'number') return value;
106
+ if (!values.includes(value)) {
107
+ const singleValue = values.length === 1;
108
+ const expectedOperationType = values[0];
109
+ const expected = singleValue ? expectedOperationType : values;
110
+ const operationName = this.#getOperationTypeName(expectedOperationType);
111
+
112
+ errors.push({
113
+ type: 'valueNotAllowed',
114
+ actual: value,
115
+ expected,
116
+ field: 'type',
117
+ message: singleValue
118
+ ? `Operation type must be ${expectedOperationType} (${operationName})`
119
+ : `Operation type must be one of: ${values.join(', ')}`
120
+ });
121
+ }
122
+
123
+ return value;
124
+ }
125
+ };
126
+ }
127
+
128
+ // Complete by default - no writer needed
129
+ #compileCoreAdminOperationSchema() {
130
+ const addressLength = this.#config.addressLength
131
+ const schema = {
132
+ $$strict: true,
133
+ type: this.#operationTypeDomain(
134
+ OperationType.ADD_ADMIN,
135
+ OperationType.DISABLE_INITIALIZATION
136
+ ),
137
+ address: {type: 'buffer', length: addressLength, required: true}, // invoker adddress (admin)
138
+ cao: {
139
+ strict: true,
140
+ type: 'object',
141
+ props: {
142
+ tx: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx hash
143
+ txv: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx validity
144
+ iw: {type: 'buffer', length: WRITER_BYTE_LENGTH, required: true}, // writer key of the admin
145
+ in: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true}, // nonce
146
+ is: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true}, // signature
147
+ }
148
+ }
149
+ };
150
+ return this.#validator.compile(schema);
151
+ }
152
+
153
+ validateCoreAdminOperation(operation) {
154
+ return this.#validateCoreAdminOperationSchema(operation) === true;
155
+ }
156
+
157
+ #compileBalanceInitializationSchema() {
158
+ const schema = {
159
+ $$strict: true,
160
+ type: this.#operationTypeDomain(OperationType.BALANCE_INITIALIZATION),
161
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
162
+ bio: {
163
+ strict: true,
164
+ type: 'object',
165
+ props: {
166
+ tx: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx hash
167
+ txv: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx validity
168
+ ia: {type: 'buffer', length: this.#config.addressLength, required: true}, // selected address to specific operation.
169
+ am: {type: 'buffer', length: AMOUNT_BYTE_LENGTH, required: true}, // amount to transfer
170
+ in: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true}, // nonce of the invoker
171
+ is: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true}, // signature of the invoker
172
+ }
173
+ }
174
+ };
175
+ return this.#validator.compile(schema);
176
+ }
177
+
178
+ validateBalanceInitialization(operation) {
179
+ return this.#validateBalanceInitializationSchema(operation) === true;
180
+ }
181
+
182
+ // Complete by default - no writer needed
183
+ #compileAdminControlOperationSchema() {
184
+ const schema = {
185
+ $$strict: true,
186
+ type: this.#operationTypeDomain(
187
+ OperationType.APPEND_WHITELIST,
188
+ OperationType.ADD_INDEXER,
189
+ OperationType.REMOVE_INDEXER,
190
+ OperationType.BAN_VALIDATOR
191
+ ),
192
+ address: {type: 'buffer', length: this.#config.addressLength, required: true}, // invoker adddress (admin)
193
+ aco: {
194
+ strict: true,
195
+ type: 'object',
196
+ props: {
197
+ tx: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx hash
198
+ txv: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx validity
199
+ ia: {type: 'buffer', length: this.#config.addressLength, required: true}, // incoming address - selected address for specific operation
200
+ in: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true}, // nonce
201
+ is: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true}, // signature
202
+ }
203
+ }
204
+ };
205
+ return this.#validator.compile(schema);
206
+ }
207
+
208
+ validateAdminControlOperation(operation) {
209
+ return this.#validateAdminControlOperationSchema(operation) === true;
210
+ }
211
+
212
+ #compileRoleAccessOperationSchema() {
213
+ const schema = {
214
+ $$strict: true,
215
+ type: this.#operationTypeDomain(
216
+ OperationType.ADD_WRITER,
217
+ OperationType.REMOVE_WRITER,
218
+ OperationType.ADMIN_RECOVERY
219
+ ),
220
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
221
+ rao: {
222
+ strict: true,
223
+ type: 'object',
224
+ props: {
225
+ tx: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx hash
226
+ txv: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx validity
227
+ iw: {type: 'buffer', length: WRITER_BYTE_LENGTH, required: true}, // writing key of the invoker
228
+ in: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true}, // nonce of the invoker
229
+ is: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true}, // signature
230
+ va: {type: 'buffer', length: this.#config.addressLength, optional: true},
231
+ vn: {type: 'buffer', length: NONCE_BYTE_LENGTH, optional: true},
232
+ vs: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, optional: true}
233
+
234
+ },
235
+ custom: (value, errors) => {
236
+ if (!value || typeof value !== 'object') return value;
237
+ const {vn, vs, va} = value;
238
+ const vnPresent = vn !== undefined
239
+ const vsPresent = vs !== undefined
240
+ const vaPresent = va !== undefined
241
+
242
+ const fieldsPresent = [vnPresent, vsPresent, vaPresent].filter(Boolean).length;
243
+
244
+ if (fieldsPresent > 0 && fieldsPresent < 3) {
245
+ errors.push({
246
+ type: 'conditionalDependency',
247
+ field: 'bdo',
248
+ message: 'Fields "vn", "vs", and "va" must all be present if any one is provided'
249
+ });
250
+ }
251
+ if (vn === null || vs === null || va === null) {
252
+ errors.push({
253
+ type: 'buffer',
254
+ field: 'bdo',
255
+ message: 'Validator fields cannot be null, must be a Buffer or undefined'
256
+ });
257
+ }
258
+
259
+ return value;
260
+ }
261
+ }
262
+ };
263
+ return this.#validator.compile(schema);
264
+ }
265
+
266
+ validateRoleAccessOperation(operation) {
267
+ return this.#validateRoleAccessOperationSchema(operation) === true;
268
+ }
269
+
270
+ #compileTransactionOperationSchema() {
271
+ const schema = {
272
+ $$strict: true,
273
+ type: this.#operationTypeDomain(OperationType.TX),
274
+ address: {type: 'buffer', length: this.#config.addressLength, required: true}, // invoker address
275
+ txo: {
276
+ strict: true,
277
+ type: 'object',
278
+ props: {
279
+ tx: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx hash
280
+ txv: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx validity
281
+ iw: {type: 'buffer', length: WRITER_BYTE_LENGTH, required: true}, // Writing key of the requesting node (external subnetwork)
282
+ ch: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true}, // Content hash (hash of the transaction's data)
283
+ bs: {type: 'buffer', length: BOOTSTRAP_BYTE_LENGTH, required: true}, // External bootstrap contract
284
+ mbs: {type: 'buffer', length: BOOTSTRAP_BYTE_LENGTH, required: true}, // MSB bootstrap key
285
+ in: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true}, // Nonce of the requesting node
286
+ is: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true}, // Requester's signature
287
+ va: {type: 'buffer', length: this.#config.addressLength, optional: true}, //validator address
288
+ vn: {type: 'buffer', length: NONCE_BYTE_LENGTH, optional: true}, //validator nonce
289
+ vs: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, optional: true}, //validator signature
290
+ },
291
+ custom: (value, errors) => {
292
+ if (!value || typeof value !== 'object') return value;
293
+ const {vn, vs, va} = value;
294
+ const vnPresent = vn !== undefined;
295
+ const vsPresent = vs !== undefined;
296
+ const vaPresent = va !== undefined;
297
+
298
+ const fieldsPresent = [vnPresent, vsPresent, vaPresent].filter(Boolean).length;
299
+
300
+ if (fieldsPresent > 0 && fieldsPresent < 3) {
301
+ errors.push({
302
+ type: 'conditionalDependency',
303
+ field: 'bdo',
304
+ message: 'Fields "vn", "vs", and "va" must all be present if any one is provided'
305
+ });
306
+ }
307
+ if (vn === null || vs === null || va === null) {
308
+ errors.push({
309
+ type: 'buffer',
310
+ field: 'bdo',
311
+ message: 'Validator fields cannot be null, must be a Buffer or undefined'
312
+ });
313
+ }
314
+
315
+ return value;
316
+ }
317
+ }
318
+ };
319
+ return this.#validator.compile(schema);
320
+ }
321
+
322
+ validateTransactionOperation(op) {
323
+ return this.#validateTransactionOperationSchema(op) === true;
324
+ }
325
+
326
+ #compileBootstrapDeploymentSchema() {
327
+ const schema = {
328
+ $$strict: true,
329
+ type: this.#operationTypeDomain(OperationType.BOOTSTRAP_DEPLOYMENT),
330
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
331
+ bdo: {
332
+
333
+ strict: true,
334
+ type: "object",
335
+ props: {
336
+ tx: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true},
337
+ txv: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true},
338
+ bs: {type: 'buffer', length: BOOTSTRAP_BYTE_LENGTH, required: true},
339
+ ic: {type: 'buffer', length: CHANNEL_BYTE_LENGTH, required: true},
340
+ in: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true},
341
+ is: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true},
342
+ va: {type: 'buffer', length: this.#config.addressLength, optional: true},
343
+ vn: {type: 'buffer', length: NONCE_BYTE_LENGTH, optional: true},
344
+ vs: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, optional: true},
345
+ },
346
+ custom: (value, errors) => {
347
+ if (!value || typeof value !== 'object') return value;
348
+ const {vn, vs, va} = value;
349
+ const vnPresent = vn !== undefined
350
+ const vsPresent = vs !== undefined
351
+ const vaPresent = va !== undefined
352
+
353
+ const fieldsPresent = [vnPresent, vsPresent, vaPresent].filter(Boolean).length;
354
+
355
+ if (fieldsPresent > 0 && fieldsPresent < 3) {
356
+ errors.push({
357
+ type: 'conditionalDependency',
358
+ field: 'bdo',
359
+ message: 'Fields "vn", "vs", and "va" must all be present if any one is provided'
360
+ });
361
+ }
362
+ if (vn === null || vs === null || va === null) {
363
+ errors.push({
364
+ type: 'buffer',
365
+ field: 'bdo',
366
+ message: 'Validator fields cannot be null, must be a Buffer or undefined'
367
+ });
368
+ }
369
+
370
+ return value;
371
+ }
372
+ }
373
+ };
374
+ return this.#validator.compile(schema);
375
+ }
376
+
377
+ validateBootstrapDeploymentOperation(op) {
378
+ return this.#validateBootstrapDeploymentSchema(op) === true;
379
+ }
380
+
381
+ #compileTransferOperationSchema() {
382
+ const schema = {
383
+ $$strict: true,
384
+ type: this.#operationTypeDomain(OperationType.TRANSFER),
385
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
386
+ tro: {
387
+ strict: true,
388
+ type: 'object',
389
+ props: {
390
+ tx: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx hash
391
+ txv: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true}, // tx validity
392
+ to: {type: 'buffer', length: this.#config.addressLength, required: true}, // recipient address
393
+ am: {type: 'buffer_amount', length: AMOUNT_BYTE_LENGTH, required: true}, // amount to transfer
394
+ in: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true}, // nonce of the invoker
395
+ is: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true}, // signature of the invoker
396
+ va: {type: 'buffer', length: this.#config.addressLength, optional: true}, // validator address
397
+ vn: {type: 'buffer', length: NONCE_BYTE_LENGTH, optional: true}, // validator nonce
398
+ vs: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, optional: true} // validator signature
399
+
400
+ },
401
+ custom: (value, errors) => {
402
+ if (!value || typeof value !== 'object') return value;
403
+ const {vn, vs, va} = value;
404
+ const vnPresent = vn !== undefined
405
+ const vsPresent = vs !== undefined
406
+ const vaPresent = va !== undefined
407
+
408
+ const fieldsPresent = [vnPresent, vsPresent, vaPresent].filter(Boolean).length;
409
+
410
+ if (fieldsPresent > 0 && fieldsPresent < 3) {
411
+ errors.push({
412
+ type: 'conditionalDependency',
413
+ field: 'tro',
414
+ message: 'Fields "vn", "vs", and "va" must all be present if any one is provided'
415
+ });
416
+ }
417
+ if (vn === null || vs === null || va === null) {
418
+ errors.push({
419
+ type: 'buffer',
420
+ field: 'tro',
421
+ message: 'Validator fields cannot be null, must be a Buffer or undefined'
422
+ });
423
+ }
424
+
425
+ return value;
426
+ }
427
+ }
428
+ };
429
+ return this.#validator.compile(schema);
430
+ }
431
+
432
+ validateTransferOperation(op) {
433
+ return this.#validateTransferOperationSchema(op) === true;
434
+ }
435
+
436
+ #compileSetEpochOperationSchema() {
437
+ const schema = {
438
+ $$strict: true,
439
+ type: this.#operationTypeDomain(OperationType.SET_EPOCH),
440
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
441
+ seo: {
442
+ strict: true,
443
+ type: 'object',
444
+ props: {
445
+ sv: {
446
+ type: 'buffer',
447
+ length: CONSENSUS_CONFIG_SCHEMA_VERSION_BYTE_LENGTH,
448
+ required: true
449
+ },
450
+ data: {
451
+ type: 'buffer_max_length',
452
+ maxLength: SET_EPOCH_DATA_MAX_SIZE,
453
+ required: true
454
+ }
455
+ },
456
+ }
457
+ };
458
+ return this.#validator.compile(schema);
459
+ }
460
+
461
+ validateSetEpochOperation(op) {
462
+ return this.#validateSetEpochOperationSchema(op) === true;
463
+ }
464
+
465
+ #compileEpochProofV1Schema() {
466
+ const schema = {
467
+ $$strict: true,
468
+ pd: {type: 'proof_data', required: true},
469
+ app: {
470
+ type: 'array',
471
+ required: true,
472
+ items: {type: 'proof_proposal_approval'}
473
+ }
474
+ };
475
+ return this.#validator.compile(schema);
476
+ }
477
+
478
+ validateEpochProofV1(epochProof) {
479
+ return this.#validateEpochProofV1Schema(epochProof) === true;
480
+ }
481
+
482
+ #compileConsensusControlOperationSchema() {
483
+ const schema = {
484
+ $$strict: true,
485
+ type: this.#operationTypeDomain(
486
+ OperationType.SET_GENESIS_EPOCH,
487
+ OperationType.SET_CONSENSUS_CONFIG
488
+ ),
489
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
490
+ cco: {
491
+ strict: true,
492
+ type: 'object',
493
+ props: {
494
+ tx: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true},
495
+ txv: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true},
496
+ cc: {
497
+ strict: true,
498
+ type: 'object',
499
+ required: true,
500
+ props: {
501
+ sv: {type: 'buffer', length: CONSENSUS_CONFIG_SCHEMA_VERSION_BYTE_LENGTH, required: true},
502
+ cd: {
503
+ type: 'buffer_max_length',
504
+ maxLength: CONSENSUS_CONFIG_DATA_MAX_SIZE,
505
+ required: true
506
+ },
507
+ }
508
+ },
509
+ in: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true},
510
+ is: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true},
511
+ }
512
+ }
513
+ };
514
+ return this.#validator.compile(schema);
515
+ }
516
+
517
+ validateConsensusControlOperation(op) {
518
+ return this.#validateConsensusControlOperationSchema(op) === true;
519
+ }
520
+
521
+ #compileHtlcClaimOperationSchema() {
522
+ const schema = {
523
+ $$strict: true,
524
+ type: this.#operationTypeDomain(OperationType.HTLC_CLAIM),
525
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
526
+ hco: {
527
+ strict: true,
528
+ type: 'object',
529
+ props: {
530
+ tx: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true},
531
+ txv: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true},
532
+ li: {type: 'buffer', length: HTLC_LOCK_ID_BYTE_LENGTH, required: true},
533
+ pi: {type: 'buffer', length: HTLC_PREIMAGE_BYTE_LENGTH, required: true},
534
+ in: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true},
535
+ is: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true},
536
+ va: {type: 'buffer', length: this.#config.addressLength, optional: true},
537
+ vn: {type: 'buffer', length: NONCE_BYTE_LENGTH, optional: true},
538
+ vs: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, optional: true}
539
+ },
540
+ custom: (value, errors) => {
541
+ if (!value || typeof value !== 'object') return value;
542
+ const {va, vn, vs} = value;
543
+ const count = [va, vn, vs].filter(field => field !== undefined).length;
544
+ if (count !== 0 && count !== 3) {
545
+ errors.push({
546
+ type: 'conditionalDependency',
547
+ field: 'hco',
548
+ message: 'Fields "va", "vn", and "vs" must all be present if any one is provided'
549
+ });
550
+ }
551
+ if (va === null || vn === null || vs === null) {
552
+ errors.push({
553
+ type: 'buffer',
554
+ field: 'hco',
555
+ message: 'Validator fields cannot be null'
556
+ });
557
+ }
558
+ return value;
559
+ }
560
+ }
561
+ };
562
+ return this.#validator.compile(schema);
563
+ }
564
+
565
+ validateHtlcClaimOperation(op) {
566
+ return this.#validateHtlcClaimOperationSchema(op) === true;
567
+ }
568
+
569
+ #compileHtlcLockOperationSchema() {
570
+ const schema = {
571
+ $$strict: true,
572
+ type: this.#operationTypeDomain(OperationType.HTLC_LOCK),
573
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
574
+ hlo: {
575
+ strict: true,
576
+ type: 'object',
577
+ props: {
578
+ tx: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true},
579
+ txv: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true},
580
+ ca: {type: 'buffer', length: this.#config.addressLength, required: true},
581
+ ra: {type: 'buffer', length: this.#config.addressLength, required: true},
582
+ am: {type: 'buffer', length: AMOUNT_BYTE_LENGTH, required: true},
583
+ fa: {type: 'buffer_amount', length: AMOUNT_BYTE_LENGTH, required: true},
584
+ fr: {type: 'buffer', length: this.#config.addressLength, optional: true},
585
+ hl: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true},
586
+ re: {type: 'buffer', length: EPOCH_BYTE_LENGTH, required: true},
587
+ md: {type: 'buffer_max_length', maxLength: HTLC_METADATA_MAX_BYTE_LENGTH, optional: true},
588
+ ss: boundedHtlcBufferArray(1, HTLC_MAX_SIGNERS, PUBLIC_KEY_LENGTH),
589
+ th: {type: 'buffer', length: HTLC_THRESHOLD_BYTE_LENGTH, required: true},
590
+ cs: boundedHtlcBufferArray(0, HTLC_MAX_SIGNERS - 1, SIGNATURE_BYTE_LENGTH),
591
+ in: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true},
592
+ is: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true},
593
+ va: {type: 'buffer', length: this.#config.addressLength, optional: true},
594
+ vn: {type: 'buffer', length: NONCE_BYTE_LENGTH, optional: true},
595
+ vs: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, optional: true}
596
+ },
597
+ custom: (value, errors) => {
598
+ if (!value || typeof value !== 'object') return value;
599
+
600
+ const {fa, fr, md, ss, th, cs, va, vn, vs} = value;
601
+ if (fr === null || md === null) {
602
+ errors.push({
603
+ type: 'buffer',
604
+ field: 'hlo',
605
+ message: 'Optional HTLC lock fields must be a Buffer or undefined'
606
+ });
607
+ }
608
+
609
+ if (b4a.isBuffer(fa) && fa.length === AMOUNT_BYTE_LENGTH) {
610
+ const feeIsZero = fa.every(byte => byte === 0);
611
+ if (feeIsZero === (fr !== undefined)) {
612
+ errors.push({
613
+ type: 'conditionalDependency',
614
+ field: 'hlo.fr',
615
+ message: 'Fee recipient must be present exactly when the HTLC fee amount is non-zero'
616
+ });
617
+ }
618
+ }
619
+
620
+ if (Array.isArray(ss) && ss.length <= HTLC_MAX_SIGNERS) {
621
+ const uniqueSignerKeys = new Set();
622
+ for (let index = 0; index < ss.length; index++) {
623
+ const signer = ss[index];
624
+ if (!b4a.isBuffer(signer) || signer.length !== PUBLIC_KEY_LENGTH) continue;
625
+
626
+ const signerHex = b4a.toString(signer, 'hex');
627
+ if (uniqueSignerKeys.has(signerHex)) {
628
+ errors.push({
629
+ type: 'duplicateSigner',
630
+ field: 'hlo.ss',
631
+ message: 'HTLC signer set must not contain duplicate public keys'
632
+ });
633
+ break;
634
+ }
635
+ uniqueSignerKeys.add(signerHex);
636
+
637
+ if (
638
+ index > 1 &&
639
+ b4a.isBuffer(ss[index - 1]) &&
640
+ ss[index - 1].length === PUBLIC_KEY_LENGTH &&
641
+ b4a.compare(ss[index - 1], signer) >= 0
642
+ ) {
643
+ errors.push({
644
+ type: 'signerOrder',
645
+ field: 'hlo.ss',
646
+ message: 'HTLC cosigner public keys must be sorted by raw bytes'
647
+ });
648
+ break;
649
+ }
650
+ }
651
+ }
652
+
653
+ if (b4a.isBuffer(th) && th.length === HTLC_THRESHOLD_BYTE_LENGTH && Array.isArray(ss)) {
654
+ const threshold = th[0];
655
+ if (threshold < 1 || threshold > ss.length) {
656
+ errors.push({
657
+ type: 'threshold',
658
+ field: 'hlo.th',
659
+ message: 'HTLC threshold must be between one and the signer-set size'
660
+ });
661
+ } else if (Array.isArray(cs) && 1 + cs.length < threshold) {
662
+ errors.push({
663
+ type: 'threshold',
664
+ field: 'hlo.cs',
665
+ message: 'HTLC signatures do not satisfy the declared threshold'
666
+ });
667
+ }
668
+ }
669
+
670
+ if (Array.isArray(cs) && Array.isArray(ss) && cs.length > ss.length - 1) {
671
+ errors.push({
672
+ type: 'signatureCount',
673
+ field: 'hlo.cs',
674
+ message: 'HTLC cosigner signatures cannot outnumber the cosigner keys'
675
+ });
676
+ }
677
+
678
+ const validatorFieldsPresent = [va, vn, vs].filter(field => field !== undefined).length;
679
+ if (validatorFieldsPresent > 0 && validatorFieldsPresent < 3) {
680
+ errors.push({
681
+ type: 'conditionalDependency',
682
+ field: 'hlo',
683
+ message: 'Fields "va", "vn", and "vs" must all be present if any one is provided'
684
+ });
685
+ }
686
+ if (va === null || vn === null || vs === null) {
687
+ errors.push({
688
+ type: 'buffer',
689
+ field: 'hlo',
690
+ message: 'Validator fields cannot be null, must be a Buffer or undefined'
691
+ });
692
+ }
693
+
694
+ return value;
695
+ }
696
+ }
697
+ };
698
+ return this.#validator.compile(schema);
699
+ }
700
+
701
+ validateHtlcLockOperation(op) {
702
+ return this.#validateHtlcLockOperationSchema(op) === true;
703
+ }
704
+
705
+ #compileHtlcRefundOperationSchema() {
706
+ const schema = {
707
+ $$strict: true,
708
+ type: this.#operationTypeDomain(OperationType.HTLC_REFUND),
709
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
710
+ hro: {
711
+ strict: true,
712
+ type: 'object',
713
+ required: true,
714
+ props: {
715
+ tx: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true},
716
+ txv: {type: 'buffer', length: HASH_BYTE_LENGTH, required: true},
717
+ li: {type: 'buffer', length: HTLC_LOCK_ID_BYTE_LENGTH, required: true},
718
+ in: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true},
719
+ is: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true},
720
+ va: {type: 'buffer', length: this.#config.addressLength, optional: true},
721
+ vn: {type: 'buffer', length: NONCE_BYTE_LENGTH, optional: true},
722
+ vs: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, optional: true}
723
+ },
724
+ custom: (value, errors) => {
725
+ if (!value || typeof value !== 'object') return value;
726
+
727
+ const {va, vn, vs} = value;
728
+ const count = [va, vn, vs].filter(field => field !== undefined).length;
729
+ if (count !== 0 && count !== 3) {
730
+ errors.push({
731
+ type: 'conditionalDependency',
732
+ field: 'hro',
733
+ message: 'Fields "va", "vn", and "vs" must all be present if any one is provided'
734
+ });
735
+ }
736
+ if (va === null || vn === null || vs === null) {
737
+ errors.push({
738
+ type: 'buffer',
739
+ field: 'hro',
740
+ message: 'Validator fields cannot be null'
741
+ });
742
+ }
743
+
744
+ return value;
745
+ }
746
+ }
747
+ };
748
+ return this.#validator.compile(schema);
749
+ }
750
+
751
+ validateHtlcRefundOperation(op) {
752
+ return this.#validateHtlcRefundOperationSchema(op) === true;
753
+ }
754
+
755
+ }
756
+
757
+ export default StateValidationSchema;