trac-msb 0.2.24 → 0.3.0-beta.1

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 (137) 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 +103 -0
  10. package/rpc/routes/v1.js +8 -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 +46 -7
  23. package/src/config/env.js +33 -6
  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/ConfirmationWatch.js +82 -0
  102. package/src/core/state/State.js +1794 -173
  103. package/src/core/state/StateEventQueue.js +69 -0
  104. package/src/core/state/utils/address.js +10 -6
  105. package/src/core/state/utils/epochProof.js +109 -0
  106. package/src/core/state/utils/escrowEntry.js +178 -0
  107. package/src/core/state/validators/StateValidationSchema.js +757 -0
  108. package/src/core/state/validators/stateValidationRules.js +312 -0
  109. package/src/index.js +255 -65
  110. package/src/messages/consensus/v1/ConsensusMessageBuilder.js +368 -0
  111. package/src/messages/consensus/v1/ConsensusMessageDirector.js +142 -0
  112. package/src/messages/consensus/v1/consensusMessageFactory.js +12 -0
  113. package/src/messages/consensus/v1/epochAppendMessage.js +58 -0
  114. package/src/messages/network/v1/NetworkMessageBuilder.js +15 -7
  115. package/src/messages/state/ApplyStateMessageBuilder.js +499 -13
  116. package/src/messages/state/ApplyStateMessageDirector.js +261 -2
  117. package/src/utils/StateMachine.js +125 -0
  118. package/src/utils/applyOperations.js +45 -2
  119. package/src/utils/buffer.js +239 -59
  120. package/src/utils/consensusConfig.js +76 -0
  121. package/src/utils/constants.js +174 -73
  122. package/src/utils/helpers.js +0 -25
  123. package/src/utils/htlcLock.js +122 -0
  124. package/src/utils/logger.js +10 -4
  125. package/src/utils/migrationUtils.js +2 -1
  126. package/src/utils/normalizers.js +113 -0
  127. package/src/utils/scheduler/SchedulableService.js +107 -0
  128. package/src/utils/{Scheduler.js → scheduler/Scheduler.js} +56 -17
  129. package/src/core/network/services/ConnectionManager.js +0 -406
  130. package/src/utils/check.js +0 -525
  131. package/src/utils/protobuf/applyOperations.cjs +0 -1373
  132. package/src/utils/protobuf/operationHelpers.js +0 -81
  133. /package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyResponseHandler.js +0 -0
  134. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/ValidatorResponse.js +0 -0
  135. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/base/BaseResponse.js +0 -0
  136. /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessRequest.js +0 -0
  137. /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessResponse.js +0 -0
@@ -1,10 +1,13 @@
1
- import { OperationType as ApplyOperationType } from './protobuf/applyOperations.cjs';
2
- import networkV1Generated from './protobuf/networkV1.generated.cjs';
1
+ import applyOperationsGenerated from '../codecs/apply/applyOperations.generated.cjs';
2
+ import networkV1Generated from '../codecs/network/v1/networkV1.generated.cjs';
3
+ import consensusV1Generated from '../codecs/consensus/v1/consensusV1.generated.cjs';
3
4
  import b4a from 'b4a'
4
5
  // TODO: We are going to have a lot of contstants. It would be good, to separate them into different files.
5
6
 
6
- const { MessageType: NetworkMessageType, ResultCode: NetworkResultCode } = networkV1Generated.network.v1;
7
-
7
+ const { OperationType: ApplyOperationType } = applyOperationsGenerated.apply.operations;
8
+ const { MessageType: NetworkMessageType } = networkV1Generated.network.v1;
9
+ const { MessageType: ConsensusMessageType } = consensusV1Generated.consensus.v1;
10
+ const { ResultCode: SharedResultCode } = networkV1Generated.common.v1;
8
11
  //ATTENTION - THIS IS USED IN THE APPLY FUNCTION!
9
12
  export const EntryType = Object.freeze({
10
13
  ADMIN: 'admin',
@@ -16,6 +19,13 @@ export const EntryType = Object.freeze({
16
19
  INITIALIZATION: 'init',
17
20
  LICENSE_COUNT: 'lc',
18
21
  LICENSE_INDEX: 'li/',
22
+ EPOCH_CURRENT: '/epoch/current',
23
+ EPOCH: `/epoch/`, // Epoch hashes are stored under `/epoch/<n>`
24
+ EPOCH_HASH: `/epochHash/`, // Versioned epoch records are stored under `/epochHash/<epochHashHex>`
25
+ CONSENSUS_CONFIG_CURRENT: '/consensus/config/current',
26
+ CONSENSUS_CONFIG_RECORD: '/consensus/config/record/',
27
+ HTLC_ESCROW: '/htlc/escrow/',
28
+
19
29
  });
20
30
 
21
31
  //ATTENTION - THIS IS USED IN THE APPLY FUNCTION!
@@ -33,6 +43,12 @@ export const OperationType = Object.freeze({
33
43
  BOOTSTRAP_DEPLOYMENT: ApplyOperationType.BOOTSTRAP_DEPLOYMENT,
34
44
  TX: ApplyOperationType.TX,
35
45
  TRANSFER: ApplyOperationType.TRANSFER,
46
+ SET_EPOCH: ApplyOperationType.SET_EPOCH,
47
+ SET_GENESIS_EPOCH: ApplyOperationType.SET_GENESIS_EPOCH,
48
+ SET_CONSENSUS_CONFIG: ApplyOperationType.SET_CONSENSUS_CONFIG,
49
+ HTLC_LOCK: ApplyOperationType.HTLC_LOCK,
50
+ HTLC_CLAIM: ApplyOperationType.HTLC_CLAIM,
51
+ HTLC_REFUND: ApplyOperationType.HTLC_REFUND,
36
52
  });
37
53
 
38
54
  export const NetworkOperationType = Object.freeze({
@@ -42,71 +58,105 @@ export const NetworkOperationType = Object.freeze({
42
58
  BROADCAST_TRANSACTION_RESPONSE: NetworkMessageType.MESSAGE_TYPE_BROADCAST_TRANSACTION_RESPONSE,
43
59
  });
44
60
 
45
- export const ResultCode = Object.freeze({
46
- UNSPECIFIED: NetworkResultCode.RESULT_CODE_UNSPECIFIED,
47
- OK: NetworkResultCode.RESULT_CODE_OK,
48
- INVALID_PAYLOAD: NetworkResultCode.RESULT_CODE_INVALID_PAYLOAD,
49
- RATE_LIMITED: NetworkResultCode.RESULT_CODE_RATE_LIMITED,
50
- SIGNATURE_INVALID: NetworkResultCode.RESULT_CODE_SIGNATURE_INVALID,
51
- UNEXPECTED_ERROR: NetworkResultCode.RESULT_CODE_UNEXPECTED_ERROR,
52
- TIMEOUT: NetworkResultCode.RESULT_CODE_TIMEOUT,
53
- NODE_HAS_NO_WRITE_ACCESS: NetworkResultCode.RESULT_CODE_NODE_HAS_NO_WRITE_ACCESS,
54
- TX_ACCEPTED_PROOF_UNAVAILABLE: NetworkResultCode.RESULT_CODE_TX_ACCEPTED_PROOF_UNAVAILABLE,
55
- NODE_OVERLOADED: NetworkResultCode.RESULT_CODE_NODE_OVERLOADED,
56
- TX_ALREADY_PENDING: NetworkResultCode.RESULT_CODE_TX_ALREADY_PENDING,
57
- OPERATION_TYPE_UNKNOWN: NetworkResultCode.RESULT_CODE_OPERATION_TYPE_UNKNOWN,
58
- SCHEMA_VALIDATION_FAILED: NetworkResultCode.RESULT_CODE_SCHEMA_VALIDATION_FAILED,
59
- REQUESTER_ADDRESS_INVALID: NetworkResultCode.RESULT_CODE_REQUESTER_ADDRESS_INVALID,
60
- REQUESTER_PUBLIC_KEY_INVALID: NetworkResultCode.RESULT_CODE_REQUESTER_PUBLIC_KEY_INVALID,
61
- TX_HASH_MISMATCH: NetworkResultCode.RESULT_CODE_TX_HASH_MISMATCH,
62
- TX_SIGNATURE_INVALID: NetworkResultCode.RESULT_CODE_TX_SIGNATURE_INVALID,
63
- TX_EXPIRED: NetworkResultCode.RESULT_CODE_TX_EXPIRED,
64
- TX_ALREADY_EXISTS: NetworkResultCode.RESULT_CODE_TX_ALREADY_EXISTS,
65
- OPERATION_ALREADY_COMPLETED: NetworkResultCode.RESULT_CODE_OPERATION_ALREADY_COMPLETED,
66
- REQUESTER_NOT_FOUND: NetworkResultCode.RESULT_CODE_REQUESTER_NOT_FOUND,
67
- INSUFFICIENT_FEE_BALANCE: NetworkResultCode.RESULT_CODE_INSUFFICIENT_FEE_BALANCE,
68
- EXTERNAL_BOOTSTRAP_EQUALS_MSB_BOOTSTRAP: NetworkResultCode.RESULT_CODE_EXTERNAL_BOOTSTRAP_EQUALS_MSB_BOOTSTRAP,
69
- SELF_VALIDATION_FORBIDDEN: NetworkResultCode.RESULT_CODE_SELF_VALIDATION_FORBIDDEN,
70
- ROLE_NODE_ENTRY_NOT_FOUND: NetworkResultCode.RESULT_CODE_ROLE_NODE_ENTRY_NOT_FOUND,
71
- ROLE_NODE_ALREADY_WRITER: NetworkResultCode.RESULT_CODE_ROLE_NODE_ALREADY_WRITER,
72
- ROLE_NODE_NOT_WHITELISTED: NetworkResultCode.RESULT_CODE_ROLE_NODE_NOT_WHITELISTED,
73
- ROLE_NODE_NOT_WRITER: NetworkResultCode.RESULT_CODE_ROLE_NODE_NOT_WRITER,
74
- ROLE_NODE_IS_INDEXER: NetworkResultCode.RESULT_CODE_ROLE_NODE_IS_INDEXER,
75
- ROLE_ADMIN_ENTRY_MISSING: NetworkResultCode.RESULT_CODE_ROLE_ADMIN_ENTRY_MISSING,
76
- ROLE_INVALID_RECOVERY_CASE: NetworkResultCode.RESULT_CODE_ROLE_INVALID_RECOVERY_CASE,
77
- ROLE_UNKNOWN_OPERATION: NetworkResultCode.RESULT_CODE_ROLE_UNKNOWN_OPERATION,
78
- ROLE_INVALID_WRITER_KEY: NetworkResultCode.RESULT_CODE_ROLE_INVALID_WRITER_KEY,
79
- ROLE_INSUFFICIENT_FEE_BALANCE: NetworkResultCode.RESULT_CODE_ROLE_INSUFFICIENT_FEE_BALANCE,
80
- MSB_BOOTSTRAP_MISMATCH: NetworkResultCode.RESULT_CODE_MSB_BOOTSTRAP_MISMATCH,
81
- EXTERNAL_BOOTSTRAP_NOT_DEPLOYED: NetworkResultCode.RESULT_CODE_EXTERNAL_BOOTSTRAP_NOT_DEPLOYED,
82
- EXTERNAL_BOOTSTRAP_TX_MISSING: NetworkResultCode.RESULT_CODE_EXTERNAL_BOOTSTRAP_TX_MISSING,
83
- EXTERNAL_BOOTSTRAP_MISMATCH: NetworkResultCode.RESULT_CODE_EXTERNAL_BOOTSTRAP_MISMATCH,
84
- BOOTSTRAP_ALREADY_EXISTS: NetworkResultCode.RESULT_CODE_BOOTSTRAP_ALREADY_EXISTS,
85
- TRANSFER_RECIPIENT_ADDRESS_INVALID: NetworkResultCode.RESULT_CODE_TRANSFER_RECIPIENT_ADDRESS_INVALID,
86
- TRANSFER_RECIPIENT_PUBLIC_KEY_INVALID: NetworkResultCode.RESULT_CODE_TRANSFER_RECIPIENT_PUBLIC_KEY_INVALID,
87
- TRANSFER_AMOUNT_TOO_LARGE: NetworkResultCode.RESULT_CODE_TRANSFER_AMOUNT_TOO_LARGE,
88
- TRANSFER_SENDER_NOT_FOUND: NetworkResultCode.RESULT_CODE_TRANSFER_SENDER_NOT_FOUND,
89
- TRANSFER_INSUFFICIENT_BALANCE: NetworkResultCode.RESULT_CODE_TRANSFER_INSUFFICIENT_BALANCE,
90
- TRANSFER_RECIPIENT_BALANCE_OVERFLOW: NetworkResultCode.RESULT_CODE_TRANSFER_RECIPIENT_BALANCE_OVERFLOW,
91
- TX_HASH_INVALID_FORMAT: NetworkResultCode.RESULT_CODE_TX_HASH_INVALID_FORMAT,
92
- INTERNAL_ENQUEUE_VALIDATION_FAILED: NetworkResultCode.RESULT_CODE_INTERNAL_ENQUEUE_VALIDATION_FAILED,
93
- TX_COMMITTED_RECEIPT_MISSING: NetworkResultCode.RESULT_CODE_TX_COMMITTED_RECEIPT_MISSING,
94
- VALIDATOR_RESPONSE_TX_TYPE_INVALID: NetworkResultCode.RESULT_CODE_VALIDATOR_RESPONSE_TX_TYPE_INVALID,
95
- VALIDATOR_RESPONSE_TX_TYPE_UNKNOWN: NetworkResultCode.RESULT_CODE_VALIDATOR_RESPONSE_TX_TYPE_UNKNOWN,
96
- VALIDATOR_RESPONSE_TX_TYPE_UNSUPPORTED: NetworkResultCode.RESULT_CODE_VALIDATOR_RESPONSE_TX_TYPE_UNSUPPORTED,
97
- VALIDATOR_RESPONSE_SCHEMA_INVALID: NetworkResultCode.RESULT_CODE_VALIDATOR_RESPONSE_SCHEMA_INVALID,
98
- PENDING_REQUEST_MISSING_TX_DATA: NetworkResultCode.RESULT_CODE_PENDING_REQUEST_MISSING_TX_DATA,
99
- PROOF_PAYLOAD_MISMATCH: NetworkResultCode.RESULT_CODE_PROOF_PAYLOAD_MISMATCH,
100
- VALIDATOR_WRITER_KEY_NOT_REGISTERED: NetworkResultCode.RESULT_CODE_VALIDATOR_WRITER_KEY_NOT_REGISTERED,
101
- VALIDATOR_ADDRESS_MISMATCH: NetworkResultCode.RESULT_CODE_VALIDATOR_ADDRESS_MISMATCH,
102
- VALIDATOR_NODE_ENTRY_NOT_FOUND: NetworkResultCode.RESULT_CODE_VALIDATOR_NODE_ENTRY_NOT_FOUND,
103
- VALIDATOR_NODE_NOT_WRITER: NetworkResultCode.RESULT_CODE_VALIDATOR_NODE_NOT_WRITER,
104
- VALIDATOR_WRITER_KEY_MISMATCH: NetworkResultCode.RESULT_CODE_VALIDATOR_WRITER_KEY_MISMATCH,
105
- VALIDATOR_TX_OBJECT_INVALID: NetworkResultCode.RESULT_CODE_VALIDATOR_TX_OBJECT_INVALID,
106
- VALIDATOR_VA_MISSING: NetworkResultCode.RESULT_CODE_VALIDATOR_VA_MISSING,
107
- TX_INVALID_PAYLOAD: NetworkResultCode.RESULT_CODE_TX_INVALID_PAYLOAD
61
+ export const ConsensusOperationType = Object.freeze({
62
+ UNSPECIFIED: ConsensusMessageType.MESSAGE_TYPE_UNSPECIFIED,
63
+ PROOF_PROPOSAL: ConsensusMessageType.MESSAGE_TYPE_PROOF_PROPOSAL,
64
+ PROOF_PROPOSAL_APPROVAL: ConsensusMessageType.MESSAGE_TYPE_PROOF_PROPOSAL_APPROVAL,
65
+ REQUEST: ConsensusMessageType.MESSAGE_TYPE_REQUEST,
66
+ REPLY: ConsensusMessageType.MESSAGE_TYPE_REPLY,
67
+ });
68
+
69
+ export const ConsensusResultCode = Object.freeze({
70
+ UNSPECIFIED: SharedResultCode.RESULT_CODE_UNSPECIFIED,
71
+ OK: SharedResultCode.RESULT_CODE_OK,
72
+ INVALID_PAYLOAD: SharedResultCode.RESULT_CODE_INVALID_PAYLOAD,
73
+ UNEXPECTED_ERROR: SharedResultCode.RESULT_CODE_UNEXPECTED_ERROR,
74
+ SCHEMA_VALIDATION_FAILED: SharedResultCode.RESULT_CODE_CONSENSUS_SCHEMA_VALIDATION_FAILED,
75
+ BAD_PROTOCOL_VERSION: SharedResultCode.RESULT_CODE_CONSENSUS_BAD_PROTOCOL_VERSION,
76
+ WRONG_NETWORK_ID: SharedResultCode.RESULT_CODE_CONSENSUS_WRONG_NETWORK_ID,
77
+ CONSENSUS_CONFIG_MISMATCH: SharedResultCode.RESULT_CODE_CONSENSUS_CONFIG_MISMATCH,
78
+ VDF_PROOF_INVALID: SharedResultCode.RESULT_CODE_CONSENSUS_VDF_PROOF_INVALID,
79
+ ADDRESS_INVALID: SharedResultCode.RESULT_CODE_CONSENSUS_ADDRESS_INVALID,
80
+ PUBLIC_KEY_MISMATCH: SharedResultCode.RESULT_CODE_CONSENSUS_PUBLIC_KEY_MISMATCH,
81
+ PROPOSAL_SIGNATURE_INVALID: SharedResultCode.RESULT_CODE_CONSENSUS_PROPOSAL_SIGNATURE_INVALID,
82
+ RESPONSE_SIGNATURE_INVALID: SharedResultCode.RESULT_CODE_CONSENSUS_RESPONSE_SIGNATURE_INVALID,
83
+ APPROVAL_SIGNATURE_INVALID: SharedResultCode.RESULT_CODE_CONSENSUS_APPROVAL_SIGNATURE_INVALID,
84
+ OPERATION_TYPE_INVALID: SharedResultCode.RESULT_CODE_CONSENSUS_OPERATION_TYPE_INVALID,
85
+ RESPONSE_APPROVAL_INVALID: SharedResultCode.RESULT_CODE_CONSENSUS_RESPONSE_APPROVAL_INVALID,
86
+ EPOCH_INVALID: SharedResultCode.RESULT_CODE_CONSENSUS_EPOCH_INVALID,
87
+ PREVIOUS_EPOCH_RECORD_HASH_INVALID: SharedResultCode.RESULT_CODE_CONSENSUS_PREVIOUS_EPOCH_RECORD_HASH_INVALID,
88
+ INDEXER_ROLE_INVALID: SharedResultCode.RESULT_CODE_CONSENSUS_INDEXER_ROLE_INVALID,
89
+ });
90
+
91
+ export const NetworkResultCode = Object.freeze({
92
+ UNSPECIFIED: SharedResultCode.RESULT_CODE_UNSPECIFIED,
93
+ OK: SharedResultCode.RESULT_CODE_OK,
94
+ INVALID_PAYLOAD: SharedResultCode.RESULT_CODE_INVALID_PAYLOAD,
95
+ RATE_LIMITED: SharedResultCode.RESULT_CODE_RATE_LIMITED,
96
+ SIGNATURE_INVALID: SharedResultCode.RESULT_CODE_SIGNATURE_INVALID,
97
+ UNEXPECTED_ERROR: SharedResultCode.RESULT_CODE_UNEXPECTED_ERROR,
98
+ TIMEOUT: SharedResultCode.RESULT_CODE_TIMEOUT,
99
+ NODE_HAS_NO_WRITE_ACCESS: SharedResultCode.RESULT_CODE_NODE_HAS_NO_WRITE_ACCESS,
100
+ TX_ACCEPTED_PROOF_UNAVAILABLE: SharedResultCode.RESULT_CODE_TX_ACCEPTED_PROOF_UNAVAILABLE,
101
+ NODE_OVERLOADED: SharedResultCode.RESULT_CODE_NODE_OVERLOADED,
102
+ TX_ALREADY_PENDING: SharedResultCode.RESULT_CODE_TX_ALREADY_PENDING,
103
+ OPERATION_TYPE_UNKNOWN: SharedResultCode.RESULT_CODE_OPERATION_TYPE_UNKNOWN,
104
+ SCHEMA_VALIDATION_FAILED: SharedResultCode.RESULT_CODE_SCHEMA_VALIDATION_FAILED,
105
+ REQUESTER_ADDRESS_INVALID: SharedResultCode.RESULT_CODE_REQUESTER_ADDRESS_INVALID,
106
+ REQUESTER_PUBLIC_KEY_INVALID: SharedResultCode.RESULT_CODE_REQUESTER_PUBLIC_KEY_INVALID,
107
+ TX_HASH_MISMATCH: SharedResultCode.RESULT_CODE_TX_HASH_MISMATCH,
108
+ TX_SIGNATURE_INVALID: SharedResultCode.RESULT_CODE_TX_SIGNATURE_INVALID,
109
+ TX_EXPIRED: SharedResultCode.RESULT_CODE_TX_EXPIRED,
110
+ TX_ALREADY_EXISTS: SharedResultCode.RESULT_CODE_TX_ALREADY_EXISTS,
111
+ OPERATION_ALREADY_COMPLETED: SharedResultCode.RESULT_CODE_OPERATION_ALREADY_COMPLETED,
112
+ REQUESTER_NOT_FOUND: SharedResultCode.RESULT_CODE_REQUESTER_NOT_FOUND,
113
+ INSUFFICIENT_FEE_BALANCE: SharedResultCode.RESULT_CODE_INSUFFICIENT_FEE_BALANCE,
114
+ EXTERNAL_BOOTSTRAP_EQUALS_MSB_BOOTSTRAP: SharedResultCode.RESULT_CODE_EXTERNAL_BOOTSTRAP_EQUALS_MSB_BOOTSTRAP,
115
+ SELF_VALIDATION_FORBIDDEN: SharedResultCode.RESULT_CODE_SELF_VALIDATION_FORBIDDEN,
116
+ ROLE_NODE_ENTRY_NOT_FOUND: SharedResultCode.RESULT_CODE_ROLE_NODE_ENTRY_NOT_FOUND,
117
+ ROLE_NODE_ALREADY_WRITER: SharedResultCode.RESULT_CODE_ROLE_NODE_ALREADY_WRITER,
118
+ ROLE_NODE_NOT_WHITELISTED: SharedResultCode.RESULT_CODE_ROLE_NODE_NOT_WHITELISTED,
119
+ ROLE_NODE_NOT_WRITER: SharedResultCode.RESULT_CODE_ROLE_NODE_NOT_WRITER,
120
+ ROLE_NODE_IS_INDEXER: SharedResultCode.RESULT_CODE_ROLE_NODE_IS_INDEXER,
121
+ ROLE_ADMIN_ENTRY_MISSING: SharedResultCode.RESULT_CODE_ROLE_ADMIN_ENTRY_MISSING,
122
+ ROLE_INVALID_RECOVERY_CASE: SharedResultCode.RESULT_CODE_ROLE_INVALID_RECOVERY_CASE,
123
+ ROLE_UNKNOWN_OPERATION: SharedResultCode.RESULT_CODE_ROLE_UNKNOWN_OPERATION,
124
+ ROLE_INVALID_WRITER_KEY: SharedResultCode.RESULT_CODE_ROLE_INVALID_WRITER_KEY,
125
+ ROLE_INSUFFICIENT_FEE_BALANCE: SharedResultCode.RESULT_CODE_ROLE_INSUFFICIENT_FEE_BALANCE,
126
+ MSB_BOOTSTRAP_MISMATCH: SharedResultCode.RESULT_CODE_MSB_BOOTSTRAP_MISMATCH,
127
+ EXTERNAL_BOOTSTRAP_NOT_DEPLOYED: SharedResultCode.RESULT_CODE_EXTERNAL_BOOTSTRAP_NOT_DEPLOYED,
128
+ EXTERNAL_BOOTSTRAP_TX_MISSING: SharedResultCode.RESULT_CODE_EXTERNAL_BOOTSTRAP_TX_MISSING,
129
+ EXTERNAL_BOOTSTRAP_MISMATCH: SharedResultCode.RESULT_CODE_EXTERNAL_BOOTSTRAP_MISMATCH,
130
+ BOOTSTRAP_ALREADY_EXISTS: SharedResultCode.RESULT_CODE_BOOTSTRAP_ALREADY_EXISTS,
131
+ TRANSFER_RECIPIENT_ADDRESS_INVALID: SharedResultCode.RESULT_CODE_TRANSFER_RECIPIENT_ADDRESS_INVALID,
132
+ TRANSFER_RECIPIENT_PUBLIC_KEY_INVALID: SharedResultCode.RESULT_CODE_TRANSFER_RECIPIENT_PUBLIC_KEY_INVALID,
133
+ TRANSFER_AMOUNT_TOO_LARGE: SharedResultCode.RESULT_CODE_TRANSFER_AMOUNT_TOO_LARGE,
134
+ TRANSFER_SENDER_NOT_FOUND: SharedResultCode.RESULT_CODE_TRANSFER_SENDER_NOT_FOUND,
135
+ TRANSFER_INSUFFICIENT_BALANCE: SharedResultCode.RESULT_CODE_TRANSFER_INSUFFICIENT_BALANCE,
136
+ TRANSFER_RECIPIENT_BALANCE_OVERFLOW: SharedResultCode.RESULT_CODE_TRANSFER_RECIPIENT_BALANCE_OVERFLOW,
137
+ TX_HASH_INVALID_FORMAT: SharedResultCode.RESULT_CODE_TX_HASH_INVALID_FORMAT,
138
+ INTERNAL_ENQUEUE_VALIDATION_FAILED: SharedResultCode.RESULT_CODE_INTERNAL_ENQUEUE_VALIDATION_FAILED,
139
+ TX_COMMITTED_RECEIPT_MISSING: SharedResultCode.RESULT_CODE_TX_COMMITTED_RECEIPT_MISSING,
140
+ VALIDATOR_RESPONSE_TX_TYPE_INVALID: SharedResultCode.RESULT_CODE_VALIDATOR_RESPONSE_TX_TYPE_INVALID,
141
+ VALIDATOR_RESPONSE_TX_TYPE_UNKNOWN: SharedResultCode.RESULT_CODE_VALIDATOR_RESPONSE_TX_TYPE_UNKNOWN,
142
+ VALIDATOR_RESPONSE_TX_TYPE_UNSUPPORTED: SharedResultCode.RESULT_CODE_VALIDATOR_RESPONSE_TX_TYPE_UNSUPPORTED,
143
+ VALIDATOR_RESPONSE_SCHEMA_INVALID: SharedResultCode.RESULT_CODE_VALIDATOR_RESPONSE_SCHEMA_INVALID,
144
+ PENDING_REQUEST_MISSING_TX_DATA: SharedResultCode.RESULT_CODE_PENDING_REQUEST_MISSING_TX_DATA,
145
+ PROOF_PAYLOAD_MISMATCH: SharedResultCode.RESULT_CODE_PROOF_PAYLOAD_MISMATCH,
146
+ VALIDATOR_WRITER_KEY_NOT_REGISTERED: SharedResultCode.RESULT_CODE_VALIDATOR_WRITER_KEY_NOT_REGISTERED,
147
+ VALIDATOR_ADDRESS_MISMATCH: SharedResultCode.RESULT_CODE_VALIDATOR_ADDRESS_MISMATCH,
148
+ VALIDATOR_NODE_ENTRY_NOT_FOUND: SharedResultCode.RESULT_CODE_VALIDATOR_NODE_ENTRY_NOT_FOUND,
149
+ VALIDATOR_NODE_NOT_WRITER: SharedResultCode.RESULT_CODE_VALIDATOR_NODE_NOT_WRITER,
150
+ VALIDATOR_WRITER_KEY_MISMATCH: SharedResultCode.RESULT_CODE_VALIDATOR_WRITER_KEY_MISMATCH,
151
+ VALIDATOR_TX_OBJECT_INVALID: SharedResultCode.RESULT_CODE_VALIDATOR_TX_OBJECT_INVALID,
152
+ VALIDATOR_VA_MISSING: SharedResultCode.RESULT_CODE_VALIDATOR_VA_MISSING,
153
+ TX_INVALID_PAYLOAD: SharedResultCode.RESULT_CODE_TX_INVALID_PAYLOAD
108
154
  });
109
155
 
156
+ // TODO: Refactor network code to use NetworkResultCode instead of "old" ResultCode
157
+ // Then, remove the line below
158
+ export const ResultCode = NetworkResultCode; // TO BE DEPRECATED
159
+
110
160
  // Role managment constants
111
161
  export const EventType = Object.freeze({
112
162
  WRITER_EVENT: 'writer-event',
@@ -115,15 +165,25 @@ export const EventType = Object.freeze({
115
165
  WRITABLE: 'writable',
116
166
  UNWRITABLE: 'unwritable',
117
167
  WARNING: 'warning',
118
- VALIDATOR_CONNECTION_READY: 'validator-connection-ready',
119
- VALIDATOR_CONNECTION_TIMEOUT: 'validator-connection-timeout',
120
168
  VALIDATOR_HEALTH_CHECK: 'validator-health-check',
121
169
  });
122
170
 
123
171
  // Role managment constants
124
172
  export const CustomEventType = Object.freeze({
125
173
  IS_INDEXER: 'msb:is-indexer',
126
- UNWRITABLE: 'msb:unwritable'
174
+ UNWRITABLE: 'msb:unwritable',
175
+ IS_NON_INDEXER: 'msb:is-non-indexer',
176
+ EPOCH_PROPOSAL_SUBMITTED: 'msb:epoch_proposal_submitted',
177
+ EPOCH_PROPOSAL_RECEIVED: 'msb:epoch_proposal_received',
178
+ EPOCH_PROPOSAL_VALIDATION_SUCCESS: 'msb:epoch_proposal_validation_success',
179
+ EPOCH_PROPOSAL_VALIDATION_FAILURE: 'msb:epoch_proposal_validation_failure',
180
+ EPOCH_PROPOSAL_APPROVAL_RECEIVED: 'msb:epoch_proposal_approval_received',
181
+ EPOCH_PROPOSAL_APPROVAL_SUCCESS: 'msb:epoch_proposal_approval_success',
182
+ EPOCH_PROPOSAL_APPROVAL_FAILURE: 'msb:epoch_proposal_approval_failure',
183
+ CONSENSUS_PEER_BAN_REQUESTED: 'msb:consensus_peer_ban_requested',
184
+ GENESIS_EPOCH_CREATED: 'msb:genesis_epoch_created',
185
+ EPOCH_CREATED: 'msb:epoch_created',
186
+ CONSENSUS_CONFIG_CHANGED: 'msb:consensus_config_changed'
127
187
  });
128
188
 
129
189
  // Token
@@ -144,19 +204,59 @@ export const ACK_INTERVAL = 1_000;
144
204
  export const AUTOBASE_VALUE_ENCODING = 'binary';
145
205
  export const HYPERBEE_KEY_ENCODING = 'ascii';
146
206
  export const HYPERBEE_VALUE_ENCODING = 'binary';
147
- // check.js
207
+ // StateValidationSchema.js
148
208
 
149
209
  //ATTENTION - THIS IS USED IN THE APPLY FUNCTION!
210
+ // Apply schema validation
211
+ export const PUBLIC_KEY_LENGTH = 32
150
212
  export const WRITER_BYTE_LENGTH = 32;
151
213
  export const BOOTSTRAP_BYTE_LENGTH = 32;
152
214
  export const CHANNEL_BYTE_LENGTH = 32;
153
215
  export const NONCE_BYTE_LENGTH = 32;
154
216
  export const HASH_BYTE_LENGTH = 32;
217
+ export const HTLC_LOCK_ID_BYTE_LENGTH = 32;
218
+ export const HTLC_PREIMAGE_BYTE_LENGTH = 32;
219
+ export const HTLC_THRESHOLD_BYTE_LENGTH = 1;
220
+ export const HTLC_METADATA_MAX_BYTE_LENGTH = 1024;
155
221
  export const BALANCE_BYTE_LENGTH = 16;
156
222
  export const SIGNATURE_BYTE_LENGTH = 64;
223
+ export const PEER_PUBLIC_KEY_HEX_LENGTH = 64;
157
224
  export const AMOUNT_BYTE_LENGTH = 16;
158
- export const MIN_SAFE_VALIDATION_INTEGER = 0x00000001;
159
- export const MAX_SAFE_VALIDATION_INTEGER = 0xFFFFFFFF;
225
+ export const UINT16_MAX = 0xFFFF;
226
+ export const UINT32_MAX = 0xFFFFFFFF;
227
+
228
+ // consensus
229
+ export const NETWORK_ID_BYTE_LENGTH = 2; // 2 BYTES - UINT16
230
+ export const EPOCH_BYTE_LENGTH = 8; // 8 BYTES - UINT64
231
+ // Peer hints advance the election clock by at most one step per message.
232
+ export const VDF_DIFFICULTY_SIZE = 4; // 4 BYTES - UINT32
233
+ export const VDF_DISCRIMINANT_SIZE = 2; // 2 BYTES - UINT16
234
+ export const MAX_VDF_DIFFICULTY = UINT32_MAX;
235
+ export const CONSENSUS_CONFIG_INDEX_SIZE = 4 // 4 BYTES - UINT32
236
+ export const CONSENSUS_CONFIG_SCHEMA_VERSION_BYTE_LENGTH = 1;
237
+ export const CONSENSUS_CONFIG_DATA_MAX_SIZE = 3072; // 3 KiB
238
+ export const SET_EPOCH_DATA_MAX_SIZE = 3072; // 3 KiB
239
+ export const VDF_PROOF_BYTE_LENGTHS = Object.freeze({
240
+ 1024: 260,
241
+ 2048: 516,
242
+ 4096: 1028
243
+ });
244
+ export const EPOCH_APPENDER_SELECTION_MAX_COUNTER = (1n << 64n) - 1n;
245
+ export const CONSENSUS_REQUEST_ID_MAX_LENGTH = 64;
246
+ export const CONSENSUS_SESSION_ID_MAX_LENGTH = 64;
247
+ export const HASH_HEX_LENGTH = HASH_BYTE_LENGTH * 2;
248
+ export const EPOCH_APPENDER_SELECTION_COUNTER_STEP = 1024n;
249
+ export const EPOCH_APPENDER_SELECTION_COUNTER_LIMIT = EPOCH_APPENDER_SELECTION_MAX_COUNTER - EPOCH_APPENDER_SELECTION_COUNTER_STEP;
250
+
251
+ // These permanent consensus IDs select the config, SET_EPOCH and genesis formats.
252
+ // Assign higher IDs to new versions; parameter updates retain the current ID.
253
+ export const ConsensusVersion = Object.freeze({
254
+ VDF_V1: 1,
255
+ });
256
+
257
+ // HTLC constants
258
+ export const HTLC_MAX_SIGNERS = 8;
259
+ export const HTLC_MIN_LOCK_DURATION_EPOCHS = 1n;
160
260
 
161
261
  export const LICENSE_BYTE_LENGTH = 4;
162
262
 
@@ -169,6 +269,7 @@ export const BATCH_SIZE = 10;
169
269
  // Operation handler constants
170
270
  export const MAX_PARTIAL_TX_PAYLOAD_BYTE_SIZE = 3072;
171
271
  export const V1_PROTOCOL_PAYLOAD_MAX_SIZE = 4096;
272
+ export const CONSENSUS_MESSAGE_MAX_BYTE_SIZE = 4096;
172
273
 
173
274
  // Transaction Commit Service
174
275
  export const TRANSACTION_COMMIT_SERVICE_BUFFER_SIZE = 1500;
@@ -1,7 +1,5 @@
1
1
  import b4a from "b4a";
2
2
  import tracCryptoApi from "trac-crypto-api";
3
- import {bufferToAddress} from "../core/state/utils/address.js";
4
- import { EntryType } from "./constants.js";
5
3
  import { v7 as uuidv7 } from 'uuid';
6
4
  //TODO: change file name or split functions below into multiple files (Remember to update imports and tests accordingly)
7
5
 
@@ -49,29 +47,6 @@ export const safeJsonParse = (str) => {
49
47
  return undefined;
50
48
  }
51
49
 
52
- export async function getFormattedIndexersWithAddresses(state, config) {
53
- const indexers = await state.getIndexersEntry();
54
- const formatted = indexers.map((entry) => ({
55
- writingKey: b4a.toString(entry.key, "hex"),
56
- }));
57
-
58
- const results = await Promise.all(
59
- formatted.map(async (entry) => {
60
- const address = bufferToAddress(
61
- await state.getSigned(EntryType.WRITER_ADDRESS + entry.writingKey),
62
- config.addressPrefix
63
- );
64
-
65
- return {
66
- ...entry,
67
- address,
68
- };
69
- })
70
- );
71
-
72
- return results;
73
- }
74
-
75
50
  export function formatIndexersEntry(indexersEntry, addressLength) {
76
51
 
77
52
  const count = indexersEntry[0];
@@ -0,0 +1,122 @@
1
+ import b4a from 'b4a';
2
+ import tracCryptoApi from 'trac-crypto-api';
3
+
4
+ import {createMessage, isZeroBuffer, uint8ToBuffer, uint32ToBuffer} from './buffer.js';
5
+ import {
6
+ AMOUNT_BYTE_LENGTH,
7
+ EPOCH_BYTE_LENGTH,
8
+ HASH_BYTE_LENGTH,
9
+ HTLC_MAX_SIGNERS,
10
+ HTLC_METADATA_MAX_BYTE_LENGTH,
11
+ HTLC_THRESHOLD_BYTE_LENGTH,
12
+ NONCE_BYTE_LENGTH,
13
+ OperationType,
14
+ PUBLIC_KEY_LENGTH,
15
+ UINT32_MAX,
16
+ } from './constants.js';
17
+
18
+ const EMPTY_METADATA = b4a.alloc(0);
19
+
20
+ function requireBuffer(value, length, field, allowZero = false) {
21
+ if (!b4a.isBuffer(value) || value.length !== length || (!allowZero && isZeroBuffer(value))) {
22
+ throw new Error(`${field} must be a${allowZero ? '' : ' non-zero'} ${length}-byte buffer.`);
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Creates the canonical message committed by every HTLC lock authorizer.
28
+ * Signatures and validator completion fields are intentionally excluded.
29
+ */
30
+ export function createHtlcLockSigningMessage(networkId, locker, operation) {
31
+ if (!Number.isInteger(networkId) || networkId < 1 || networkId > UINT32_MAX) {
32
+ throw new Error('HTLC network id must be an unsigned non-zero 32-bit integer.');
33
+ }
34
+ if (!operation || !Array.isArray(operation.ss)) {
35
+ throw new Error('HTLC lock operation and signer set are required.');
36
+ }
37
+ if (!b4a.isBuffer(locker) || locker.length === 0) {
38
+ throw new Error('HTLC locker must be a non-empty address buffer.');
39
+ }
40
+ if (operation.ss.length < 1 || operation.ss.length > HTLC_MAX_SIGNERS) {
41
+ throw new Error(`HTLC signer set must contain between 1 and ${HTLC_MAX_SIGNERS} public keys.`);
42
+ }
43
+
44
+ requireBuffer(operation.txv, HASH_BYTE_LENGTH, 'HTLC transaction validity');
45
+ requireBuffer(operation.ca, locker.length, 'HTLC claim address');
46
+ requireBuffer(operation.ra, locker.length, 'HTLC refund address');
47
+ requireBuffer(operation.am, AMOUNT_BYTE_LENGTH, 'HTLC amount');
48
+ requireBuffer(operation.fa, AMOUNT_BYTE_LENGTH, 'HTLC fee amount', true);
49
+ requireBuffer(operation.hl, HASH_BYTE_LENGTH, 'HTLC hashlock');
50
+ requireBuffer(operation.re, EPOCH_BYTE_LENGTH, 'HTLC refund epoch');
51
+ requireBuffer(operation.th, HTLC_THRESHOLD_BYTE_LENGTH, 'HTLC threshold');
52
+ requireBuffer(operation.in, NONCE_BYTE_LENGTH, 'HTLC nonce');
53
+ if (operation.fr !== undefined) requireBuffer(operation.fr, locker.length, 'HTLC fee recipient');
54
+ if (operation.md !== undefined && (
55
+ !b4a.isBuffer(operation.md) || operation.md.length === 0 || operation.md.length > HTLC_METADATA_MAX_BYTE_LENGTH
56
+ )) {
57
+ throw new Error(`HTLC metadata must be a buffer containing 1 to ${HTLC_METADATA_MAX_BYTE_LENGTH} bytes.`);
58
+ }
59
+
60
+ const feeIsZero = isZeroBuffer(operation.fa);
61
+ if (feeIsZero === (operation.fr !== undefined)) {
62
+ throw new Error('HTLC fee recipient must be present exactly when the fee amount is non-zero.');
63
+ }
64
+
65
+ const signerKeys = new Set();
66
+ for (let index = 0; index < operation.ss.length; index++) {
67
+ const signer = operation.ss[index];
68
+ requireBuffer(signer, PUBLIC_KEY_LENGTH, `HTLC signer ${index}`);
69
+ const signerHex = b4a.toString(signer, 'hex');
70
+ if (signerKeys.has(signerHex)) throw new Error('HTLC signer set must not contain duplicates.');
71
+ signerKeys.add(signerHex);
72
+ if (index > 1 && b4a.compare(operation.ss[index - 1], signer) >= 0) {
73
+ throw new Error('HTLC cosigner public keys must be sorted by raw bytes.');
74
+ }
75
+ }
76
+
77
+ const threshold = operation.th[0];
78
+ if (threshold < 1 || threshold > operation.ss.length) {
79
+ throw new Error('HTLC threshold must be between one and the signer-set size.');
80
+ }
81
+
82
+ return createMessage(
83
+ networkId,
84
+ locker,
85
+ operation.txv,
86
+ operation.ca,
87
+ operation.ra,
88
+ operation.am,
89
+ operation.fa,
90
+ operation.fr ?? b4a.alloc(locker.length),
91
+ operation.hl,
92
+ operation.re,
93
+ uint32ToBuffer(operation.md?.length ?? 0),
94
+ operation.md ?? EMPTY_METADATA,
95
+ uint8ToBuffer(operation.ss.length),
96
+ ...operation.ss,
97
+ operation.th,
98
+ operation.in,
99
+ OperationType.HTLC_LOCK
100
+ );
101
+ }
102
+
103
+ /**
104
+ * Match signatures to cosigner keys using Bitcoin-style forward-only scanning.
105
+ * Both arrays must be in signer-set order; omitted cosigners need no placeholder.
106
+ */
107
+ export function verifyOrderedHtlcCosignerSignatures(signatures, transactionHash, signerSet) {
108
+ if (!Array.isArray(signatures) || !Array.isArray(signerSet)) return false;
109
+
110
+ let signerIndex = 1;
111
+ for (const signature of signatures) {
112
+ let matched = false;
113
+ while (signerIndex < signerSet.length) {
114
+ matched = tracCryptoApi.signature.verify(signature, transactionHash, signerSet[signerIndex]);
115
+ signerIndex++;
116
+ if (matched) break;
117
+ }
118
+ if (!matched) return false;
119
+ }
120
+
121
+ return true;
122
+ }
@@ -1,25 +1,31 @@
1
1
  export class Logger {
2
2
  #config
3
+
3
4
  constructor(config) {
4
5
  this.#config = config;
5
6
  }
6
7
 
8
+ #format(message) {
9
+ const timestamp = this.#config.enableLogTimestamp ? `[${new Date().toISOString()}] ` : '';
10
+ return `${timestamp}${message}`;
11
+ }
12
+
7
13
  info(message) {
8
- console.log("i: " + message);
14
+ console.log(this.#format("i: " + message));
9
15
  }
10
16
 
11
17
  debug(message) {
12
18
  if (this.#config.debug) {
13
- console.debug("d: " + message);
19
+ console.debug(this.#format("d: " + message));
14
20
  }
15
21
  }
16
22
 
17
23
  error(message) {
18
- console.error("e: " + message);
24
+ console.error(this.#format("e: " + message));
19
25
  }
20
26
 
21
27
  warn(message) {
22
- console.warn("w: " + message);
28
+ console.warn(this.#format("w: " + message));
23
29
  }
24
30
 
25
31
  }
@@ -3,6 +3,7 @@ import { isAddressValid } from '../core/state/utils/address.js';
3
3
  import tracCryptoApi from 'trac-crypto-api';
4
4
  import b4a from 'b4a';
5
5
  import { ZERO_LICENSE } from '../core/state/utils/nodeEntry.js';
6
+ import { PUBLIC_KEY_LENGTH } from './constants.js';
6
7
 
7
8
  export async function validateAddressFromIncomingFile(stateInstance, config, address, adminEntry) {
8
9
  if (!isAddressValid(address, config.addressPrefix)) {
@@ -11,7 +12,7 @@ export async function validateAddressFromIncomingFile(stateInstance, config, add
11
12
 
12
13
  const publicKey = tracCryptoApi.address.decode(address);
13
14
 
14
- if (!publicKey || publicKey.length !== 32) {
15
+ if (!publicKey || publicKey.length !== PUBLIC_KEY_LENGTH) {
15
16
  throw new Error(`Invalid public key: '${address}'. Please ensure all addresses are valid.`);
16
17
  }
17
18
 
@@ -201,6 +201,107 @@ export function normalizeBootstrapDeploymentOperation(payload, config) {
201
201
  };
202
202
  }
203
203
 
204
+ /**
205
+ * Normalizes the payload for an HTLC lock operation.
206
+ *
207
+ * @param {Object} payload The raw payload for the HTLC lock operation.
208
+ * @param {object} config The environment configuration object.
209
+ * @returns {Object} A normalized payload with address converted to buffer and hex values normalized.
210
+ */
211
+ export function normalizeHtlcLockOperation(payload, config) {
212
+ if (!payload || typeof payload !== 'object' || !payload.hlo) {
213
+ throw new Error('Invalid payload for HTLC lock operation normalization.');
214
+ }
215
+ const { type, address, hlo } = payload;
216
+ if (
217
+ type !== OperationType.HTLC_LOCK ||
218
+ !address ||
219
+ !hlo.tx || !hlo.txv || !hlo.ca || !hlo.ra ||
220
+ !hlo.am || !hlo.fa || !hlo.hl || !hlo.re ||
221
+ !Array.isArray(hlo.ss) || !hlo.th || !Array.isArray(hlo.cs) ||
222
+ !hlo.in || !hlo.is
223
+ ) {
224
+ throw new Error('Missing required fields in HTLC lock operation payload.');
225
+ }
226
+
227
+ const normalizedHlo = {
228
+ tx: normalizeHex(hlo.tx),
229
+ txv: normalizeHex(hlo.txv),
230
+ ca: addressToBuffer(hlo.ca, config.addressPrefix),
231
+ ra: addressToBuffer(hlo.ra, config.addressPrefix),
232
+ am: normalizeHex(hlo.am),
233
+ fa: normalizeHex(hlo.fa),
234
+ hl: normalizeHex(hlo.hl),
235
+ re: normalizeHex(hlo.re),
236
+ ss: hlo.ss.map(normalizeHex),
237
+ th: normalizeHex(hlo.th),
238
+ cs: hlo.cs.map(normalizeHex),
239
+ in: normalizeHex(hlo.in),
240
+ is: normalizeHex(hlo.is)
241
+ };
242
+ if (hlo.fr !== undefined) normalizedHlo.fr = addressToBuffer(hlo.fr, config.addressPrefix);
243
+ if (hlo.md !== undefined) normalizedHlo.md = normalizeHex(hlo.md);
244
+
245
+ return {
246
+ type,
247
+ address: addressToBuffer(address, config.addressPrefix),
248
+ hlo: normalizedHlo
249
+ };
250
+ }
251
+
252
+ export function normalizeHtlcClaimOperation(payload, config) {
253
+ if (!payload || typeof payload !== 'object' || !payload.hco) {
254
+ throw new Error('Invalid payload for HTLC claim operation normalization.');
255
+ }
256
+ const {type, address, hco} = payload;
257
+ if (
258
+ type !== OperationType.HTLC_CLAIM ||
259
+ !address || !hco.tx || !hco.txv || !hco.li ||
260
+ !hco.pi || !hco.in || !hco.is
261
+ ) {
262
+ throw new Error('Missing required fields in HTLC claim operation payload.');
263
+ }
264
+
265
+ return {
266
+ type,
267
+ address: addressToBuffer(address, config.addressPrefix),
268
+ hco: {
269
+ tx: normalizeHex(hco.tx),
270
+ txv: normalizeHex(hco.txv),
271
+ li: normalizeHex(hco.li),
272
+ pi: normalizeHex(hco.pi),
273
+ in: normalizeHex(hco.in),
274
+ is: normalizeHex(hco.is)
275
+ }
276
+ };
277
+ }
278
+
279
+ export function normalizeHtlcRefundOperation(payload, config) {
280
+ if (!payload || typeof payload !== 'object' || !payload.hro) {
281
+ throw new Error('Invalid payload for HTLC refund operation normalization.');
282
+ }
283
+ const {type, address, hro} = payload;
284
+ if (
285
+ type !== OperationType.HTLC_REFUND ||
286
+ !address || !hro.tx || !hro.txv || !hro.li ||
287
+ !hro.in || !hro.is
288
+ ) {
289
+ throw new Error('Missing required fields in HTLC refund operation payload.');
290
+ }
291
+
292
+ return {
293
+ type,
294
+ address: addressToBuffer(address, config.addressPrefix),
295
+ hro: {
296
+ tx: normalizeHex(hro.tx),
297
+ txv: normalizeHex(hro.txv),
298
+ li: normalizeHex(hro.li),
299
+ in: normalizeHex(hro.in),
300
+ is: normalizeHex(hro.is)
301
+ }
302
+ };
303
+ }
304
+
204
305
  /**
205
306
  * Normalizes an incoming partial operation message based on its operation type.
206
307
  *
@@ -235,5 +336,17 @@ export function normalizeMessageByOperationType(message, config) {
235
336
  return normalizeTransferOperation(message, config);
236
337
  }
237
338
 
339
+ if (type === OperationType.HTLC_LOCK) {
340
+ return normalizeHtlcLockOperation(message, config);
341
+ }
342
+
343
+ if (type === OperationType.HTLC_CLAIM) {
344
+ return normalizeHtlcClaimOperation(message, config);
345
+ }
346
+
347
+ if (type === OperationType.HTLC_REFUND) {
348
+ return normalizeHtlcRefundOperation(message, config);
349
+ }
350
+
238
351
  throw new Error(`Unsupported operation type for normalization: ${type}`);
239
352
  }