trac-msb 0.2.7 → 0.2.9

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 (187) hide show
  1. package/.github/workflows/publish.yml +8 -16
  2. package/msb.mjs +13 -25
  3. package/package.json +8 -4
  4. package/proto/network.proto +74 -0
  5. package/rpc/{create_server.mjs → create_server.js} +4 -4
  6. package/rpc/{handlers.mjs → handlers.js} +7 -7
  7. package/rpc/routes/{index.mjs → index.js} +1 -1
  8. package/rpc/routes/{v1.mjs → v1.js} +1 -1
  9. package/rpc/rpc_server.js +10 -0
  10. package/rpc/rpc_services.js +48 -7
  11. package/rpc/utils/{helpers.mjs → helpers.js} +1 -1
  12. package/src/config/config.js +137 -0
  13. package/src/config/env.js +63 -0
  14. package/src/core/network/Network.js +133 -119
  15. package/src/core/network/identity/NetworkWalletFactory.js +5 -6
  16. package/src/core/network/protocols/LegacyProtocol.js +67 -0
  17. package/src/core/network/protocols/NetworkMessages.js +48 -0
  18. package/src/core/network/protocols/ProtocolInterface.js +31 -0
  19. package/src/core/network/protocols/ProtocolSession.js +59 -0
  20. package/src/core/network/protocols/V1Protocol.js +64 -0
  21. package/src/core/network/protocols/legacy/NetworkMessageRouter.js +84 -0
  22. package/src/core/network/protocols/legacy/handlers/GetRequestHandler.js +53 -0
  23. package/src/core/network/protocols/legacy/handlers/ResponseHandler.js +37 -0
  24. package/src/core/network/{messaging → protocols/legacy}/validators/ValidatorResponse.js +2 -2
  25. package/src/core/network/{messaging → protocols/legacy}/validators/base/BaseResponse.js +13 -6
  26. package/src/core/network/protocols/shared/handlers/RoleOperationHandler.js +88 -0
  27. package/src/core/network/protocols/shared/handlers/SubnetworkOperationHandler.js +93 -0
  28. package/src/core/network/protocols/shared/handlers/TransferOperationHandler.js +57 -0
  29. package/src/core/network/{messaging → protocols/shared}/handlers/base/BaseOperationHandler.js +21 -26
  30. package/src/core/network/{messaging → protocols/shared}/validators/PartialBootstrapDeployment.js +3 -3
  31. package/src/core/network/{messaging → protocols/shared}/validators/PartialRoleAccess.js +15 -12
  32. package/src/core/network/{messaging → protocols/shared}/validators/PartialTransaction.js +10 -11
  33. package/src/core/network/{messaging → protocols/shared}/validators/PartialTransfer.js +10 -7
  34. package/src/core/network/{messaging → protocols/shared}/validators/base/PartialOperation.js +40 -22
  35. package/src/core/network/protocols/v1/NetworkMessageRouter.js +15 -0
  36. package/src/core/network/services/ConnectionManager.js +13 -19
  37. package/src/core/network/services/MessageOrchestrator.js +10 -22
  38. package/src/core/network/services/TransactionPoolService.js +10 -10
  39. package/src/core/network/services/TransactionRateLimiterService.js +5 -3
  40. package/src/core/network/services/ValidatorObserverService.js +46 -21
  41. package/src/core/state/State.js +137 -141
  42. package/src/core/state/utils/address.js +18 -16
  43. package/src/core/state/utils/adminEntry.js +17 -16
  44. package/src/core/state/utils/deploymentEntry.js +15 -15
  45. package/src/core/state/utils/transaction.js +3 -95
  46. package/src/index.js +250 -325
  47. package/src/messages/network/v1/NetworkMessageBuilder.js +325 -0
  48. package/src/messages/network/v1/NetworkMessageDirector.js +137 -0
  49. package/src/messages/network/v1/networkMessageFactory.js +12 -0
  50. package/src/messages/state/ApplyStateMessageBuilder.js +661 -0
  51. package/src/messages/state/ApplyStateMessageDirector.js +516 -0
  52. package/src/messages/state/applyStateMessageFactory.js +12 -0
  53. package/src/utils/buffer.js +53 -1
  54. package/src/utils/check.js +21 -17
  55. package/src/utils/cli.js +0 -8
  56. package/src/utils/cliCommands.js +11 -11
  57. package/src/utils/constants.js +36 -24
  58. package/src/utils/fileUtils.js +1 -4
  59. package/src/utils/helpers.js +9 -20
  60. package/src/utils/migrationUtils.js +2 -2
  61. package/src/utils/normalizers.js +94 -11
  62. package/src/utils/protobuf/network.cjs +840 -0
  63. package/src/utils/protobuf/operationHelpers.js +10 -0
  64. package/tests/acceptance/v1/account/account.test.mjs +2 -2
  65. package/tests/acceptance/v1/balance/balance.test.mjs +1 -1
  66. package/tests/acceptance/v1/broadcast-transaction/broadcast-transaction.test.mjs +11 -2
  67. package/tests/acceptance/v1/rpc.test.mjs +10 -10
  68. package/tests/acceptance/v1/tx/tx.test.mjs +4 -2
  69. package/tests/acceptance/v1/tx-details/tx-details.test.mjs +7 -3
  70. package/tests/fixtures/check.fixtures.js +42 -42
  71. package/tests/fixtures/networkV1.fixtures.js +84 -0
  72. package/tests/fixtures/protobuf.fixtures.js +110 -26
  73. package/tests/helpers/StateNetworkFactory.js +3 -5
  74. package/tests/helpers/autobaseTestHelpers.js +1 -2
  75. package/tests/helpers/config.js +3 -0
  76. package/tests/helpers/setupApplyTests.js +113 -99
  77. package/tests/helpers/transactionPayloads.mjs +26 -12
  78. package/tests/unit/messages/messages.test.js +12 -0
  79. package/tests/unit/messages/network/NetworkMessageBuilder.test.js +276 -0
  80. package/tests/unit/messages/network/NetworkMessageDirector.test.js +203 -0
  81. package/tests/unit/messages/state/applyStateMessageBuilder.complete.test.js +521 -0
  82. package/tests/unit/messages/state/applyStateMessageBuilder.partial.test.js +233 -0
  83. package/tests/unit/network/ConnectionManager.test.js +10 -7
  84. package/tests/unit/network/NetworkWalletFactory.test.js +14 -14
  85. package/tests/unit/network/networkModule.test.js +3 -2
  86. package/tests/unit/state/apply/addAdmin/addAdminHappyPathScenario.js +10 -6
  87. package/tests/unit/state/apply/addAdmin/addAdminScenarioHelpers.js +11 -8
  88. package/tests/unit/state/apply/addAdmin/state.apply.addAdmin.test.js +11 -7
  89. package/tests/unit/state/apply/addIndexer/addIndexerScenarioHelpers.js +18 -20
  90. package/tests/unit/state/apply/addWriter/addWriterScenarioHelpers.js +57 -48
  91. package/tests/unit/state/apply/addWriter/addWriterValidatorRewardScenario.js +2 -1
  92. package/tests/unit/state/apply/adminRecovery/adminRecoveryScenarioHelpers.js +72 -57
  93. package/tests/unit/state/apply/adminRecovery/state.apply.adminRecovery.test.js +3 -7
  94. package/tests/unit/state/apply/appendWhitelist/appendWhitelistScenarioHelpers.js +12 -14
  95. package/tests/unit/state/apply/balanceInitialization/balanceInitializationScenarioHelpers.js +18 -13
  96. package/tests/unit/state/apply/balanceInitialization/nodeEntryBalanceUpdateFailureScenario.js +2 -1
  97. package/tests/unit/state/apply/banValidator/banValidatorBanAndReWhitelistScenario.js +2 -1
  98. package/tests/unit/state/apply/banValidator/banValidatorScenarioHelpers.js +27 -30
  99. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentDuplicateRegistrationScenario.js +2 -1
  100. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentScenarioHelpers.js +24 -21
  101. package/tests/unit/state/apply/common/access-control/adminConsistencyMismatchScenario.js +5 -4
  102. package/tests/unit/state/apply/common/access-control/adminPublicKeyDecodeFailureScenario.js +4 -3
  103. package/tests/unit/state/apply/common/balances/base/requesterBalanceScenarioBase.js +2 -1
  104. package/tests/unit/state/apply/common/commonScenarioHelper.js +16 -16
  105. package/tests/unit/state/apply/common/payload-structure/initializationDisabledScenario.js +10 -5
  106. package/tests/unit/state/apply/common/payload-structure/invalidHashValidationScenario.js +2 -2
  107. package/tests/unit/state/apply/common/requester/requesterNodeEntryBufferMissingScenario.js +2 -1
  108. package/tests/unit/state/apply/common/requester/requesterNodeEntryDecodeFailureScenario.js +2 -1
  109. package/tests/unit/state/apply/common/validatorConsistency/base/validatorConsistencyScenarioBase.js +2 -1
  110. package/tests/unit/state/apply/common/validatorEntryValidation/base/validatorEntryValidationScenarioBase.js +2 -1
  111. package/tests/unit/state/apply/disableInitialization/disableInitializationScenarioHelpers.js +16 -9
  112. package/tests/unit/state/apply/removeIndexer/removeIndexerScenarioHelpers.js +6 -5
  113. package/tests/unit/state/apply/removeWriter/removeWriterScenarioHelpers.js +23 -19
  114. package/tests/unit/state/apply/transfer/transferDoubleSpendAcrossValidatorsScenario.js +45 -36
  115. package/tests/unit/state/apply/transfer/transferScenarioHelpers.js +48 -45
  116. package/tests/unit/state/apply/txOperation/txOperationScenarioHelpers.js +32 -29
  117. package/tests/unit/state/apply/txOperation/txOperationTransferFeeGuardScenarioFactory.js +2 -1
  118. package/tests/unit/state/stateModule.test.js +0 -1
  119. package/tests/unit/state/stateTestUtils.js +7 -3
  120. package/tests/unit/state/utils/address.test.js +3 -3
  121. package/tests/unit/state/utils/adminEntry.test.js +10 -9
  122. package/tests/unit/unit.test.js +1 -1
  123. package/tests/unit/utils/buffer/buffer.test.js +62 -1
  124. package/tests/unit/utils/check/adminControlOperation.test.js +3 -3
  125. package/tests/unit/utils/check/balanceInitializationOperation.test.js +2 -2
  126. package/tests/unit/utils/check/bootstrapDeploymentOperation.test.js +2 -3
  127. package/tests/unit/utils/check/common.test.js +7 -6
  128. package/tests/unit/utils/check/coreAdminOperation.test.js +3 -3
  129. package/tests/unit/utils/check/roleAccessOperation.test.js +3 -2
  130. package/tests/unit/utils/check/transactionOperation.test.js +3 -3
  131. package/tests/unit/utils/check/transferOperation.test.js +3 -3
  132. package/tests/unit/utils/fileUtils/readAddressesFromWhitelistFile.test.js +2 -1
  133. package/tests/unit/utils/fileUtils/readBalanceMigrationFile.test.js +2 -1
  134. package/tests/unit/utils/migrationUtils/validateAddressFromIncomingFile.test.js +7 -0
  135. package/tests/unit/utils/normalizers/normalizers.test.js +469 -0
  136. package/tests/unit/utils/protobuf/operationHelpers.test.js +120 -2
  137. package/tests/unit/utils/utils.test.js +0 -1
  138. package/rpc/rpc_server.mjs +0 -10
  139. package/src/core/network/messaging/NetworkMessages.js +0 -63
  140. package/src/core/network/messaging/handlers/GetRequestHandler.js +0 -112
  141. package/src/core/network/messaging/handlers/ResponseHandler.js +0 -108
  142. package/src/core/network/messaging/handlers/RoleOperationHandler.js +0 -116
  143. package/src/core/network/messaging/handlers/SubnetworkOperationHandler.js +0 -143
  144. package/src/core/network/messaging/handlers/TransferOperationHandler.js +0 -52
  145. package/src/core/network/messaging/routes/NetworkMessageRouter.js +0 -94
  146. package/src/core/network/messaging/validators/AdminResponse.js +0 -58
  147. package/src/core/network/messaging/validators/CustomNodeResponse.js +0 -46
  148. package/src/core/state/utils/indexerEntry.js +0 -105
  149. package/src/messages/base/StateBuilder.js +0 -25
  150. package/src/messages/completeStateMessages/CompleteStateMessageBuilder.js +0 -421
  151. package/src/messages/completeStateMessages/CompleteStateMessageDirector.js +0 -252
  152. package/src/messages/completeStateMessages/CompleteStateMessageOperations.js +0 -299
  153. package/src/messages/partialStateMessages/PartialStateMessageBuilder.js +0 -272
  154. package/src/messages/partialStateMessages/PartialStateMessageDirector.js +0 -137
  155. package/src/messages/partialStateMessages/PartialStateMessageOperations.js +0 -131
  156. package/src/utils/crypto.js +0 -11
  157. package/tests/integration/apply/addAdmin/addAdminBasic.test.js +0 -68
  158. package/tests/integration/apply/addAdmin/addAdminRecovery.test.js +0 -125
  159. package/tests/integration/apply/addIndexer.test.js +0 -237
  160. package/tests/integration/apply/addWhitelist.test.js +0 -53
  161. package/tests/integration/apply/addWriter.test.js +0 -244
  162. package/tests/integration/apply/apply.test.js +0 -19
  163. package/tests/integration/apply/banValidator.test.js +0 -109
  164. package/tests/integration/apply/postTx/invalidSubValues.test.js +0 -103
  165. package/tests/integration/apply/postTx/postTx.test.js +0 -222
  166. package/tests/integration/apply/removeIndexer.test.js +0 -128
  167. package/tests/integration/apply/removeWriter.test.js +0 -167
  168. package/tests/integration/apply/transfer.test.js +0 -81
  169. package/tests/integration/integration.test.js +0 -9
  170. package/tests/unit/messageOperations/assembleAddIndexerMessage.test.js +0 -21
  171. package/tests/unit/messageOperations/assembleAddWriterMessage.test.js +0 -16
  172. package/tests/unit/messageOperations/assembleAdminMessage.test.js +0 -69
  173. package/tests/unit/messageOperations/assembleBanWriterMessage.test.js +0 -16
  174. package/tests/unit/messageOperations/assemblePostTransaction.test.js +0 -442
  175. package/tests/unit/messageOperations/assembleRemoveIndexerMessage.test.js +0 -19
  176. package/tests/unit/messageOperations/assembleRemoveWriterMessage.test.js +0 -17
  177. package/tests/unit/messageOperations/assembleWhitelistMessages.test.js +0 -58
  178. package/tests/unit/messageOperations/commonsStateMessageOperationsTest.js +0 -277
  179. package/tests/unit/messageOperations/stateMessageOperations.test.js +0 -19
  180. package/tests/unit/state/utils/indexerEntry.test.js +0 -83
  181. package/tests/unit/state/utils/transaction.test.js +0 -97
  182. package/tests/unit/utils/crypto/createHash.test.js +0 -15
  183. /package/rpc/{constants.mjs → constants.js} +0 -0
  184. /package/rpc/{cors.mjs → cors.js} +0 -0
  185. /package/rpc/utils/{confirmedParameter.mjs → confirmedParameter.js} +0 -0
  186. /package/rpc/utils/{url.mjs → url.js} +0 -0
  187. /package/src/utils/{operations.js → applyOperations.js} +0 -0
@@ -10,9 +10,7 @@ import {
10
10
  BOOTSTRAP_BYTE_LENGTH,
11
11
  CHANNEL_BYTE_LENGTH,
12
12
  AMOUNT_BYTE_LENGTH,
13
- TRAC_ADDRESS_SIZE,
14
13
  } from './constants.js';
15
-
16
14
  //TODO: ATTENTION - CURRENT IMPLEMENTATION UTILIZES `custom` FOR MULTIPLE TIMES IN MANY SCHEMAS. IT SHOULD BE CLEANED UP
17
15
  // TO UTILIZE ONLY ONE FUNCTION COMMON FOR ALL THE SCHEMAS. CREATE A TICKED P2/P3.
18
16
 
@@ -25,8 +23,13 @@ class Check {
25
23
  #validateTransactionOperationSchema
26
24
  #validateTransferOperationSchema
27
25
  #validateBalanceInitializationSchema
26
+ #config
28
27
 
29
- constructor() {
28
+ /**
29
+ * @param {object} config
30
+ **/
31
+ constructor(config) {
32
+ this.#config = config
30
33
 
31
34
  this.#validator = new Validator({
32
35
  useNewCustomCheckerFunction: true,
@@ -101,6 +104,7 @@ class Check {
101
104
 
102
105
  // Complete by default - no writer needed
103
106
  #compileCoreAdminOperationSchema() {
107
+ const addressLength = this.#config.addressLength
104
108
  const schema = {
105
109
  $$strict: true,
106
110
  type: {
@@ -124,7 +128,7 @@ class Check {
124
128
  return value;
125
129
  }
126
130
  },
127
- address: { type: 'buffer', length: TRAC_ADDRESS_SIZE, required: true }, // invoker adddress (admin)
131
+ address: {type: 'buffer', length: addressLength, required: true}, // invoker adddress (admin)
128
132
  cao: {
129
133
  strict: true,
130
134
  type: 'object',
@@ -163,14 +167,14 @@ class Check {
163
167
  return value;
164
168
  }
165
169
  },
166
- address: { type: 'buffer', length: TRAC_ADDRESS_SIZE, required: true },
170
+ address: { type: 'buffer', length: this.#config.addressLength, required: true },
167
171
  bio: {
168
172
  strict: true,
169
173
  type: 'object',
170
174
  props: {
171
175
  tx: { type: 'buffer', length: HASH_BYTE_LENGTH, required: true }, // tx hash
172
176
  txv: { type: 'buffer', length: HASH_BYTE_LENGTH, required: true }, // tx validity
173
- ia: { type: 'buffer', length: TRAC_ADDRESS_SIZE, required: true }, // selected address to specific operation.
177
+ ia: { type: 'buffer', length: this.#config.addressLength, required: true }, // selected address to specific operation.
174
178
  am: { type: 'buffer', length: AMOUNT_BYTE_LENGTH, required: true }, // amount to transfer
175
179
  in: { type: 'buffer', length: NONCE_BYTE_LENGTH, required: true }, // nonce of the invoker
176
180
  is: { type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true }, // signature of the invoker
@@ -211,14 +215,14 @@ class Check {
211
215
  return value;
212
216
  }
213
217
  },
214
- address: { type: 'buffer', length: TRAC_ADDRESS_SIZE, required: true }, // invoker adddress (admin)
218
+ address: {type: 'buffer', length: this.#config.addressLength, required: true}, // invoker adddress (admin)
215
219
  aco: {
216
220
  strict: true,
217
221
  type: 'object',
218
222
  props: {
219
223
  tx: { type: 'buffer', length: HASH_BYTE_LENGTH, required: true }, // tx hash
220
224
  txv: { type: 'buffer', length: HASH_BYTE_LENGTH, required: true }, // tx validity
221
- ia: { type: 'buffer', length: TRAC_ADDRESS_SIZE, required: true }, // incoming address - selected address for specific operation
225
+ ia: { type: 'buffer', length: this.#config.addressLength, required: true }, // incoming address - selected address for specific operation
222
226
  in: { type: 'buffer', length: NONCE_BYTE_LENGTH, required: true }, // nonce
223
227
  is: { type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true }, // signature
224
228
  }
@@ -256,7 +260,7 @@ class Check {
256
260
  return value;
257
261
  }
258
262
  },
259
- address: { type: 'buffer', length: TRAC_ADDRESS_SIZE, required: true },
263
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
260
264
  rao: {
261
265
  strict: true,
262
266
  type: 'object',
@@ -266,7 +270,7 @@ class Check {
266
270
  iw: { type: 'buffer', length: WRITER_BYTE_LENGTH, required: true }, // writing key of the invoker
267
271
  in: { type: 'buffer', length: NONCE_BYTE_LENGTH, required: true }, // nonce of the invoker
268
272
  is: { type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true }, // signature
269
- va: { type: 'buffer', length: TRAC_ADDRESS_SIZE, optional: true },
273
+ va: { type: 'buffer', length: this.#config.addressLength, optional: true },
270
274
  vn: { type: 'buffer', length: NONCE_BYTE_LENGTH, optional: true },
271
275
  vs: { type: 'buffer', length: SIGNATURE_BYTE_LENGTH, optional: true }
272
276
 
@@ -325,7 +329,7 @@ class Check {
325
329
  return value;
326
330
  }
327
331
  },
328
- address: { type: 'buffer', length: TRAC_ADDRESS_SIZE, required: true }, // invoker address
332
+ address: {type: 'buffer', length: this.#config.addressLength, required: true}, // invoker address
329
333
  txo: {
330
334
  strict: true,
331
335
  type: 'object',
@@ -338,7 +342,7 @@ class Check {
338
342
  mbs: { type: 'buffer', length: BOOTSTRAP_BYTE_LENGTH, required: true }, // MSB bootstrap key
339
343
  in: { type: 'buffer', length: NONCE_BYTE_LENGTH, required: true }, // Nonce of the requesting node
340
344
  is: { type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true }, // Requester's signature
341
- va: { type: 'buffer', length: TRAC_ADDRESS_SIZE, optional: true }, //validator address
345
+ va: { type: 'buffer', length: this.#config.addressLength, optional: true }, //validator address
342
346
  vn: { type: 'buffer', length: NONCE_BYTE_LENGTH, optional: true }, //validator nonce
343
347
  vs: { type: 'buffer', length: SIGNATURE_BYTE_LENGTH, optional: true }, //validator signature
344
348
  },
@@ -396,7 +400,7 @@ class Check {
396
400
  return value;
397
401
  }
398
402
  },
399
- address: { type: 'buffer', length: TRAC_ADDRESS_SIZE, required: true },
403
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
400
404
  bdo: {
401
405
 
402
406
  strict: true,
@@ -408,7 +412,7 @@ class Check {
408
412
  ic: { type: 'buffer', length: CHANNEL_BYTE_LENGTH, required: true },
409
413
  in: { type: 'buffer', length: NONCE_BYTE_LENGTH, required: true },
410
414
  is: { type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true },
411
- va: { type: 'buffer', length: TRAC_ADDRESS_SIZE, optional: true },
415
+ va: { type: 'buffer', length: this.#config.addressLength, optional: true },
412
416
  vn: { type: 'buffer', length: NONCE_BYTE_LENGTH, optional: true },
413
417
  vs: { type: 'buffer', length: SIGNATURE_BYTE_LENGTH, optional: true },
414
418
  },
@@ -466,18 +470,18 @@ class Check {
466
470
  return value;
467
471
  }
468
472
  },
469
- address: { type: 'buffer', length: TRAC_ADDRESS_SIZE, required: true },
473
+ address: {type: 'buffer', length: this.#config.addressLength, required: true},
470
474
  tro: {
471
475
  strict: true,
472
476
  type: 'object',
473
477
  props: {
474
478
  tx: { type: 'buffer', length: HASH_BYTE_LENGTH, required: true }, // tx hash
475
479
  txv: { type: 'buffer', length: HASH_BYTE_LENGTH, required: true }, // tx validity
476
- to: { type: 'buffer', length: TRAC_ADDRESS_SIZE, required: true }, // recipient address
480
+ to: { type: 'buffer', length: this.#config.addressLength, required: true }, // recipient address
477
481
  am: { type: 'buffer_amount', length: AMOUNT_BYTE_LENGTH, required: true }, // amount to transfer
478
482
  in: { type: 'buffer', length: NONCE_BYTE_LENGTH, required: true }, // nonce of the invoker
479
483
  is: { type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true }, // signature of the invoker
480
- va: { type: 'buffer', length: TRAC_ADDRESS_SIZE, optional: true }, // validator address
484
+ va: { type: 'buffer', length: this.#config.addressLength, optional: true }, // validator address
481
485
  vn: { type: 'buffer', length: NONCE_BYTE_LENGTH, optional: true }, // validator nonce
482
486
  vs: { type: 'buffer', length: SIGNATURE_BYTE_LENGTH, optional: true } // validator signature
483
487
 
package/src/utils/cli.js CHANGED
@@ -39,14 +39,6 @@ export async function verifyDag(state, network, wallet, writerKey) {
39
39
  const wl = await state.getWriterLength();
40
40
  console.log('Total Registered Writers:', wl !== null ? wl : 0);
41
41
 
42
- console.log("---------- connections stats ----------");
43
- console.log("Admin Stream:", network.admin_stream ? "Connected" : "Not Connected");
44
- console.log("Admin Public Key:", network.admin ? network.admin.toString('hex') : "None");
45
- console.log("Validator Stream:", network.validatorConnectionManager.connectionCount() > 0 ? "Connected" : "Not Connected");
46
- console.log("Validator Public Key:", network.validator ? network.validator.toString('hex') : "None");
47
- console.log("Custom Stream:", network.custom_stream ? "Connected" : "Not Connected");
48
- console.log("Custom Node Address:", network.custom_node ? network.custom_node.toString('hex') : "None");
49
-
50
42
  console.log("---------- flags ----------");
51
43
  try {
52
44
  console.log(`isIndexer: ${state?.isIndexer?.() ?? 'unset'}`);
@@ -83,20 +83,20 @@ export async function coreInfoCommand(state) {
83
83
  }
84
84
  }
85
85
 
86
- export async function getValidatorAddressCommand(state, wkHexString) {
86
+ export async function getValidatorAddressCommand(state, wkHexString, prefix) {
87
87
  const payload = await state.getSigned(EntryType.WRITER_ADDRESS + wkHexString);
88
88
  if (payload === null) {
89
89
  console.log(`No address assigned to the writer key: ${wkHexString}`);
90
90
  } else {
91
- console.log(`Address assigned to the writer key: ${wkHexString} - ${bufferToAddress(payload)}`);
91
+ console.log(`Address assigned to the writer key: ${wkHexString} - ${bufferToAddress(payload, prefix)}`);
92
92
  }
93
93
  }
94
94
 
95
- export async function getDeploymentCommand(state, bootstrapHex) {
95
+ export async function getDeploymentCommand(state, bootstrapHex, addressLength) {
96
96
  const deploymentEntry = await state.getRegisteredBootstrapEntry(bootstrapHex);
97
97
  console.log(`Searching deployment for bootstrap: ${bootstrapHex}`);
98
98
  if (deploymentEntry) {
99
- const decodedDeploymentEntry = deploymentEntryUtils.decode(deploymentEntry);
99
+ const decodedDeploymentEntry = deploymentEntryUtils.decode(deploymentEntry, addressLength);
100
100
  const txhash = decodedDeploymentEntry.txHash.toString("hex");
101
101
  console.log(`Bootstrap deployed under transaction hash: ${txhash}`);
102
102
  const payload = await state.getSigned(txhash);
@@ -189,7 +189,7 @@ export function getUnconfirmedLengthCommand(state) {
189
189
  return unconfirmedLength;
190
190
  }
191
191
 
192
- export async function getTxPayloadsBulkCommand(state, hashes) {
192
+ export async function getTxPayloadsBulkCommand(state, hashes, config) {
193
193
  if (!Array.isArray(hashes) || hashes.length === 0) {
194
194
  throw new Error("Missing hash list.");
195
195
  }
@@ -208,7 +208,7 @@ export async function getTxPayloadsBulkCommand(state, hashes) {
208
208
  if (result === null || result === undefined) {
209
209
  res.missing.push(hash);
210
210
  } else {
211
- const decodedResult = normalizeDecodedPayloadForJson(result.decoded);
211
+ const decodedResult = normalizeDecodedPayloadForJson(result.decoded, config);
212
212
  res.results.push({ hash, payload: decodedResult });
213
213
  }
214
214
  });
@@ -225,20 +225,20 @@ export async function getTxHashesCommand(state, start, end) {
225
225
  }
226
226
  }
227
227
 
228
- export async function getTxDetailsCommand(state, hash) {
228
+ export async function getTxDetailsCommand(state, hash, config) {
229
229
  try {
230
230
  const rawPayload = await get_confirmed_tx_info(state, hash);
231
231
  if (!rawPayload) {
232
232
  console.log(`No payload found for tx hash: ${hash}`);
233
233
  return null;
234
234
  }
235
- return normalizeDecodedPayloadForJson(rawPayload.decoded);
235
+ return normalizeDecodedPayloadForJson(rawPayload.decoded, config);
236
236
  } catch (error) {
237
237
  throw new Error("Invalid params to perform the request.", error.message);
238
238
  }
239
239
  }
240
240
 
241
- export async function getExtendedTxDetailsCommand(state, hash, confirmed) {
241
+ export async function getExtendedTxDetailsCommand(state, hash, confirmed, config) {
242
242
  if (confirmed) {
243
243
  const rawPayload = await get_confirmed_tx_info(state, hash);
244
244
  if (!rawPayload) {
@@ -248,7 +248,7 @@ export async function getExtendedTxDetailsCommand(state, hash, confirmed) {
248
248
  if (confirmedLength === null) {
249
249
  throw new Error(`No confirmed length found for tx hash: ${hash} in confirmed mode`);
250
250
  }
251
- const normalizedPayload = normalizeDecodedPayloadForJson(rawPayload.decoded, true);
251
+ const normalizedPayload = normalizeDecodedPayloadForJson(rawPayload.decoded, config);
252
252
  const fee = state.getFee();
253
253
  return {
254
254
  txDetails: normalizedPayload,
@@ -261,7 +261,7 @@ export async function getExtendedTxDetailsCommand(state, hash, confirmed) {
261
261
  if (!rawPayload) {
262
262
  throw new Error(`No payload found for tx hash: ${hash}`);
263
263
  }
264
- const normalizedPayload = normalizeDecodedPayloadForJson(rawPayload.decoded, true);
264
+ const normalizedPayload = normalizeDecodedPayloadForJson(rawPayload.decoded, config);
265
265
  const length = await state.getTransactionConfirmedLength(hash);
266
266
  if (length === null) {
267
267
  return {
@@ -1,4 +1,5 @@
1
- import { OperationType as OP } from './protobuf/applyOperations.cjs';
1
+ import { OperationType as ApplyOperationType } from './protobuf/applyOperations.cjs';
2
+ import { MessageType as NetworkMessageType, ResultCode as NetworkResultCode } from './protobuf/network.cjs';
2
3
  import b4a from 'b4a'
3
4
  // TODO: We are going to have a lot of contstants. It would be good, to separate them into different files.
4
5
 
@@ -17,19 +18,37 @@ export const EntryType = Object.freeze({
17
18
 
18
19
  //ATTENTION - THIS IS USED IN THE APPLY FUNCTION!
19
20
  export const OperationType = Object.freeze({
20
- ADD_ADMIN: OP.ADD_ADMIN,
21
- DISABLE_INITIALIZATION: OP.DISABLE_INITIALIZATION,
22
- BALANCE_INITIALIZATION: OP.BALANCE_INITIALIZATION,
23
- APPEND_WHITELIST: OP.APPEND_WHITELIST,
24
- ADD_WRITER: OP.ADD_WRITER,
25
- REMOVE_WRITER: OP.REMOVE_WRITER,
26
- ADMIN_RECOVERY: OP.ADMIN_RECOVERY,
27
- ADD_INDEXER: OP.ADD_INDEXER,
28
- REMOVE_INDEXER: OP.REMOVE_INDEXER,
29
- BAN_VALIDATOR: OP.BAN_VALIDATOR,
30
- BOOTSTRAP_DEPLOYMENT: OP.BOOTSTRAP_DEPLOYMENT,
31
- TX: OP.TX,
32
- TRANSFER: OP.TRANSFER,
21
+ ADD_ADMIN: ApplyOperationType.ADD_ADMIN,
22
+ DISABLE_INITIALIZATION: ApplyOperationType.DISABLE_INITIALIZATION,
23
+ BALANCE_INITIALIZATION: ApplyOperationType.BALANCE_INITIALIZATION,
24
+ APPEND_WHITELIST: ApplyOperationType.APPEND_WHITELIST,
25
+ ADD_WRITER: ApplyOperationType.ADD_WRITER,
26
+ REMOVE_WRITER: ApplyOperationType.REMOVE_WRITER,
27
+ ADMIN_RECOVERY: ApplyOperationType.ADMIN_RECOVERY,
28
+ ADD_INDEXER: ApplyOperationType.ADD_INDEXER,
29
+ REMOVE_INDEXER: ApplyOperationType.REMOVE_INDEXER,
30
+ BAN_VALIDATOR: ApplyOperationType.BAN_VALIDATOR,
31
+ BOOTSTRAP_DEPLOYMENT: ApplyOperationType.BOOTSTRAP_DEPLOYMENT,
32
+ TX: ApplyOperationType.TX,
33
+ TRANSFER: ApplyOperationType.TRANSFER,
34
+ });
35
+
36
+ export const NetworkOperationType = Object.freeze({
37
+ VALIDATOR_CONNECTION_REQUEST: NetworkMessageType.MESSAGE_TYPE_VALIDATOR_CONNECTION_REQUEST,
38
+ VALIDATOR_CONNECTION_RESPONSE: NetworkMessageType.MESSAGE_TYPE_VALIDATOR_CONNECTION_RESPONSE,
39
+ LIVENESS_REQUEST: NetworkMessageType.MESSAGE_TYPE_LIVENESS_REQUEST,
40
+ LIVENESS_RESPONSE: NetworkMessageType.MESSAGE_TYPE_LIVENESS_RESPONSE,
41
+ BROADCAST_TRANSACTION_REQUEST: NetworkMessageType.MESSAGE_TYPE_BROADCAST_TRANSACTION_REQUEST,
42
+ BROADCAST_TRANSACTION_RESPONSE: NetworkMessageType.MESSAGE_TYPE_BROADCAST_TRANSACTION_RESPONSE,
43
+ });
44
+
45
+ export const ResultCode = Object.freeze({
46
+ OK: NetworkResultCode.RESULT_CODE_OK,
47
+ INVALID_PAYLOAD: NetworkResultCode.RESULT_CODE_INVALID_PAYLOAD,
48
+ UNSUPPORTED_VERSION: NetworkResultCode.RESULT_CODE_UNSUPPORTED_VERSION,
49
+ RATE_LIMITED: NetworkResultCode.RESULT_CODE_RATE_LIMITED,
50
+ TIMEOUT: NetworkResultCode.RESULT_CODE_TIMEOUT,
51
+ SIGNATURE_INVALID: NetworkResultCode.RESULT_CODE_SIGNATURE_INVALID,
33
52
  });
34
53
 
35
54
  // Role managment constants
@@ -40,6 +59,8 @@ export const EventType = Object.freeze({
40
59
  WRITABLE: 'writable',
41
60
  UNWRITABLE: 'unwritable',
42
61
  WARNING: 'warning',
62
+ VALIDATOR_CONNECTION_READY: 'validator-connection-ready',
63
+ VALIDATOR_CONNECTION_TIMEOUT: 'validator-connection-timeout',
43
64
  });
44
65
 
45
66
  // Role managment constants
@@ -66,8 +87,8 @@ export const MAX_PEERS = 64;
66
87
  export const MAX_PARALLEL = 64;
67
88
  export const MAX_SERVER_CONNECTIONS = Infinity;
68
89
  export const MAX_CLIENT_CONNECTIONS = Infinity;
69
- export const DHT_BOOTSTRAPS = ['116.202.214.149:10001', '157.180.12.214:10001', 'node1.hyperdht.org:49737', 'node2.hyperdht.org:49737', 'node3.hyperdht.org:49737'];
70
90
  export const MAX_WRITERS_FOR_ADMIN_INDEXER_CONNECTION = 10;
91
+
71
92
  // State
72
93
  export const ACK_INTERVAL = 1_000;
73
94
  export const AUTOBASE_VALUE_ENCODING = 'binary';
@@ -119,12 +140,3 @@ export const NETWORK_MESSAGE_TYPES = Object.freeze({
119
140
  NODE: 'nodeResponse'
120
141
  },
121
142
  });
122
-
123
- export const TRAC_ADDRESS_SIZE = 63; // TODO: Change this to config().addressLength || 63
124
- export const NETWORK_ID = 918; // TODO: Change this to config().network_id || 918
125
-
126
- export const MAX_VALIDATORS_IN_CONNECTION_POOL = 50;
127
- export const MAX_MESSAGE_SEND_ATTEMPTS = 3;
128
- export const MESSAGE_VALIDATOR_RETRY_DELAY_MS = 1000;
129
- export const MESSAGE_VALIDATOR_RESPONSE_TIMEOUT_MS = 3 * MAX_MESSAGE_SEND_ATTEMPTS * MESSAGE_VALIDATOR_RETRY_DELAY_MS;
130
- export const MAX_SUCCESSIVE_MESSAGES_PER_VALIDATOR = 3;
@@ -1,11 +1,8 @@
1
1
  import fs from 'fs'; // TODO: If we are using bare environment, we should use bare-fs instead
2
2
  import path from 'path';
3
3
  import { WHITELIST_FILEPATH, BALANCE_MIGRATION_FILEPATH, BALANCE_MIGRATED_DIR, WHITELIST_MIGRATION_DIR } from '../utils/constants.js';
4
- import { isAddressValid } from '../core/state/utils/address.js';
5
4
  import { decimalStringToBigInt, bigIntTo16ByteBuffer, bufferToBigInt, bigIntToDecimalString } from './amountSerialization.js';
6
- import PeerWallet from 'trac-wallet';
7
- import b4a from 'b4a';
8
- import { ZERO_LICENSE } from '../core/state/utils/nodeEntry.js';
5
+
9
6
  const MIGRATED_FILE_REGEX = /^migrated(\d+)\.csv$/;
10
7
 
11
8
  /**
@@ -1,6 +1,6 @@
1
1
  import b4a from "b4a";
2
2
  import {bufferToAddress} from "../core/state/utils/address.js";
3
- import { EntryType, TRAC_ADDRESS_SIZE } from "./constants.js";
3
+ import { EntryType } from "./constants.js";
4
4
 
5
5
  //TODO: change file name or split functions below into multiple files (Remember to update imports and tests accordingly)
6
6
 
@@ -48,7 +48,7 @@ export const safeJsonParse = (str) => {
48
48
  return undefined;
49
49
  }
50
50
 
51
- export async function getFormattedIndexersWithAddresses(state) {
51
+ export async function getFormattedIndexersWithAddresses(state, config) {
52
52
  const indexers = await state.getIndexersEntry();
53
53
  const formatted = indexers.map((entry) => ({
54
54
  writingKey: b4a.toString(entry.key, "hex"),
@@ -56,7 +56,10 @@ export async function getFormattedIndexersWithAddresses(state) {
56
56
 
57
57
  const results = await Promise.all(
58
58
  formatted.map(async (entry) => {
59
- const address = bufferToAddress(await state.getSigned(EntryType.WRITER_ADDRESS + entry.writingKey));
59
+ const address = bufferToAddress(
60
+ await state.getSigned(EntryType.WRITER_ADDRESS + entry.writingKey),
61
+ config.addressPrefix
62
+ );
60
63
 
61
64
  return {
62
65
  ...entry,
@@ -68,14 +71,14 @@ export async function getFormattedIndexersWithAddresses(state) {
68
71
  return results;
69
72
  }
70
73
 
71
- export function formatIndexersEntry(indexersEntry) {
74
+ export function formatIndexersEntry(indexersEntry, addressLength) {
72
75
 
73
76
  const count = indexersEntry[0];
74
77
  const indexers = [];
75
78
 
76
79
  for (let i = 0; i < count; i++) {
77
- const start = 1 + (i * TRAC_ADDRESS_SIZE);
78
- const end = start + TRAC_ADDRESS_SIZE;
80
+ const start = 1 + (i * addressLength);
81
+ const end = start + addressLength;
79
82
  const indexerAddr = indexersEntry.subarray(start, end);
80
83
  indexers.push(indexerAddr.toString('ascii'));
81
84
  }
@@ -86,20 +89,6 @@ export function formatIndexersEntry(indexersEntry) {
86
89
  };
87
90
  }
88
91
 
89
- export function convertAdminCoreOperationPayloadToHex(payload) {
90
- return {
91
- ...payload,
92
- address: bufferToAddress(payload.address),
93
- aco: {
94
- tx: payload.aco.tx.toString('hex'),
95
- txv: payload.aco.txv.toString('hex'),
96
- in: payload.aco.in.toString('hex'),
97
- ia: payload.aco.ia.toString('hex'),
98
- is: payload.aco.is.toString('hex'),
99
- },
100
- };
101
- }
102
-
103
92
  export function isTransactionRecordPut(entry) {
104
93
  const isPut = entry.type === "put";
105
94
  const isHex = isHexString(entry.key);
@@ -4,8 +4,8 @@ import PeerWallet from 'trac-wallet';
4
4
  import b4a from 'b4a';
5
5
  import { ZERO_LICENSE } from '../core/state/utils/nodeEntry.js';
6
6
 
7
- export async function validateAddressFromIncomingFile(stateInstance, address, adminEntry) {
8
- if (!isAddressValid(address)) {
7
+ export async function validateAddressFromIncomingFile(stateInstance, config, address, adminEntry) {
8
+ if (!isAddressValid(address, config.addressPrefix)) {
9
9
  throw new Error(`Invalid address format: '${address}'. Please ensure all addresses are valid.`);
10
10
  }
11
11
 
@@ -10,10 +10,11 @@ import { bufferToBigInt } from './amountSerialization.js'
10
10
  * to the correct buffer or hexadecimal string format for processing.
11
11
  *
12
12
  * @param {Object} payload The raw payload for the transfer operation.
13
+ * @param {object} config The environment configuration object.
13
14
  * @returns {Object} A new object with addresses converted to buffers and hex values normalized.
14
15
  * @throws {Error} If the payload is invalid or missing required fields.
15
16
  */
16
- export function normalizeTransferOperation(payload) {
17
+ export function normalizeTransferOperation(payload, config) {
17
18
  if (!payload || typeof payload !== 'object' || !payload.tro) {
18
19
  throw new Error('Invalid payload for transfer operation normalization.');
19
20
  }
@@ -31,19 +32,27 @@ export function normalizeTransferOperation(payload) {
31
32
  tx: normalizeHex(tro.tx), // Transaction hash
32
33
  txv: normalizeHex(tro.txv), // Transaction validity
33
34
  in: normalizeHex(tro.in), // Nonce
34
- to: addressToBuffer(tro.to), // Recipient address
35
+ to: addressToBuffer(tro.to, config.addressPrefix), // Recipient address
35
36
  am: normalizeHex(tro.am), // Amount
36
37
  is: normalizeHex(tro.is) // Signature
37
38
  };
38
39
 
39
40
  return {
40
41
  type,
41
- address: addressToBuffer(address),
42
+ address: addressToBuffer(address, config.addressPrefix),
42
43
  tro: normalizedTro
43
44
  };
44
45
  }
45
46
 
46
- export function normalizeTransactionOperation(payload) {
47
+ /**
48
+ * Normalizes the payload for a transaction operation.
49
+ * This is useful for validating and assembling a transaction operation.
50
+ *
51
+ * @param {Object} payload The raw payload for the transaction operation.
52
+ * @param {object} config The environment configuration object.
53
+ * @returns {Object} A normalized payload with addresses converted to buffers and hex values normalized.
54
+ */
55
+ export function normalizeTransactionOperation(payload, config) {
47
56
  if (!payload || typeof payload !== 'object' || !payload.txo) {
48
57
  throw new Error('Invalid payload for transaction operation normalization.');
49
58
  }
@@ -70,7 +79,7 @@ export function normalizeTransactionOperation(payload) {
70
79
 
71
80
  return {
72
81
  type,
73
- address: addressToBuffer(address),
82
+ address: addressToBuffer(address, config.addressPrefix),
74
83
  txo: normalizedTxo
75
84
  };
76
85
  }
@@ -79,10 +88,11 @@ export function normalizeTransactionOperation(payload) {
79
88
  * Normalizes an operation payload by converting any Buffer values to hex strings.
80
89
  * This is useful for preparing a payload to be returned as a JSON response.
81
90
  *
82
- * @param {Object} payload The decoded transaction payload.
83
- * @returns {Object} A new object with Buffer values converted to hex strings.
91
+ * @param {Object} payload The raw payload for the role access operation.
92
+ * @param {object} config The environment configuration object.
93
+ * @returns {Object} A normalized payload with addresses converted to buffers and hex values normalized.
84
94
  */
85
- export function normalizeDecodedPayloadForJson(payload) {
95
+ export function normalizeDecodedPayloadForJson(payload, config) {
86
96
  if (!payload || typeof payload !== "object") {
87
97
  return payload;
88
98
  }
@@ -96,7 +106,7 @@ export function normalizeDecodedPayloadForJson(payload) {
96
106
  if (b4a.isBuffer(value)) {
97
107
  // 👇 intercept address buffers by key name (e.g. `address`)
98
108
  if (addressKeys.some(k => key.toLowerCase().includes(k))) {
99
- const addr = bufferToAddress(value);
109
+ const addr = bufferToAddress(value, config.addressPrefix);
100
110
  newPayload[key] = addr ?? b4a.toString(value, "hex");
101
111
  } else if (key.toLowerCase().includes("am")) {
102
112
  const amount = bufferToBigInt(value)
@@ -107,7 +117,7 @@ export function normalizeDecodedPayloadForJson(payload) {
107
117
 
108
118
  } else if (typeof value === "object" && value !== null) {
109
119
  // recursively handle nested objects
110
- newPayload[key] = normalizeDecodedPayloadForJson(value);
120
+ newPayload[key] = normalizeDecodedPayloadForJson(value, config);
111
121
 
112
122
  } else {
113
123
  newPayload[key] = value;
@@ -115,4 +125,77 @@ export function normalizeDecodedPayloadForJson(payload) {
115
125
  }
116
126
  }
117
127
  return newPayload;
118
- }
128
+ }
129
+
130
+ /**
131
+ * Normalizes the payload for a role access operation.
132
+ * This is useful for validating and assembling a role access operation.
133
+ *
134
+ * @param {Object} payload The raw payload for the role access operation.
135
+ * @param {object} config The environment configuration object.
136
+ * @returns {Object} A normalized payload with addresses converted to buffers and hex values normalized.
137
+ */
138
+ export function normalizeRoleAccessOperation(payload, config) {
139
+ if (!payload || typeof payload !== 'object' || !payload.rao) {
140
+ throw new Error('Invalid payload for role access normalization.');
141
+ }
142
+ const { type, address, rao } = payload;
143
+ if (
144
+ !type ||
145
+ !address ||
146
+ !rao.tx || !rao.txv || !rao.iw || !rao.in || !rao.is
147
+ ) {
148
+ throw new Error('Missing required fields in role access payload.');
149
+ }
150
+
151
+ const normalizedRao = {
152
+ tx: normalizeHex(rao.tx),
153
+ txv: normalizeHex(rao.txv),
154
+ iw: normalizeHex(rao.iw),
155
+ in: normalizeHex(rao.in),
156
+ is: normalizeHex(rao.is)
157
+ };
158
+
159
+ return {
160
+ type,
161
+ address: addressToBuffer(address, config.addressPrefix),
162
+ rao: normalizedRao
163
+ };
164
+ }
165
+
166
+ /**
167
+ * Normalizes the payload for a bootstrap deployment operation.
168
+ * This is useful for validating and assembling a bootstrap deployment operation.
169
+ *
170
+ * @param {Object} payload The raw payload for the bootstrap deployment operation.
171
+ * @param {object} config The environment configuration object.
172
+ * @returns {Object} A normalized payload with addresses converted to buffers and hex values normalized.
173
+ */
174
+ export function normalizeBootstrapDeploymentOperation(payload, config) {
175
+ if (!payload || typeof payload !== 'object' || !payload.bdo) {
176
+ throw new Error('Invalid payload for bootstrap deployment normalization.');
177
+ }
178
+ const { type, address, bdo } = payload;
179
+ if (
180
+ type !== OperationType.BOOTSTRAP_DEPLOYMENT ||
181
+ !address ||
182
+ !bdo.tx || !bdo.bs || !bdo.ic || !bdo.in || !bdo.is || !bdo.txv
183
+ ) {
184
+ throw new Error('Missing required fields in bootstrap deployment payload.');
185
+ }
186
+
187
+ const normalizedBdo = {
188
+ tx: normalizeHex(bdo.tx), // Transaction hash
189
+ txv: normalizeHex(bdo.txv), // Transaction validity
190
+ bs: normalizeHex(bdo.bs), // External bootstrap
191
+ ic: normalizeHex(bdo.ic), // Channel
192
+ in: normalizeHex(bdo.in), // Nonce
193
+ is: normalizeHex(bdo.is) // Signature
194
+ };
195
+
196
+ return {
197
+ type,
198
+ address: addressToBuffer(address, config.addressPrefix),
199
+ bdo: normalizedBdo
200
+ };
201
+ }