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.
- package/.github/workflows/publish.yml +8 -16
- package/msb.mjs +13 -25
- package/package.json +8 -4
- package/proto/network.proto +74 -0
- package/rpc/{create_server.mjs → create_server.js} +4 -4
- package/rpc/{handlers.mjs → handlers.js} +7 -7
- package/rpc/routes/{index.mjs → index.js} +1 -1
- package/rpc/routes/{v1.mjs → v1.js} +1 -1
- package/rpc/rpc_server.js +10 -0
- package/rpc/rpc_services.js +48 -7
- package/rpc/utils/{helpers.mjs → helpers.js} +1 -1
- package/src/config/config.js +137 -0
- package/src/config/env.js +63 -0
- package/src/core/network/Network.js +133 -119
- package/src/core/network/identity/NetworkWalletFactory.js +5 -6
- package/src/core/network/protocols/LegacyProtocol.js +67 -0
- package/src/core/network/protocols/NetworkMessages.js +48 -0
- package/src/core/network/protocols/ProtocolInterface.js +31 -0
- package/src/core/network/protocols/ProtocolSession.js +59 -0
- package/src/core/network/protocols/V1Protocol.js +64 -0
- package/src/core/network/protocols/legacy/NetworkMessageRouter.js +84 -0
- package/src/core/network/protocols/legacy/handlers/GetRequestHandler.js +53 -0
- package/src/core/network/protocols/legacy/handlers/ResponseHandler.js +37 -0
- package/src/core/network/{messaging → protocols/legacy}/validators/ValidatorResponse.js +2 -2
- package/src/core/network/{messaging → protocols/legacy}/validators/base/BaseResponse.js +13 -6
- package/src/core/network/protocols/shared/handlers/RoleOperationHandler.js +88 -0
- package/src/core/network/protocols/shared/handlers/SubnetworkOperationHandler.js +93 -0
- package/src/core/network/protocols/shared/handlers/TransferOperationHandler.js +57 -0
- package/src/core/network/{messaging → protocols/shared}/handlers/base/BaseOperationHandler.js +21 -26
- package/src/core/network/{messaging → protocols/shared}/validators/PartialBootstrapDeployment.js +3 -3
- package/src/core/network/{messaging → protocols/shared}/validators/PartialRoleAccess.js +15 -12
- package/src/core/network/{messaging → protocols/shared}/validators/PartialTransaction.js +10 -11
- package/src/core/network/{messaging → protocols/shared}/validators/PartialTransfer.js +10 -7
- package/src/core/network/{messaging → protocols/shared}/validators/base/PartialOperation.js +40 -22
- package/src/core/network/protocols/v1/NetworkMessageRouter.js +15 -0
- package/src/core/network/services/ConnectionManager.js +13 -19
- package/src/core/network/services/MessageOrchestrator.js +10 -22
- package/src/core/network/services/TransactionPoolService.js +10 -10
- package/src/core/network/services/TransactionRateLimiterService.js +5 -3
- package/src/core/network/services/ValidatorObserverService.js +46 -21
- package/src/core/state/State.js +137 -141
- package/src/core/state/utils/address.js +18 -16
- package/src/core/state/utils/adminEntry.js +17 -16
- package/src/core/state/utils/deploymentEntry.js +15 -15
- package/src/core/state/utils/transaction.js +3 -95
- package/src/index.js +250 -325
- package/src/messages/network/v1/NetworkMessageBuilder.js +325 -0
- package/src/messages/network/v1/NetworkMessageDirector.js +137 -0
- package/src/messages/network/v1/networkMessageFactory.js +12 -0
- package/src/messages/state/ApplyStateMessageBuilder.js +661 -0
- package/src/messages/state/ApplyStateMessageDirector.js +516 -0
- package/src/messages/state/applyStateMessageFactory.js +12 -0
- package/src/utils/buffer.js +53 -1
- package/src/utils/check.js +21 -17
- package/src/utils/cli.js +0 -8
- package/src/utils/cliCommands.js +11 -11
- package/src/utils/constants.js +36 -24
- package/src/utils/fileUtils.js +1 -4
- package/src/utils/helpers.js +9 -20
- package/src/utils/migrationUtils.js +2 -2
- package/src/utils/normalizers.js +94 -11
- package/src/utils/protobuf/network.cjs +840 -0
- package/src/utils/protobuf/operationHelpers.js +10 -0
- package/tests/acceptance/v1/account/account.test.mjs +2 -2
- package/tests/acceptance/v1/balance/balance.test.mjs +1 -1
- package/tests/acceptance/v1/broadcast-transaction/broadcast-transaction.test.mjs +11 -2
- package/tests/acceptance/v1/rpc.test.mjs +10 -10
- package/tests/acceptance/v1/tx/tx.test.mjs +4 -2
- package/tests/acceptance/v1/tx-details/tx-details.test.mjs +7 -3
- package/tests/fixtures/check.fixtures.js +42 -42
- package/tests/fixtures/networkV1.fixtures.js +84 -0
- package/tests/fixtures/protobuf.fixtures.js +110 -26
- package/tests/helpers/StateNetworkFactory.js +3 -5
- package/tests/helpers/autobaseTestHelpers.js +1 -2
- package/tests/helpers/config.js +3 -0
- package/tests/helpers/setupApplyTests.js +113 -99
- package/tests/helpers/transactionPayloads.mjs +26 -12
- package/tests/unit/messages/messages.test.js +12 -0
- package/tests/unit/messages/network/NetworkMessageBuilder.test.js +276 -0
- package/tests/unit/messages/network/NetworkMessageDirector.test.js +203 -0
- package/tests/unit/messages/state/applyStateMessageBuilder.complete.test.js +521 -0
- package/tests/unit/messages/state/applyStateMessageBuilder.partial.test.js +233 -0
- package/tests/unit/network/ConnectionManager.test.js +10 -7
- package/tests/unit/network/NetworkWalletFactory.test.js +14 -14
- package/tests/unit/network/networkModule.test.js +3 -2
- package/tests/unit/state/apply/addAdmin/addAdminHappyPathScenario.js +10 -6
- package/tests/unit/state/apply/addAdmin/addAdminScenarioHelpers.js +11 -8
- package/tests/unit/state/apply/addAdmin/state.apply.addAdmin.test.js +11 -7
- package/tests/unit/state/apply/addIndexer/addIndexerScenarioHelpers.js +18 -20
- package/tests/unit/state/apply/addWriter/addWriterScenarioHelpers.js +57 -48
- package/tests/unit/state/apply/addWriter/addWriterValidatorRewardScenario.js +2 -1
- package/tests/unit/state/apply/adminRecovery/adminRecoveryScenarioHelpers.js +72 -57
- package/tests/unit/state/apply/adminRecovery/state.apply.adminRecovery.test.js +3 -7
- package/tests/unit/state/apply/appendWhitelist/appendWhitelistScenarioHelpers.js +12 -14
- package/tests/unit/state/apply/balanceInitialization/balanceInitializationScenarioHelpers.js +18 -13
- package/tests/unit/state/apply/balanceInitialization/nodeEntryBalanceUpdateFailureScenario.js +2 -1
- package/tests/unit/state/apply/banValidator/banValidatorBanAndReWhitelistScenario.js +2 -1
- package/tests/unit/state/apply/banValidator/banValidatorScenarioHelpers.js +27 -30
- package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentDuplicateRegistrationScenario.js +2 -1
- package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentScenarioHelpers.js +24 -21
- package/tests/unit/state/apply/common/access-control/adminConsistencyMismatchScenario.js +5 -4
- package/tests/unit/state/apply/common/access-control/adminPublicKeyDecodeFailureScenario.js +4 -3
- package/tests/unit/state/apply/common/balances/base/requesterBalanceScenarioBase.js +2 -1
- package/tests/unit/state/apply/common/commonScenarioHelper.js +16 -16
- package/tests/unit/state/apply/common/payload-structure/initializationDisabledScenario.js +10 -5
- package/tests/unit/state/apply/common/payload-structure/invalidHashValidationScenario.js +2 -2
- package/tests/unit/state/apply/common/requester/requesterNodeEntryBufferMissingScenario.js +2 -1
- package/tests/unit/state/apply/common/requester/requesterNodeEntryDecodeFailureScenario.js +2 -1
- package/tests/unit/state/apply/common/validatorConsistency/base/validatorConsistencyScenarioBase.js +2 -1
- package/tests/unit/state/apply/common/validatorEntryValidation/base/validatorEntryValidationScenarioBase.js +2 -1
- package/tests/unit/state/apply/disableInitialization/disableInitializationScenarioHelpers.js +16 -9
- package/tests/unit/state/apply/removeIndexer/removeIndexerScenarioHelpers.js +6 -5
- package/tests/unit/state/apply/removeWriter/removeWriterScenarioHelpers.js +23 -19
- package/tests/unit/state/apply/transfer/transferDoubleSpendAcrossValidatorsScenario.js +45 -36
- package/tests/unit/state/apply/transfer/transferScenarioHelpers.js +48 -45
- package/tests/unit/state/apply/txOperation/txOperationScenarioHelpers.js +32 -29
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeGuardScenarioFactory.js +2 -1
- package/tests/unit/state/stateModule.test.js +0 -1
- package/tests/unit/state/stateTestUtils.js +7 -3
- package/tests/unit/state/utils/address.test.js +3 -3
- package/tests/unit/state/utils/adminEntry.test.js +10 -9
- package/tests/unit/unit.test.js +1 -1
- package/tests/unit/utils/buffer/buffer.test.js +62 -1
- package/tests/unit/utils/check/adminControlOperation.test.js +3 -3
- package/tests/unit/utils/check/balanceInitializationOperation.test.js +2 -2
- package/tests/unit/utils/check/bootstrapDeploymentOperation.test.js +2 -3
- package/tests/unit/utils/check/common.test.js +7 -6
- package/tests/unit/utils/check/coreAdminOperation.test.js +3 -3
- package/tests/unit/utils/check/roleAccessOperation.test.js +3 -2
- package/tests/unit/utils/check/transactionOperation.test.js +3 -3
- package/tests/unit/utils/check/transferOperation.test.js +3 -3
- package/tests/unit/utils/fileUtils/readAddressesFromWhitelistFile.test.js +2 -1
- package/tests/unit/utils/fileUtils/readBalanceMigrationFile.test.js +2 -1
- package/tests/unit/utils/migrationUtils/validateAddressFromIncomingFile.test.js +7 -0
- package/tests/unit/utils/normalizers/normalizers.test.js +469 -0
- package/tests/unit/utils/protobuf/operationHelpers.test.js +120 -2
- package/tests/unit/utils/utils.test.js +0 -1
- package/rpc/rpc_server.mjs +0 -10
- package/src/core/network/messaging/NetworkMessages.js +0 -63
- package/src/core/network/messaging/handlers/GetRequestHandler.js +0 -112
- package/src/core/network/messaging/handlers/ResponseHandler.js +0 -108
- package/src/core/network/messaging/handlers/RoleOperationHandler.js +0 -116
- package/src/core/network/messaging/handlers/SubnetworkOperationHandler.js +0 -143
- package/src/core/network/messaging/handlers/TransferOperationHandler.js +0 -52
- package/src/core/network/messaging/routes/NetworkMessageRouter.js +0 -94
- package/src/core/network/messaging/validators/AdminResponse.js +0 -58
- package/src/core/network/messaging/validators/CustomNodeResponse.js +0 -46
- package/src/core/state/utils/indexerEntry.js +0 -105
- package/src/messages/base/StateBuilder.js +0 -25
- package/src/messages/completeStateMessages/CompleteStateMessageBuilder.js +0 -421
- package/src/messages/completeStateMessages/CompleteStateMessageDirector.js +0 -252
- package/src/messages/completeStateMessages/CompleteStateMessageOperations.js +0 -299
- package/src/messages/partialStateMessages/PartialStateMessageBuilder.js +0 -272
- package/src/messages/partialStateMessages/PartialStateMessageDirector.js +0 -137
- package/src/messages/partialStateMessages/PartialStateMessageOperations.js +0 -131
- package/src/utils/crypto.js +0 -11
- package/tests/integration/apply/addAdmin/addAdminBasic.test.js +0 -68
- package/tests/integration/apply/addAdmin/addAdminRecovery.test.js +0 -125
- package/tests/integration/apply/addIndexer.test.js +0 -237
- package/tests/integration/apply/addWhitelist.test.js +0 -53
- package/tests/integration/apply/addWriter.test.js +0 -244
- package/tests/integration/apply/apply.test.js +0 -19
- package/tests/integration/apply/banValidator.test.js +0 -109
- package/tests/integration/apply/postTx/invalidSubValues.test.js +0 -103
- package/tests/integration/apply/postTx/postTx.test.js +0 -222
- package/tests/integration/apply/removeIndexer.test.js +0 -128
- package/tests/integration/apply/removeWriter.test.js +0 -167
- package/tests/integration/apply/transfer.test.js +0 -81
- package/tests/integration/integration.test.js +0 -9
- package/tests/unit/messageOperations/assembleAddIndexerMessage.test.js +0 -21
- package/tests/unit/messageOperations/assembleAddWriterMessage.test.js +0 -16
- package/tests/unit/messageOperations/assembleAdminMessage.test.js +0 -69
- package/tests/unit/messageOperations/assembleBanWriterMessage.test.js +0 -16
- package/tests/unit/messageOperations/assemblePostTransaction.test.js +0 -442
- package/tests/unit/messageOperations/assembleRemoveIndexerMessage.test.js +0 -19
- package/tests/unit/messageOperations/assembleRemoveWriterMessage.test.js +0 -17
- package/tests/unit/messageOperations/assembleWhitelistMessages.test.js +0 -58
- package/tests/unit/messageOperations/commonsStateMessageOperationsTest.js +0 -277
- package/tests/unit/messageOperations/stateMessageOperations.test.js +0 -19
- package/tests/unit/state/utils/indexerEntry.test.js +0 -83
- package/tests/unit/state/utils/transaction.test.js +0 -97
- package/tests/unit/utils/crypto/createHash.test.js +0 -15
- /package/rpc/{constants.mjs → constants.js} +0 -0
- /package/rpc/{cors.mjs → cors.js} +0 -0
- /package/rpc/utils/{confirmedParameter.mjs → confirmedParameter.js} +0 -0
- /package/rpc/utils/{url.mjs → url.js} +0 -0
- /package/src/utils/{operations.js → applyOperations.js} +0 -0
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
import b4a from 'b4a';
|
|
2
|
+
import PeerWallet from 'trac-wallet';
|
|
3
|
+
|
|
4
|
+
import { createMessage } from '../../utils/buffer.js';
|
|
5
|
+
import { OperationType } from '../../utils/constants.js';
|
|
6
|
+
import { addressToBuffer, bufferToAddress } from '../../core/state/utils/address.js';
|
|
7
|
+
import { isAddressValid } from "../../core/state/utils/address.js";
|
|
8
|
+
import {
|
|
9
|
+
isAdminControl,
|
|
10
|
+
isBalanceInitialization,
|
|
11
|
+
isBootstrapDeployment,
|
|
12
|
+
isCoreAdmin,
|
|
13
|
+
isRoleAccess,
|
|
14
|
+
isTransaction,
|
|
15
|
+
isTransfer,
|
|
16
|
+
operationToPayload
|
|
17
|
+
} from '../../utils/applyOperations.js';
|
|
18
|
+
import { isHexString } from '../../utils/helpers.js';
|
|
19
|
+
|
|
20
|
+
// Single use per transaction: reuse of this instance needs mutex/queue or fail-fast and can delay validation or break validation rule.
|
|
21
|
+
// A fresh instance is effectively zero-cost, so no reset() is provided.
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Builder for partial/complete ApplyState messages.
|
|
25
|
+
* @param {PeerWallet} wallet
|
|
26
|
+
* @param {object} config
|
|
27
|
+
*/
|
|
28
|
+
class ApplyStateMessageBuilder {
|
|
29
|
+
#address;
|
|
30
|
+
#amount;
|
|
31
|
+
#channel;
|
|
32
|
+
#config
|
|
33
|
+
#contentHash;
|
|
34
|
+
#externalBootstrap;
|
|
35
|
+
#incomingAddress;
|
|
36
|
+
#incomingNonce;
|
|
37
|
+
#incomingSignature;
|
|
38
|
+
#incomingWriterKey;
|
|
39
|
+
#msbBootstrap;
|
|
40
|
+
#operationType;
|
|
41
|
+
#payload;
|
|
42
|
+
#txHash;
|
|
43
|
+
#txValidity;
|
|
44
|
+
#wallet;
|
|
45
|
+
#writingKey;
|
|
46
|
+
#phase;
|
|
47
|
+
#output;
|
|
48
|
+
#payloadKey;
|
|
49
|
+
#built=false;
|
|
50
|
+
|
|
51
|
+
constructor(wallet, config) {
|
|
52
|
+
this.#config = config;
|
|
53
|
+
if (!wallet || typeof wallet !== 'object') {
|
|
54
|
+
throw new Error('Wallet must be a valid wallet object');
|
|
55
|
+
}
|
|
56
|
+
if (!isAddressValid(wallet.address, this.#config.addressPrefix)) {
|
|
57
|
+
throw new Error('Wallet should have a valid TRAC address.');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.#wallet = wallet;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
setPhase(phase) {
|
|
64
|
+
if (!['partial', 'complete'].includes(phase)) {
|
|
65
|
+
throw new Error(`Invalid phase: ${phase}`);
|
|
66
|
+
}
|
|
67
|
+
this.#phase = phase;
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setOutput(output) {
|
|
72
|
+
if (!['json', 'buffer'].includes(output)) {
|
|
73
|
+
throw new Error(`Invalid output format: ${output}`);
|
|
74
|
+
}
|
|
75
|
+
this.#output = output;
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
setOperationType(operationType) {
|
|
80
|
+
if (!Object.values(OperationType).includes(operationType)) {
|
|
81
|
+
throw new Error(`Invalid operation type: ${operationType}`);
|
|
82
|
+
}
|
|
83
|
+
this.#operationType = operationType;
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
setAddress(address) {
|
|
88
|
+
const addressBuffer = this.#normalizeAddress(address);
|
|
89
|
+
if (!addressBuffer) {
|
|
90
|
+
throw new Error(`Address field must be a valid TRAC bech32m address with length ${this.#config.addressLength}.`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.#address = addressBuffer;
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
setWriterKey(writingKey) {
|
|
98
|
+
this.#writingKey = this.#normalizeHexBuffer(writingKey, 32, 'Writer key');
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
setTxHash(txHash) {
|
|
103
|
+
this.#txHash = this.#normalizeHexBuffer(txHash, 32, 'Transaction hash');
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
setIncomingAddress(address) {
|
|
108
|
+
const addressBuffer = this.#normalizeAddress(address);
|
|
109
|
+
if (!addressBuffer) {
|
|
110
|
+
throw new Error(`Address field must be a valid TRAC bech32m address with length ${this.#config.addressLength}.`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
this.#incomingAddress = addressBuffer;
|
|
114
|
+
return this;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
setIncomingWriterKey(writerKey) {
|
|
118
|
+
this.#incomingWriterKey = this.#normalizeHexBuffer(writerKey, 32, 'Incoming writer key');
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
setIncomingNonce(nonce) {
|
|
123
|
+
this.#incomingNonce = this.#normalizeHexBuffer(nonce, 32, 'Incoming nonce');
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
setContentHash(contentHash) {
|
|
128
|
+
this.#contentHash = this.#normalizeHexBuffer(contentHash, 32, 'Content hash');
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
setIncomingSignature(signature) {
|
|
133
|
+
this.#incomingSignature = this.#normalizeHexBuffer(signature, 64, 'Incoming signature');
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
setExternalBootstrap(bootstrapKey) {
|
|
138
|
+
this.#externalBootstrap = this.#normalizeHexBuffer(bootstrapKey, 32, 'Bootstrap key');
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
setMsbBootstrap(msbBootstrap) {
|
|
143
|
+
this.#msbBootstrap = this.#normalizeHexBuffer(msbBootstrap, 32, 'MSB bootstrap');
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
setChannel(channel) {
|
|
148
|
+
this.#channel = this.#normalizeHexBuffer(channel, 32, 'Channel');
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
setTxValidity(txValidity) {
|
|
153
|
+
this.#txValidity = this.#normalizeHexBuffer(txValidity, 32, 'Transaction validity');
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
setAmount(amount) {
|
|
158
|
+
this.#amount = this.#normalizeHexBuffer(amount, 16, 'Amount');
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
#requireFields(fields) {
|
|
163
|
+
for (const [value, name] of fields) {
|
|
164
|
+
if (!value) {
|
|
165
|
+
throw new Error(`${name} must be set before build.`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async build() {
|
|
171
|
+
this.#assertPhaseAndOutput();
|
|
172
|
+
|
|
173
|
+
if (!this.#operationType) {
|
|
174
|
+
throw new Error('Operation type must be set before build.');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!this.#address) {
|
|
178
|
+
throw new Error('Address must be set before build.');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const payloadKey = operationToPayload(this.#operationType);
|
|
182
|
+
if (!payloadKey) {
|
|
183
|
+
throw new Error(`Unsupported operation type: ${this.#operationType}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let body;
|
|
187
|
+
if (this.#phase === 'partial') {
|
|
188
|
+
body = await this.#buildPartialBody();
|
|
189
|
+
} else {
|
|
190
|
+
body = await this.#buildCompleteBody();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
this.#payloadKey = payloadKey;
|
|
194
|
+
this.#payload = {
|
|
195
|
+
type: this.#operationType,
|
|
196
|
+
address: this.#address,
|
|
197
|
+
[payloadKey]: body
|
|
198
|
+
};
|
|
199
|
+
this.#built = true;
|
|
200
|
+
return this;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
getPayload() {
|
|
204
|
+
if (!this.#built || !this.#payload) {
|
|
205
|
+
throw new Error('Payload has not been built.');
|
|
206
|
+
}
|
|
207
|
+
return this.#output === 'json' ? this.#encodePayloadJson(this.#payload) : this.#payload;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
#assertPhaseAndOutput() {
|
|
211
|
+
if (!this.#phase) {
|
|
212
|
+
throw new Error('Phase must be set before build.');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (!this.#output) {
|
|
216
|
+
throw new Error('Output format must be set before build.');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// We assume that complete phase only supports buffer output. So this check will be enforced
|
|
220
|
+
if (this.#phase === 'complete' && this.#output !== 'buffer') {
|
|
221
|
+
throw new Error('Complete phase only supports buffer output.');
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
#normalizeHexBuffer(value, expectedBytes, fieldName) {
|
|
226
|
+
// with normalizer built in builder, we can remove other normalizers later.
|
|
227
|
+
if (b4a.isBuffer(value)) {
|
|
228
|
+
if (value.length !== expectedBytes) {
|
|
229
|
+
throw new Error(`${fieldName} must be a ${expectedBytes}-byte buffer.`);
|
|
230
|
+
}
|
|
231
|
+
return value;
|
|
232
|
+
}
|
|
233
|
+
if (typeof value === 'string') {
|
|
234
|
+
const expectedLength = expectedBytes * 2;
|
|
235
|
+
if (!isHexString(value) || value.length !== expectedLength) {
|
|
236
|
+
throw new Error(`${fieldName} must be a ${expectedLength}-length hexstring.`);
|
|
237
|
+
}
|
|
238
|
+
return b4a.from(value, 'hex');
|
|
239
|
+
}
|
|
240
|
+
throw new Error(`${fieldName} must be a ${expectedBytes}-byte buffer or ${expectedBytes * 2}-length hexstring.`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
#normalizeAddress(address) {
|
|
244
|
+
if (b4a.isBuffer(address)) {
|
|
245
|
+
const addr = bufferToAddress(address, this.#config.addressPrefix);
|
|
246
|
+
return addr ? address : null;
|
|
247
|
+
}
|
|
248
|
+
if (!isAddressValid(address, this.#config.addressPrefix)) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
return addressToBuffer(address, this.#config.addressPrefix);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async #buildPartialBody() {
|
|
255
|
+
if (!isRoleAccess(this.#operationType) && !isTransaction(this.#operationType) &&
|
|
256
|
+
!isBootstrapDeployment(this.#operationType) && !isTransfer(this.#operationType)) {
|
|
257
|
+
throw new Error(`Operation type ${this.#operationType} is not supported for partial build.`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const nonce = PeerWallet.generateNonce();
|
|
261
|
+
let msg;
|
|
262
|
+
|
|
263
|
+
switch (this.#operationType) {
|
|
264
|
+
case OperationType.ADD_WRITER:
|
|
265
|
+
case OperationType.REMOVE_WRITER:
|
|
266
|
+
case OperationType.ADMIN_RECOVERY:
|
|
267
|
+
this.#requireFields([
|
|
268
|
+
[this.#txValidity, 'Transaction validity'],
|
|
269
|
+
[this.#writingKey, 'Writer key']
|
|
270
|
+
]);
|
|
271
|
+
msg = createMessage(
|
|
272
|
+
this.#config.networkId,
|
|
273
|
+
this.#txValidity,
|
|
274
|
+
this.#writingKey,
|
|
275
|
+
nonce,
|
|
276
|
+
this.#operationType
|
|
277
|
+
);
|
|
278
|
+
break;
|
|
279
|
+
case OperationType.BOOTSTRAP_DEPLOYMENT:
|
|
280
|
+
this.#requireFields([
|
|
281
|
+
[this.#txValidity, 'Transaction validity'],
|
|
282
|
+
[this.#externalBootstrap, 'External bootstrap'],
|
|
283
|
+
[this.#channel, 'Channel']
|
|
284
|
+
]);
|
|
285
|
+
msg = createMessage(
|
|
286
|
+
this.#config.networkId,
|
|
287
|
+
this.#txValidity,
|
|
288
|
+
this.#externalBootstrap,
|
|
289
|
+
this.#channel,
|
|
290
|
+
nonce,
|
|
291
|
+
OperationType.BOOTSTRAP_DEPLOYMENT
|
|
292
|
+
);
|
|
293
|
+
break;
|
|
294
|
+
case OperationType.TX:
|
|
295
|
+
this.#requireFields([
|
|
296
|
+
[this.#txValidity, 'Transaction validity'],
|
|
297
|
+
[this.#writingKey, 'Writer key'],
|
|
298
|
+
[this.#contentHash, 'Content hash'],
|
|
299
|
+
[this.#externalBootstrap, 'External bootstrap'],
|
|
300
|
+
[this.#msbBootstrap, 'MSB bootstrap']
|
|
301
|
+
]);
|
|
302
|
+
msg = createMessage(
|
|
303
|
+
this.#config.networkId,
|
|
304
|
+
this.#txValidity,
|
|
305
|
+
this.#writingKey,
|
|
306
|
+
this.#contentHash,
|
|
307
|
+
this.#externalBootstrap,
|
|
308
|
+
this.#msbBootstrap,
|
|
309
|
+
nonce,
|
|
310
|
+
OperationType.TX
|
|
311
|
+
);
|
|
312
|
+
break;
|
|
313
|
+
case OperationType.TRANSFER:
|
|
314
|
+
this.#requireFields([
|
|
315
|
+
[this.#txValidity, 'Transaction validity'],
|
|
316
|
+
[this.#incomingAddress, 'Incoming address'],
|
|
317
|
+
[this.#amount, 'Amount']
|
|
318
|
+
]);
|
|
319
|
+
msg = createMessage(
|
|
320
|
+
this.#config.networkId,
|
|
321
|
+
this.#txValidity,
|
|
322
|
+
this.#incomingAddress,
|
|
323
|
+
this.#amount,
|
|
324
|
+
nonce,
|
|
325
|
+
OperationType.TRANSFER
|
|
326
|
+
);
|
|
327
|
+
break;
|
|
328
|
+
default:
|
|
329
|
+
throw new Error(`Unsupported operation type: ${this.#operationType}`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const tx = await PeerWallet.blake3(msg);
|
|
333
|
+
const signature = this.#wallet.sign(tx);
|
|
334
|
+
|
|
335
|
+
if (isBootstrapDeployment(this.#operationType)) {
|
|
336
|
+
return {
|
|
337
|
+
tx,
|
|
338
|
+
txv: this.#txValidity,
|
|
339
|
+
bs: this.#externalBootstrap,
|
|
340
|
+
ic: this.#channel,
|
|
341
|
+
in: nonce,
|
|
342
|
+
is: signature
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
if (isRoleAccess(this.#operationType)) {
|
|
346
|
+
return {
|
|
347
|
+
tx,
|
|
348
|
+
txv: this.#txValidity,
|
|
349
|
+
iw: this.#writingKey,
|
|
350
|
+
in: nonce,
|
|
351
|
+
is: signature
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
if (isTransaction(this.#operationType)) {
|
|
355
|
+
return {
|
|
356
|
+
tx,
|
|
357
|
+
txv: this.#txValidity,
|
|
358
|
+
iw: this.#writingKey,
|
|
359
|
+
ch: this.#contentHash,
|
|
360
|
+
bs: this.#externalBootstrap,
|
|
361
|
+
mbs: this.#msbBootstrap,
|
|
362
|
+
in: nonce,
|
|
363
|
+
is: signature,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
if (isTransfer(this.#operationType)) {
|
|
367
|
+
return {
|
|
368
|
+
tx,
|
|
369
|
+
txv: this.#txValidity,
|
|
370
|
+
to: this.#incomingAddress,
|
|
371
|
+
am: this.#amount,
|
|
372
|
+
in: nonce,
|
|
373
|
+
is: signature
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
throw new Error(`No corresponding value type for operation: ${this.#operationType}`);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async #buildCompleteBody() {
|
|
381
|
+
const nonce = PeerWallet.generateNonce();
|
|
382
|
+
let msg;
|
|
383
|
+
|
|
384
|
+
switch (this.#operationType) {
|
|
385
|
+
case OperationType.ADD_ADMIN:
|
|
386
|
+
case OperationType.DISABLE_INITIALIZATION:
|
|
387
|
+
this.#requireFields([
|
|
388
|
+
[this.#txValidity, 'Transaction validity'],
|
|
389
|
+
[this.#writingKey, 'Writer key']
|
|
390
|
+
]);
|
|
391
|
+
msg = createMessage(
|
|
392
|
+
this.#config.networkId,
|
|
393
|
+
this.#txValidity,
|
|
394
|
+
this.#writingKey,
|
|
395
|
+
nonce,
|
|
396
|
+
this.#operationType
|
|
397
|
+
);
|
|
398
|
+
break;
|
|
399
|
+
case OperationType.BALANCE_INITIALIZATION:
|
|
400
|
+
this.#requireFields([
|
|
401
|
+
[this.#txValidity, 'Transaction validity'],
|
|
402
|
+
[this.#incomingAddress, 'Incoming address'],
|
|
403
|
+
[this.#amount, 'Amount']
|
|
404
|
+
]);
|
|
405
|
+
msg = createMessage(
|
|
406
|
+
this.#config.networkId,
|
|
407
|
+
this.#txValidity,
|
|
408
|
+
this.#incomingAddress,
|
|
409
|
+
this.#amount,
|
|
410
|
+
nonce,
|
|
411
|
+
this.#operationType
|
|
412
|
+
);
|
|
413
|
+
break;
|
|
414
|
+
case OperationType.APPEND_WHITELIST:
|
|
415
|
+
case OperationType.ADD_INDEXER:
|
|
416
|
+
case OperationType.REMOVE_INDEXER:
|
|
417
|
+
case OperationType.BAN_VALIDATOR: {
|
|
418
|
+
this.#requireFields([
|
|
419
|
+
[this.#txValidity, 'Transaction validity'],
|
|
420
|
+
[this.#incomingAddress, 'Incoming address']
|
|
421
|
+
]);
|
|
422
|
+
const incomingAddress = bufferToAddress(this.#incomingAddress, this.#config.addressPrefix);
|
|
423
|
+
if (incomingAddress && this.#wallet.address === incomingAddress) {
|
|
424
|
+
throw new Error('Address must not be the same as the wallet address for basic operations.');
|
|
425
|
+
}
|
|
426
|
+
msg = createMessage(
|
|
427
|
+
this.#config.networkId,
|
|
428
|
+
this.#txValidity,
|
|
429
|
+
this.#incomingAddress,
|
|
430
|
+
nonce,
|
|
431
|
+
this.#operationType
|
|
432
|
+
);
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
case OperationType.ADD_WRITER:
|
|
436
|
+
case OperationType.REMOVE_WRITER:
|
|
437
|
+
case OperationType.ADMIN_RECOVERY:
|
|
438
|
+
this.#requireFields([
|
|
439
|
+
[this.#txHash, 'Transaction hash'],
|
|
440
|
+
[this.#txValidity, 'Transaction validity'],
|
|
441
|
+
[this.#incomingWriterKey, 'Incoming writer key'],
|
|
442
|
+
[this.#incomingNonce, 'Incoming nonce'],
|
|
443
|
+
[this.#incomingSignature, 'Incoming signature']
|
|
444
|
+
]);
|
|
445
|
+
msg = createMessage(
|
|
446
|
+
this.#config.networkId,
|
|
447
|
+
this.#txHash,
|
|
448
|
+
nonce,
|
|
449
|
+
this.#operationType
|
|
450
|
+
);
|
|
451
|
+
break;
|
|
452
|
+
case OperationType.BOOTSTRAP_DEPLOYMENT:
|
|
453
|
+
this.#requireFields([
|
|
454
|
+
[this.#txHash, 'Transaction hash'],
|
|
455
|
+
[this.#txValidity, 'Transaction validity'],
|
|
456
|
+
[this.#externalBootstrap, 'External bootstrap'],
|
|
457
|
+
[this.#channel, 'Channel'],
|
|
458
|
+
[this.#incomingNonce, 'Incoming nonce'],
|
|
459
|
+
[this.#incomingSignature, 'Incoming signature']
|
|
460
|
+
]);
|
|
461
|
+
msg = createMessage(
|
|
462
|
+
this.#config.networkId,
|
|
463
|
+
this.#txHash,
|
|
464
|
+
nonce,
|
|
465
|
+
this.#operationType
|
|
466
|
+
);
|
|
467
|
+
break;
|
|
468
|
+
case OperationType.TX:
|
|
469
|
+
this.#requireFields([
|
|
470
|
+
[this.#txHash, 'Transaction hash'],
|
|
471
|
+
[this.#txValidity, 'Transaction validity'],
|
|
472
|
+
[this.#incomingWriterKey, 'Incoming writer key'],
|
|
473
|
+
[this.#incomingNonce, 'Incoming nonce'],
|
|
474
|
+
[this.#incomingSignature, 'Incoming signature'],
|
|
475
|
+
[this.#contentHash, 'Content hash'],
|
|
476
|
+
[this.#externalBootstrap, 'External bootstrap'],
|
|
477
|
+
[this.#msbBootstrap, 'MSB bootstrap']
|
|
478
|
+
]);
|
|
479
|
+
msg = createMessage(
|
|
480
|
+
this.#config.networkId,
|
|
481
|
+
this.#txHash,
|
|
482
|
+
nonce,
|
|
483
|
+
this.#operationType
|
|
484
|
+
);
|
|
485
|
+
break;
|
|
486
|
+
case OperationType.TRANSFER:
|
|
487
|
+
this.#requireFields([
|
|
488
|
+
[this.#txHash, 'Transaction hash'],
|
|
489
|
+
[this.#txValidity, 'Transaction validity'],
|
|
490
|
+
[this.#incomingAddress, 'Incoming address'],
|
|
491
|
+
[this.#amount, 'Amount'],
|
|
492
|
+
[this.#incomingNonce, 'Incoming nonce'],
|
|
493
|
+
[this.#incomingSignature, 'Incoming signature']
|
|
494
|
+
]);
|
|
495
|
+
msg = createMessage(
|
|
496
|
+
this.#config.networkId,
|
|
497
|
+
this.#txHash,
|
|
498
|
+
nonce,
|
|
499
|
+
this.#operationType
|
|
500
|
+
);
|
|
501
|
+
break;
|
|
502
|
+
default:
|
|
503
|
+
throw new Error(`Unsupported operation type: ${this.#operationType}`);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const tx = await PeerWallet.blake3(msg);
|
|
507
|
+
const signature = this.#wallet.sign(tx);
|
|
508
|
+
const validatorAddress = addressToBuffer(this.#wallet.address, this.#config.addressPrefix);
|
|
509
|
+
|
|
510
|
+
if (isCoreAdmin(this.#operationType)) {
|
|
511
|
+
return {
|
|
512
|
+
tx,
|
|
513
|
+
txv: this.#txValidity,
|
|
514
|
+
iw: this.#writingKey,
|
|
515
|
+
in: nonce,
|
|
516
|
+
is: signature
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
if (isAdminControl(this.#operationType)) {
|
|
520
|
+
return {
|
|
521
|
+
tx,
|
|
522
|
+
txv: this.#txValidity,
|
|
523
|
+
ia: this.#incomingAddress,
|
|
524
|
+
in: nonce,
|
|
525
|
+
is: signature
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
if (isRoleAccess(this.#operationType)) {
|
|
529
|
+
return {
|
|
530
|
+
tx: this.#txHash,
|
|
531
|
+
txv: this.#txValidity,
|
|
532
|
+
iw: this.#incomingWriterKey,
|
|
533
|
+
in: this.#incomingNonce,
|
|
534
|
+
is: this.#incomingSignature,
|
|
535
|
+
va: validatorAddress,
|
|
536
|
+
vn: nonce,
|
|
537
|
+
vs: signature,
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
if (isTransaction(this.#operationType)) {
|
|
541
|
+
return {
|
|
542
|
+
tx: this.#txHash,
|
|
543
|
+
txv: this.#txValidity,
|
|
544
|
+
iw: this.#incomingWriterKey,
|
|
545
|
+
ch: this.#contentHash,
|
|
546
|
+
bs: this.#externalBootstrap,
|
|
547
|
+
mbs: this.#msbBootstrap,
|
|
548
|
+
in: this.#incomingNonce,
|
|
549
|
+
is: this.#incomingSignature,
|
|
550
|
+
va: validatorAddress,
|
|
551
|
+
vn: nonce,
|
|
552
|
+
vs: signature,
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
if (isBootstrapDeployment(this.#operationType)) {
|
|
556
|
+
return {
|
|
557
|
+
tx: this.#txHash,
|
|
558
|
+
txv: this.#txValidity,
|
|
559
|
+
bs: this.#externalBootstrap,
|
|
560
|
+
ic: this.#channel,
|
|
561
|
+
in: this.#incomingNonce,
|
|
562
|
+
is: this.#incomingSignature,
|
|
563
|
+
va: validatorAddress,
|
|
564
|
+
vn: nonce,
|
|
565
|
+
vs: signature
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
if (isTransfer(this.#operationType)) {
|
|
569
|
+
return {
|
|
570
|
+
tx: this.#txHash,
|
|
571
|
+
txv: this.#txValidity,
|
|
572
|
+
to: this.#incomingAddress,
|
|
573
|
+
am: this.#amount,
|
|
574
|
+
in: this.#incomingNonce,
|
|
575
|
+
is: this.#incomingSignature,
|
|
576
|
+
va: validatorAddress,
|
|
577
|
+
vn: nonce,
|
|
578
|
+
vs: signature
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
if (isBalanceInitialization(this.#operationType)) {
|
|
582
|
+
return {
|
|
583
|
+
tx,
|
|
584
|
+
txv: this.#txValidity,
|
|
585
|
+
ia: this.#incomingAddress,
|
|
586
|
+
am: this.#amount,
|
|
587
|
+
in: nonce,
|
|
588
|
+
is: signature
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
throw new Error(`No corresponding value type for operation: ${this.#operationType}`);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
#encodePayloadJson(payload) {
|
|
596
|
+
const toHex = buffer => buffer.toString('hex');
|
|
597
|
+
const address = bufferToAddress(payload.address, this.#config.addressPrefix);
|
|
598
|
+
if (!address) {
|
|
599
|
+
throw new Error('Payload address is invalid.');
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const body = payload[this.#payloadKey];
|
|
603
|
+
const base = { type: payload.type, address };
|
|
604
|
+
|
|
605
|
+
switch (this.#payloadKey) {
|
|
606
|
+
case 'rao':
|
|
607
|
+
return {
|
|
608
|
+
...base,
|
|
609
|
+
rao: {
|
|
610
|
+
tx: toHex(body.tx),
|
|
611
|
+
txv: toHex(body.txv),
|
|
612
|
+
iw: toHex(body.iw),
|
|
613
|
+
in: toHex(body.in),
|
|
614
|
+
is: toHex(body.is)
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
case 'txo':
|
|
618
|
+
return {
|
|
619
|
+
...base,
|
|
620
|
+
txo: {
|
|
621
|
+
tx: toHex(body.tx),
|
|
622
|
+
txv: toHex(body.txv),
|
|
623
|
+
iw: toHex(body.iw),
|
|
624
|
+
ch: toHex(body.ch),
|
|
625
|
+
bs: toHex(body.bs),
|
|
626
|
+
mbs: toHex(body.mbs),
|
|
627
|
+
in: toHex(body.in),
|
|
628
|
+
is: toHex(body.is)
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
case 'bdo':
|
|
632
|
+
return {
|
|
633
|
+
...base,
|
|
634
|
+
bdo: {
|
|
635
|
+
tx: toHex(body.tx),
|
|
636
|
+
txv: toHex(body.txv),
|
|
637
|
+
bs: toHex(body.bs),
|
|
638
|
+
ic: toHex(body.ic),
|
|
639
|
+
in: toHex(body.in),
|
|
640
|
+
is: toHex(body.is)
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
case 'tro':
|
|
644
|
+
return {
|
|
645
|
+
...base,
|
|
646
|
+
tro: {
|
|
647
|
+
tx: toHex(body.tx),
|
|
648
|
+
txv: toHex(body.txv),
|
|
649
|
+
to: bufferToAddress(body.to, this.#config.addressPrefix),
|
|
650
|
+
am: toHex(body.am),
|
|
651
|
+
in: toHex(body.in),
|
|
652
|
+
is: toHex(body.is)
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
default:
|
|
656
|
+
throw new Error(`JSON output is not supported for payload ${this.#payloadKey}.`);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
export default ApplyStateMessageBuilder;
|