bulletin-deploy 0.7.21 → 0.7.22-rc.0
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/dist/bug-report.js +4 -4
- package/dist/{chunk-2VNGK2MU.js → chunk-3LGLMHQI.js} +26 -3
- package/dist/{chunk-VTTN4BX7.js → chunk-4YO5SOAY.js} +151 -2
- package/dist/chunk-74ETPOKH.js +284 -0
- package/dist/chunk-A5IQ5MKO.js +207 -0
- package/dist/chunk-EJ5TNGAY.js +24 -0
- package/dist/{chunk-BFXHVC23.js → chunk-HEUS42MX.js} +21 -17
- package/dist/{chunk-ZY6QLNKQ.js → chunk-KTOZL74I.js} +1 -1
- package/dist/{chunk-MJTQOXBC.js → chunk-LEYQOOWC.js} +3 -2
- package/dist/{chunk-G2P5UIPX.js → chunk-LZO2QX4T.js} +4 -3
- package/dist/chunk-QHOZEY5X.js +231 -0
- package/dist/{chunk-RJAFD4LO.js → chunk-SL7LV4DS.js} +1 -1
- package/dist/chunk-T7EEVWNU.js +32 -0
- package/dist/{chunk-SA37SLYF.js → chunk-TA3NCL6U.js} +2 -2
- package/dist/chunk-UPWEOGLQ.js +37 -0
- package/dist/{chunk-4TS6R26J.js → chunk-WVCIU6WM.js} +22 -9
- package/dist/chunk-ZYVGHDMU.js +117 -0
- package/dist/chunk-probe.js +3 -3
- package/dist/deploy.d.ts +4 -2
- package/dist/deploy.js +9 -9
- package/dist/dotns.d.ts +74 -1
- package/dist/dotns.js +8 -4
- package/dist/incremental-stats.d.ts +3 -1
- package/dist/incremental-stats.js +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +9 -9
- package/dist/memory-report.js +2 -2
- package/dist/merkle.js +9 -9
- package/dist/personhood/bind-paid-alias.d.ts +43 -0
- package/dist/personhood/bind-paid-alias.js +10 -0
- package/dist/personhood/bind-personal-id.d.ts +55 -0
- package/dist/personhood/bind-personal-id.js +12 -0
- package/dist/personhood/bootstrap.d.ts +85 -0
- package/dist/personhood/bootstrap.js +245 -0
- package/dist/personhood/claim-pgas.d.ts +61 -0
- package/dist/personhood/claim-pgas.js +12 -0
- package/dist/personhood/constants.d.ts +23 -0
- package/dist/personhood/constants.js +22 -0
- package/dist/personhood/encoding.d.ts +49 -0
- package/dist/personhood/encoding.js +24 -0
- package/dist/personhood/hashing.d.ts +4 -0
- package/dist/personhood/hashing.js +8 -0
- package/dist/personhood/member-key.d.ts +12 -0
- package/dist/personhood/member-key.js +10 -0
- package/dist/personhood/people-client.d.ts +14 -0
- package/dist/personhood/people-client.js +48 -0
- package/dist/personhood/reprove.d.ts +43 -0
- package/dist/personhood/reprove.js +225 -0
- package/dist/pool.d.ts +7 -2
- package/dist/pool.js +3 -1
- package/dist/run-state.js +1 -1
- package/dist/telemetry.d.ts +7 -1
- package/dist/telemetry.js +8 -2
- package/dist/version-check.js +3 -3
- package/docs/e2e-bootstrap.md +36 -10
- package/package.json +4 -3
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildImplicationMessage,
|
|
3
|
+
buildV5GeneralExtrinsic,
|
|
4
|
+
bytesToHex,
|
|
5
|
+
hexToBytes,
|
|
6
|
+
readExtensionOrder,
|
|
7
|
+
toHex
|
|
8
|
+
} from "./chunk-ZYVGHDMU.js";
|
|
9
|
+
import {
|
|
10
|
+
BANDERSNATCH_SIGNATURE_BYTES
|
|
11
|
+
} from "./chunk-T7EEVWNU.js";
|
|
12
|
+
|
|
13
|
+
// src/personhood/bind-personal-id.ts
|
|
14
|
+
import { Enum } from "polkadot-api";
|
|
15
|
+
var AS_PERSON_IDENTIFIER = "AsPerson";
|
|
16
|
+
var VERIFY_MULTI_SIGNATURE_IDENTIFIER = "VerifyMultiSignature";
|
|
17
|
+
var IMPLICATION_EXCLUDE = /* @__PURE__ */ new Set([
|
|
18
|
+
"VerifyMultiSignature",
|
|
19
|
+
AS_PERSON_IDENTIFIER,
|
|
20
|
+
"AuthorizeCall",
|
|
21
|
+
"StorageWeightReclaim"
|
|
22
|
+
]);
|
|
23
|
+
var PersonalIdBindingError = class extends Error {
|
|
24
|
+
dispatchError;
|
|
25
|
+
kind;
|
|
26
|
+
constructor(message, options = {}) {
|
|
27
|
+
super(message, options);
|
|
28
|
+
this.name = "PersonalIdBindingError";
|
|
29
|
+
this.kind = options.kind ?? "unknown";
|
|
30
|
+
this.dispatchError = options.dispatchError;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
function buildAsPersonExtensionValue(signature, personalId) {
|
|
34
|
+
return Enum("AsPersonalIdentityWithProof", [bytesToHex(signature), personalId]);
|
|
35
|
+
}
|
|
36
|
+
var bindPersonalIdToAccount = async ({
|
|
37
|
+
typedApi,
|
|
38
|
+
client,
|
|
39
|
+
personalId,
|
|
40
|
+
account,
|
|
41
|
+
signMember,
|
|
42
|
+
callValidAt,
|
|
43
|
+
progress
|
|
44
|
+
}) => {
|
|
45
|
+
const api = typedApi;
|
|
46
|
+
if (typeof api.tx?.People?.set_personal_id_account !== "function") {
|
|
47
|
+
throw new PersonalIdBindingError(
|
|
48
|
+
"typedApi does not expose People.set_personal_id_account \u2014 wrong chain or stale descriptors",
|
|
49
|
+
{ kind: "client_error" }
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const block = callValidAt ?? await api.query.System.Number.getValue();
|
|
53
|
+
const innerTx = api.tx.People.set_personal_id_account({
|
|
54
|
+
account,
|
|
55
|
+
call_valid_at: block
|
|
56
|
+
});
|
|
57
|
+
const callBytes = await innerTx.getEncodedData();
|
|
58
|
+
const passEmpty = await capturePass({
|
|
59
|
+
innerTx,
|
|
60
|
+
asPersonValue: new Uint8Array()
|
|
61
|
+
});
|
|
62
|
+
const msgHash = buildImplicationMessage(
|
|
63
|
+
callBytes,
|
|
64
|
+
passEmpty.extensions,
|
|
65
|
+
IMPLICATION_EXCLUDE
|
|
66
|
+
);
|
|
67
|
+
const signature = await Promise.resolve(signMember(msgHash));
|
|
68
|
+
if (signature.length !== BANDERSNATCH_SIGNATURE_BYTES) {
|
|
69
|
+
throw new PersonalIdBindingError(
|
|
70
|
+
`Bandersnatch signature must be ${BANDERSNATCH_SIGNATURE_BYTES} bytes, got ${signature.length}`,
|
|
71
|
+
{ kind: "client_error" }
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const asPersonProof = Enum("AsPersonalIdentityWithProof", [bytesToHex(signature), personalId]);
|
|
75
|
+
const passProof = await capturePass({
|
|
76
|
+
innerTx,
|
|
77
|
+
asPersonValue: asPersonProof
|
|
78
|
+
});
|
|
79
|
+
const extrinsicBytes = buildV5GeneralExtrinsic(callBytes, passProof.extensions);
|
|
80
|
+
const extrinsicHex = toHex(extrinsicBytes);
|
|
81
|
+
const blockHash = await submitExtrinsic(client, extrinsicHex, progress);
|
|
82
|
+
return { extrinsicHex, blockHash };
|
|
83
|
+
};
|
|
84
|
+
var capturePass = async ({
|
|
85
|
+
innerTx,
|
|
86
|
+
asPersonValue
|
|
87
|
+
}) => {
|
|
88
|
+
let captured = null;
|
|
89
|
+
const sentinel = new Error("__personhood_capture_sentinel__");
|
|
90
|
+
const signer = {
|
|
91
|
+
publicKey: new Uint8Array(32),
|
|
92
|
+
signTx: async (callData, signedExtensions, metadata) => {
|
|
93
|
+
const order = await readExtensionOrder(metadata);
|
|
94
|
+
const byIdentifier = {};
|
|
95
|
+
for (const id of order) {
|
|
96
|
+
const ext = signedExtensions[id];
|
|
97
|
+
if (!ext) {
|
|
98
|
+
throw new PersonalIdBindingError(
|
|
99
|
+
`papi did not produce signed extension '${id}'`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
byIdentifier[id] = {
|
|
103
|
+
value: ext.value,
|
|
104
|
+
additionalSigned: ext.additionalSigned
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
captured = { callData, extensions: { order, byIdentifier } };
|
|
108
|
+
throw sentinel;
|
|
109
|
+
},
|
|
110
|
+
signBytes: async () => new Uint8Array(64)
|
|
111
|
+
};
|
|
112
|
+
try {
|
|
113
|
+
await innerTx.sign(signer, {
|
|
114
|
+
customSignedExtensions: {
|
|
115
|
+
[AS_PERSON_IDENTIFIER]: {
|
|
116
|
+
value: asPersonValue,
|
|
117
|
+
additionalSigned: new Uint8Array()
|
|
118
|
+
},
|
|
119
|
+
[VERIFY_MULTI_SIGNATURE_IDENTIFIER]: {
|
|
120
|
+
value: Enum("Disabled")
|
|
121
|
+
},
|
|
122
|
+
RestrictOrigins: {
|
|
123
|
+
value: new Uint8Array([1]),
|
|
124
|
+
additionalSigned: new Uint8Array()
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
} catch (err) {
|
|
129
|
+
if (err !== sentinel) throw err;
|
|
130
|
+
}
|
|
131
|
+
if (!captured) {
|
|
132
|
+
throw new PersonalIdBindingError(
|
|
133
|
+
"extension capture failed \u2014 papi never invoked signTx",
|
|
134
|
+
{ kind: "client_error" }
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
return captured;
|
|
138
|
+
};
|
|
139
|
+
var submitExtrinsic = (client, extrinsicHex, progress) => {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
let settled = false;
|
|
142
|
+
const fail = (err) => {
|
|
143
|
+
if (settled) return;
|
|
144
|
+
settled = true;
|
|
145
|
+
reject(err);
|
|
146
|
+
};
|
|
147
|
+
const succeed = (blockHash) => {
|
|
148
|
+
if (settled) return;
|
|
149
|
+
settled = true;
|
|
150
|
+
resolve(blockHash);
|
|
151
|
+
};
|
|
152
|
+
client.submitAndWatch(hexToBytes(extrinsicHex)).subscribe({
|
|
153
|
+
next: (event) => {
|
|
154
|
+
if (settled) return;
|
|
155
|
+
if (event.type === "broadcasted") {
|
|
156
|
+
progress?.onBroadcasted?.();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (event.type === "txBestBlocksState" && event.found) {
|
|
160
|
+
if (event.ok === false) {
|
|
161
|
+
fail(
|
|
162
|
+
new PersonalIdBindingError(
|
|
163
|
+
"set_personal_id_account dispatched but failed in-block",
|
|
164
|
+
{
|
|
165
|
+
kind: "dispatch_error",
|
|
166
|
+
dispatchError: event.dispatchError
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
progress?.onBestBlock?.(event.block.hash);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (event.type === "finalized") {
|
|
176
|
+
if (event.ok === false) {
|
|
177
|
+
fail(
|
|
178
|
+
new PersonalIdBindingError(
|
|
179
|
+
"set_personal_id_account dispatch failed at finalization",
|
|
180
|
+
{
|
|
181
|
+
kind: "dispatch_error",
|
|
182
|
+
dispatchError: event.dispatchError
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
succeed(event.block.hash);
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
error: (err) => {
|
|
192
|
+
fail(
|
|
193
|
+
err instanceof PersonalIdBindingError ? err : new PersonalIdBindingError(
|
|
194
|
+
err instanceof Error ? `RPC rejected extrinsic: ${err.message}` : "RPC error during submitAndWatch",
|
|
195
|
+
{ cause: err, kind: "rpc_error" }
|
|
196
|
+
)
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
export {
|
|
204
|
+
PersonalIdBindingError,
|
|
205
|
+
buildAsPersonExtensionValue,
|
|
206
|
+
bindPersonalIdToAccount
|
|
207
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
blake2b256Keyed
|
|
3
|
+
} from "./chunk-UPWEOGLQ.js";
|
|
4
|
+
import {
|
|
5
|
+
MEMBER_ENTROPY_KEY
|
|
6
|
+
} from "./chunk-T7EEVWNU.js";
|
|
7
|
+
|
|
8
|
+
// src/personhood/member-key.ts
|
|
9
|
+
import { mnemonicToEntropy } from "@polkadot-labs/hdkd-helpers";
|
|
10
|
+
import * as verifiable from "verifiablejs/nodejs";
|
|
11
|
+
function deriveMemberEntropy(mnemonic) {
|
|
12
|
+
const normalized = mnemonic.trim().split(/\s+/).join(" ");
|
|
13
|
+
const bip39Entropy = mnemonicToEntropy(normalized);
|
|
14
|
+
return blake2b256Keyed(bip39Entropy, MEMBER_ENTROPY_KEY);
|
|
15
|
+
}
|
|
16
|
+
function deriveMemberKey(mnemonic) {
|
|
17
|
+
const entropy = deriveMemberEntropy(mnemonic);
|
|
18
|
+
return verifiable.member_from_entropy(entropy);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
deriveMemberEntropy,
|
|
23
|
+
deriveMemberKey
|
|
24
|
+
};
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
computeStats,
|
|
3
3
|
renderSummary,
|
|
4
4
|
telemetryAttributes
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LEYQOOWC.js";
|
|
6
6
|
import {
|
|
7
7
|
finaliseEmbeddedManifest,
|
|
8
8
|
writeEmbeddedManifestPlaceholder
|
|
@@ -20,10 +20,10 @@ import {
|
|
|
20
20
|
} from "./chunk-S7EM5VMW.js";
|
|
21
21
|
import {
|
|
22
22
|
setDeployContext
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-TA3NCL6U.js";
|
|
24
24
|
import {
|
|
25
25
|
probeChunks
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-KTOZL74I.js";
|
|
27
27
|
import {
|
|
28
28
|
packSection
|
|
29
29
|
} from "./chunk-C2TS5MER.js";
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
parseDomainName,
|
|
35
35
|
popStatusName,
|
|
36
36
|
verifyNonceAdvanced
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-4YO5SOAY.js";
|
|
38
38
|
import {
|
|
39
39
|
derivePoolAccounts,
|
|
40
40
|
detectTestnet,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
fetchPoolAuthorizations,
|
|
43
43
|
selectAccount,
|
|
44
44
|
topUpBy
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-WVCIU6WM.js";
|
|
46
46
|
import {
|
|
47
47
|
VERSION,
|
|
48
48
|
captureWarning,
|
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
truncateAddress,
|
|
57
57
|
withDeploySpan,
|
|
58
58
|
withSpan
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-3LGLMHQI.js";
|
|
60
60
|
import {
|
|
61
61
|
DEFAULT_ENV_ID,
|
|
62
62
|
loadEnvironments,
|
|
@@ -395,7 +395,7 @@ function assignDenseNonces(stored, startNonce) {
|
|
|
395
395
|
return nonces;
|
|
396
396
|
}
|
|
397
397
|
var __assignDenseNoncesForTest = assignDenseNonces;
|
|
398
|
-
async function storeChunkedContent(chunks, { client: existingClient, unsafeApi: existingApi, signer: existingSigner, ss58: existingSS58, reconnect, fetchNonce: fetchNonceOverride, skipCids, probeFailedCids, gateway: providerGateway } = {}) {
|
|
398
|
+
async function storeChunkedContent(chunks, { client: existingClient, unsafeApi: existingApi, signer: existingSigner, ss58: existingSS58, reconnect, fetchNonce: fetchNonceOverride, skipCids, probeFailedCids, gateway: providerGateway, bulletinAuthorizeV2 } = {}) {
|
|
399
399
|
const _fetchNonce = fetchNonceOverride ?? fetchNonce;
|
|
400
400
|
console.log(`
|
|
401
401
|
Chunks: ${chunks.length}`);
|
|
@@ -461,11 +461,13 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
|
|
|
461
461
|
const bytesRemaining = uploadAuth ? BigInt(uploadAuth.extent.bytes_allowance) - BigInt(uploadAuth.extent.bytes) : 0n;
|
|
462
462
|
const isAuthorized = uploadAuth !== void 0 && Number(uploadAuth.expiration ?? 0) > currentBlockNum;
|
|
463
463
|
if (!isAuthorized || txsRemaining < requiredTxs || bytesRemaining < requiredBytes) {
|
|
464
|
+
const txsRemainingDisplay = txsRemaining < 0n ? 0n : txsRemaining;
|
|
465
|
+
const bytesRemainingDisplay = bytesRemaining < 0n ? 0n : bytesRemaining;
|
|
464
466
|
console.log(`
|
|
465
|
-
Account needs re-authorization (authorized=${isAuthorized}, need ${requiredTxs} txs / ${(totalBytes / 1e6).toFixed(1)}MB, have ${
|
|
467
|
+
Account needs re-authorization (authorized=${isAuthorized}, need ${requiredTxs} txs / ${(totalBytes / 1e6).toFixed(1)}MB, have ${txsRemainingDisplay} txs / ${(Number(bytesRemainingDisplay) / 1e6).toFixed(2)}MB)`);
|
|
466
468
|
console.log(` Attempting to re-authorize with Alice...`);
|
|
467
469
|
try {
|
|
468
|
-
await ensureAuthorized(unsafeApi, ss58);
|
|
470
|
+
await ensureAuthorized(unsafeApi, ss58, void 0, bulletinAuthorizeV2, { txs: requiredTxs, bytes: requiredBytes });
|
|
469
471
|
console.log(` Re-authorization successful`);
|
|
470
472
|
} catch (e) {
|
|
471
473
|
throw new NonRetryableError(`Account ${ss58} has insufficient Bulletin authorization and auto-authorization via Alice failed (${e.message}). Authorize the account on-chain.`);
|
|
@@ -1024,11 +1026,11 @@ async function storeDirectoryV2(directoryPath, opts = {}) {
|
|
|
1024
1026
|
const probe = carChunkCidsA.length > 0 ? await withSpan("deploy.chain-probe", "2. chain probe", { "deploy.probe.total": carChunkCidsA.length }, () => probeChunks(carChunkCidsA, { client: provider.client })) : [];
|
|
1025
1027
|
const skipCids = /* @__PURE__ */ new Set();
|
|
1026
1028
|
const probeFailedCidsA = /* @__PURE__ */ new Set();
|
|
1027
|
-
let
|
|
1029
|
+
let bytesProbePresent = 0;
|
|
1028
1030
|
for (let i = 0; i < probe.length; i++) {
|
|
1029
1031
|
if (probe[i].present === true) {
|
|
1030
1032
|
skipCids.add(carChunkCidsA[i]);
|
|
1031
|
-
|
|
1033
|
+
bytesProbePresent += carChunksA[i].length;
|
|
1032
1034
|
} else if (probe[i].present === null) {
|
|
1033
1035
|
probeFailedCidsA.add(carChunkCidsA[i]);
|
|
1034
1036
|
}
|
|
@@ -1165,6 +1167,7 @@ async function storeDirectoryV2(directoryPath, opts = {}) {
|
|
|
1165
1167
|
probeResults: probe,
|
|
1166
1168
|
prevChunks: prevManifest?.chunks ?? {},
|
|
1167
1169
|
retentionPeriodBlocks,
|
|
1170
|
+
bytesProbePresent,
|
|
1168
1171
|
bytesSkipped: bytesSkippedB,
|
|
1169
1172
|
bytesUploaded: bytesUploadedB,
|
|
1170
1173
|
chunksTotal: phaseB.chunks.length,
|
|
@@ -1182,15 +1185,16 @@ async function storeDirectoryV2(directoryPath, opts = {}) {
|
|
|
1182
1185
|
console.log("\n" + renderSummary(stats));
|
|
1183
1186
|
return { storageCid, ipfsCid: phaseB.cid, carBytes: phaseB.carBytes };
|
|
1184
1187
|
}
|
|
1185
|
-
function resolveDotnsConnectOptions(options, assetHubEndpoints, autoAccountMapping, contracts, nativeToEthRatio) {
|
|
1188
|
+
function resolveDotnsConnectOptions(options, assetHubEndpoints, autoAccountMapping, contracts, nativeToEthRatio, environmentId) {
|
|
1186
1189
|
const tail = assetHubEndpoints && assetHubEndpoints.length > 0 ? { assetHubEndpoints } : {};
|
|
1187
1190
|
const mappingTail = autoAccountMapping ? { autoAccountMapping } : {};
|
|
1188
1191
|
const contractsTail = contracts && Object.keys(contracts).length > 0 ? { contracts } : {};
|
|
1189
1192
|
const ratioTail = nativeToEthRatio ? { nativeToEthRatio } : {};
|
|
1193
|
+
const envTail = environmentId ? { environmentId } : {};
|
|
1190
1194
|
if (options.signer && options.signerAddress) {
|
|
1191
|
-
return { signer: options.signer, signerAddress: options.signerAddress, ...tail, ...mappingTail, ...contractsTail, ...ratioTail };
|
|
1195
|
+
return { signer: options.signer, signerAddress: options.signerAddress, ...tail, ...mappingTail, ...contractsTail, ...ratioTail, ...envTail };
|
|
1192
1196
|
}
|
|
1193
|
-
return { mnemonic: options.mnemonic, derivationPath: options.derivationPath, ...tail, ...mappingTail, ...contractsTail, ...ratioTail };
|
|
1197
|
+
return { mnemonic: options.mnemonic, derivationPath: options.derivationPath, ...tail, ...mappingTail, ...contractsTail, ...ratioTail, ...envTail };
|
|
1194
1198
|
}
|
|
1195
1199
|
async function estimateUploadBytes(content) {
|
|
1196
1200
|
try {
|
|
@@ -1328,7 +1332,7 @@ async function deploy(content, domainName = null, options = {}) {
|
|
|
1328
1332
|
}
|
|
1329
1333
|
}
|
|
1330
1334
|
provider = await reconnect();
|
|
1331
|
-
const providerWithReconnect = { ...provider, reconnect };
|
|
1335
|
+
const providerWithReconnect = { ...provider, reconnect, bulletinAuthorizeV2: envBulletinAuthorizeV2 };
|
|
1332
1336
|
const [isTestnet, estimated] = await Promise.all([
|
|
1333
1337
|
detectTestnet(provider.unsafeApi),
|
|
1334
1338
|
estimateUploadBytes(content)
|
|
@@ -1337,7 +1341,7 @@ async function deploy(content, domainName = null, options = {}) {
|
|
|
1337
1341
|
const uploadBytes = Math.ceil(estimated * 1.2);
|
|
1338
1342
|
const chunksNeeded = Math.max(1, Math.ceil(uploadBytes / CHUNK_SIZE));
|
|
1339
1343
|
const needs = { txs: BigInt(chunksNeeded + 2), bytes: BigInt(uploadBytes) };
|
|
1340
|
-
await topUpBy(provider.unsafeApi, provider.ss58, needs, "uploader");
|
|
1344
|
+
await topUpBy(provider.unsafeApi, provider.ss58, needs, "uploader", envBulletinAuthorizeV2);
|
|
1341
1345
|
}
|
|
1342
1346
|
console.log("\n" + "=".repeat(60));
|
|
1343
1347
|
console.log("Storage");
|
|
@@ -1502,7 +1506,7 @@ async function deploy(content, domainName = null, options = {}) {
|
|
|
1502
1506
|
console.log("=".repeat(60));
|
|
1503
1507
|
await withSpan("deploy.dotns", "2. dotns", { "deploy.domain": name, "deploy.subdomain": String(parsed?.isSubdomain ?? false) }, async () => {
|
|
1504
1508
|
const dotns = new DotNS();
|
|
1505
|
-
await dotns.connect(resolveDotnsConnectOptions(options, envAssetHub, envAutoAccountMapping, envContracts, envNativeToEthRatio));
|
|
1509
|
+
await dotns.connect(resolveDotnsConnectOptions(options, envAssetHub, envAutoAccountMapping, envContracts, envNativeToEthRatio, envId));
|
|
1506
1510
|
if (parsed?.isSubdomain) {
|
|
1507
1511
|
const { owned, owner } = await dotns.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
|
|
1508
1512
|
if (owned) {
|
|
@@ -6,7 +6,6 @@ function countByReason(probe, reason) {
|
|
|
6
6
|
function computeStats(input) {
|
|
7
7
|
const present = input.probeResults.filter((r) => r.present === true);
|
|
8
8
|
const failed = input.probeResults.filter((r) => r.present === null);
|
|
9
|
-
const presentInPrev = present.filter((r) => input.prevChunks[r.cid] != null);
|
|
10
9
|
const recycled = present.filter((r) => input.prevChunks[r.cid] == null);
|
|
11
10
|
return {
|
|
12
11
|
manifestSource: input.manifestSource,
|
|
@@ -25,6 +24,7 @@ function computeStats(input) {
|
|
|
25
24
|
probeFailedMetadata: countByReason(input.probeResults, "metadata_error"),
|
|
26
25
|
recycledCids: recycled.length,
|
|
27
26
|
retentionPeriodBlocks: input.retentionPeriodBlocks,
|
|
27
|
+
bytesProbePresent: input.bytesProbePresent,
|
|
28
28
|
bytesSkipped: input.bytesSkipped,
|
|
29
29
|
bytesUploaded: input.bytesUploaded,
|
|
30
30
|
chunksTotal: input.chunksTotal,
|
|
@@ -34,7 +34,7 @@ function computeStats(input) {
|
|
|
34
34
|
section0Bytes: input.sectionSizes.section0,
|
|
35
35
|
section1Bytes: input.sectionSizes.section1,
|
|
36
36
|
section2Bytes: input.sectionSizes.section2,
|
|
37
|
-
estimatedSecondsSaved: Math.round(SECONDS_PER_PROBE_SKIP *
|
|
37
|
+
estimatedSecondsSaved: Math.round(SECONDS_PER_PROBE_SKIP * present.length),
|
|
38
38
|
tier2VerifiedCount: input.tier2VerifiedCount,
|
|
39
39
|
tier2InconclusiveCount: input.tier2InconclusiveCount,
|
|
40
40
|
tier2FallbackCount: input.tier2FallbackCount
|
|
@@ -63,6 +63,7 @@ function telemetryAttributes(s) {
|
|
|
63
63
|
"deploy.cache.chunks_total": String(s.chunksTotal),
|
|
64
64
|
"deploy.cache.chunks_uploaded": String(s.chunksUploaded),
|
|
65
65
|
"deploy.cache.chunks_skipped": String(s.chunksSkipped),
|
|
66
|
+
"deploy.cache.bytes_probe_present": String(s.bytesProbePresent),
|
|
66
67
|
"deploy.cache.bytes_skipped": String(s.bytesSkipped),
|
|
67
68
|
"deploy.cache.bytes_uploaded": String(s.bytesUploaded),
|
|
68
69
|
"deploy.cache.car_bytes": String(s.carBytes),
|
|
@@ -6,7 +6,7 @@ import * as path from "path";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "bulletin-deploy",
|
|
9
|
-
version: "0.7.
|
|
9
|
+
version: "0.7.22-rc.0",
|
|
10
10
|
private: false,
|
|
11
11
|
repository: {
|
|
12
12
|
type: "git",
|
|
@@ -36,11 +36,11 @@ var package_default = {
|
|
|
36
36
|
"assets"
|
|
37
37
|
],
|
|
38
38
|
scripts: {
|
|
39
|
-
build: "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/memory-report.ts src/merkle.ts src/gh-pages-mirror.ts src/version-check.ts src/bug-report.ts src/run-state.ts src/environments.ts src/errors.ts src/manifest.ts src/chunk-probe.ts src/manifest-embed.ts src/manifest-fetch.ts src/manifest-roundtrip.ts src/incremental-stats.ts src/chunker.ts src/mirror.ts --format esm --dts --clean --target node22",
|
|
39
|
+
build: "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/memory-report.ts src/merkle.ts src/gh-pages-mirror.ts src/version-check.ts src/bug-report.ts src/run-state.ts src/environments.ts src/errors.ts src/manifest.ts src/chunk-probe.ts src/manifest-embed.ts src/manifest-fetch.ts src/manifest-roundtrip.ts src/incremental-stats.ts src/chunker.ts src/mirror.ts src/personhood/encoding.ts src/personhood/hashing.ts src/personhood/constants.ts src/personhood/member-key.ts src/personhood/people-client.ts src/personhood/reprove.ts src/personhood/bind-personal-id.ts src/personhood/claim-pgas.ts src/personhood/bind-paid-alias.ts src/personhood/bootstrap.ts --format esm --dts --clean --target node22",
|
|
40
40
|
"refresh-environments": "node scripts/refresh-environments.mjs",
|
|
41
41
|
"check:watched-dependencies": "node tools/check-watched-dependencies.mjs",
|
|
42
42
|
prepare: "npm run build",
|
|
43
|
-
test: "npm run build && node --test test/test.js test/cli-help.test.js test/helpers/e2e-helpers.test.js test/environments.test.js test/refresh-environments.test.js test/watched-dependencies.test.js",
|
|
43
|
+
test: "npm run build && node --test test/test.js test/cli-help.test.js test/helpers/e2e-helpers.test.js test/environments.test.js test/refresh-environments.test.js test/watched-dependencies.test.js test/chunk-sharing-report.test.js",
|
|
44
44
|
"test:e2e": "npm run build && node --test test/e2e.test.js",
|
|
45
45
|
"test:e2e:smoke": "bash scripts/e2e-pass.sh smoke",
|
|
46
46
|
"test:e2e:pr": "bash scripts/e2e-pass.sh pr",
|
|
@@ -62,6 +62,7 @@ var package_default = {
|
|
|
62
62
|
"ipfs-unixfs-importer": "^16.1.4",
|
|
63
63
|
multiformats: "^13.4.1",
|
|
64
64
|
"polkadot-api": "^2.1.3",
|
|
65
|
+
verifiablejs: "^1.2.0",
|
|
65
66
|
viem: "^2.30.5"
|
|
66
67
|
},
|
|
67
68
|
devDependencies: {
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import {
|
|
2
|
+
blake2_256,
|
|
3
|
+
bytesToHex,
|
|
4
|
+
concatBytes,
|
|
5
|
+
encodeMembers,
|
|
6
|
+
hexToBytes
|
|
7
|
+
} from "./chunk-ZYVGHDMU.js";
|
|
8
|
+
import {
|
|
9
|
+
PAID_PROOF_TAG,
|
|
10
|
+
PEOPLE_MEMBER_IDENTIFIER_HEX,
|
|
11
|
+
PGAS_ASSET_ID,
|
|
12
|
+
PGAS_ASSET_LOCATION,
|
|
13
|
+
PROOF_BYTES
|
|
14
|
+
} from "./chunk-T7EEVWNU.js";
|
|
15
|
+
|
|
16
|
+
// src/personhood/bind-paid-alias.ts
|
|
17
|
+
import { getSs58AddressInfo } from "polkadot-api";
|
|
18
|
+
var PaidAliasBindingError = class extends Error {
|
|
19
|
+
kind;
|
|
20
|
+
dispatchError;
|
|
21
|
+
constructor(message, options = {}) {
|
|
22
|
+
super(message, options);
|
|
23
|
+
this.name = "PaidAliasBindingError";
|
|
24
|
+
this.kind = options.kind ?? "Unknown";
|
|
25
|
+
this.dispatchError = options.dispatchError;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var bindPaidAliasToAccount = async ({
|
|
29
|
+
peopleUnsafeApi,
|
|
30
|
+
ahUnsafeApi,
|
|
31
|
+
account,
|
|
32
|
+
memberKey,
|
|
33
|
+
contextBytes,
|
|
34
|
+
signCall,
|
|
35
|
+
buildRingProof,
|
|
36
|
+
progress
|
|
37
|
+
}) => {
|
|
38
|
+
const people = peopleUnsafeApi;
|
|
39
|
+
const ah = ahUnsafeApi;
|
|
40
|
+
if (memberKey.length !== 32) {
|
|
41
|
+
throw new PaidAliasBindingError("memberKey must be 32 bytes", {
|
|
42
|
+
kind: "ClientError"
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
if (contextBytes.length !== 32) {
|
|
46
|
+
throw new PaidAliasBindingError("contextBytes must be 32 bytes", {
|
|
47
|
+
kind: "ClientError"
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const fee = await ah.query.AliasAccounts.PaidAliasFee.getValue({ at: "best" });
|
|
51
|
+
if (fee === void 0) {
|
|
52
|
+
throw new PaidAliasBindingError(
|
|
53
|
+
"AliasAccounts.PaidAliasFee is unset \u2014 needs sudo `set_paid_alias_fee`",
|
|
54
|
+
{ kind: "PaidAliasFeeUnset" }
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
const pgas = await ah.query.Assets.Account.getValue(
|
|
58
|
+
PGAS_ASSET_ID,
|
|
59
|
+
account,
|
|
60
|
+
{ at: "best" }
|
|
61
|
+
);
|
|
62
|
+
const pgasBalance = pgas?.balance ?? 0n;
|
|
63
|
+
if (pgasBalance < fee) {
|
|
64
|
+
throw new PaidAliasBindingError(
|
|
65
|
+
`signer has ${pgasBalance.toString()} PGAS but PaidAliasFee is ${fee.toString()} \u2014 claim PGAS first`,
|
|
66
|
+
{ kind: "InsufficientPgas" }
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const position = await people.query.Members.Members.getValue(
|
|
70
|
+
PEOPLE_MEMBER_IDENTIFIER_HEX,
|
|
71
|
+
bytesToHex(memberKey),
|
|
72
|
+
{ at: "best" }
|
|
73
|
+
);
|
|
74
|
+
if (!position || position.type !== "Included") {
|
|
75
|
+
throw new PaidAliasBindingError(
|
|
76
|
+
`member position is '${position?.type ?? "absent"}', expected 'Included'`,
|
|
77
|
+
{ kind: "NotARecognizedPerson" }
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const ringIndex = position.value.ring_index;
|
|
81
|
+
const allEntries = await people.query.Members.RingKeys.getEntries({
|
|
82
|
+
at: "best"
|
|
83
|
+
});
|
|
84
|
+
const pages = [];
|
|
85
|
+
const identHex = PEOPLE_MEMBER_IDENTIFIER_HEX.toLowerCase();
|
|
86
|
+
for (const entry of allEntries) {
|
|
87
|
+
if (entry.keyArgs[0].toLowerCase() !== identHex) continue;
|
|
88
|
+
if (Number(entry.keyArgs[1]) !== ringIndex) continue;
|
|
89
|
+
pages.push([Number(entry.keyArgs[2]), [...entry.value]]);
|
|
90
|
+
}
|
|
91
|
+
pages.sort((a, b) => a[0] - b[0]);
|
|
92
|
+
const ringKeys = pages.flatMap(([, ks]) => ks);
|
|
93
|
+
if (ringKeys.length === 0) {
|
|
94
|
+
throw new PaidAliasBindingError("ring has no members on People", {
|
|
95
|
+
kind: "ClientError"
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const membersBytes = encodeMembers(ringKeys.map((k) => hexToBytes(k)));
|
|
99
|
+
const collectionId = await ah.constants.AliasAccounts.PeopleCollectionIdentifier();
|
|
100
|
+
const ringExp = await ah.constants.AliasAccounts.PeopleRingExponent();
|
|
101
|
+
const ringExponent = ringExp.type === "R2e9" ? 9 : ringExp.type === "R2e10" ? 10 : 14;
|
|
102
|
+
const ringRoots = await ah.query.MembersSubscriber.RingRoots.getValue(
|
|
103
|
+
collectionId,
|
|
104
|
+
ringIndex,
|
|
105
|
+
{ at: "best" }
|
|
106
|
+
);
|
|
107
|
+
if (!ringRoots || ringRoots.length === 0) {
|
|
108
|
+
throw new PaidAliasBindingError(
|
|
109
|
+
"AH has no RingRoots for this (collection, ring_index)",
|
|
110
|
+
{ kind: "RingRootNotFound" }
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
const latest = ringRoots[ringRoots.length - 1];
|
|
114
|
+
const revision = latest.revision;
|
|
115
|
+
const ss58Info = getSs58AddressInfo(account);
|
|
116
|
+
if (!ss58Info.isValid) {
|
|
117
|
+
throw new PaidAliasBindingError(`invalid SS58: ${account}`, {
|
|
118
|
+
kind: "ClientError"
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
const paidMsg = blake2_256(concatBytes(PAID_PROOF_TAG, ss58Info.publicKey));
|
|
122
|
+
const { proof, alias } = await buildRingProof({
|
|
123
|
+
ringExponent,
|
|
124
|
+
members: membersBytes,
|
|
125
|
+
context: contextBytes,
|
|
126
|
+
msg: paidMsg
|
|
127
|
+
});
|
|
128
|
+
if (proof.length !== PROOF_BYTES) {
|
|
129
|
+
throw new PaidAliasBindingError(
|
|
130
|
+
`ring proof must be ${PROOF_BYTES} bytes, got ${proof.length}`,
|
|
131
|
+
{ kind: "ClientError" }
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
const tx = ah.tx.AliasAccounts.set_paid_alias_account({
|
|
135
|
+
proof: bytesToHex(proof),
|
|
136
|
+
collection: collectionId,
|
|
137
|
+
ring_index: ringIndex,
|
|
138
|
+
ring_revision: revision,
|
|
139
|
+
context: bytesToHex(contextBytes)
|
|
140
|
+
});
|
|
141
|
+
const submitOptions = {
|
|
142
|
+
customSignedExtensions: {
|
|
143
|
+
ChargeAssetTxPayment: {
|
|
144
|
+
value: { tip: 0n, asset_id: PGAS_ASSET_LOCATION }
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const blockHash = await new Promise((resolve, reject) => {
|
|
149
|
+
let settled = false;
|
|
150
|
+
const fail = (err) => {
|
|
151
|
+
if (settled) return;
|
|
152
|
+
settled = true;
|
|
153
|
+
reject(err);
|
|
154
|
+
};
|
|
155
|
+
const succeed = (h) => {
|
|
156
|
+
if (settled) return;
|
|
157
|
+
settled = true;
|
|
158
|
+
resolve(h);
|
|
159
|
+
};
|
|
160
|
+
tx.signSubmitAndWatch(signCall, submitOptions).subscribe({
|
|
161
|
+
next: (event) => {
|
|
162
|
+
if (settled) return;
|
|
163
|
+
const ev = event;
|
|
164
|
+
if (ev.type === "broadcasted") {
|
|
165
|
+
progress?.onBroadcasted?.();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (ev.type === "txBestBlocksState" && ev.found) {
|
|
169
|
+
if (ev.ok === false) {
|
|
170
|
+
fail(
|
|
171
|
+
new PaidAliasBindingError(
|
|
172
|
+
"set_paid_alias_account dispatched but failed in-block",
|
|
173
|
+
{
|
|
174
|
+
kind: narrowDispatchError(ev.dispatchError),
|
|
175
|
+
dispatchError: ev.dispatchError
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (ev.block) progress?.onBestBlock?.(ev.block.hash);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (ev.type === "finalized") {
|
|
185
|
+
if (ev.ok === false) {
|
|
186
|
+
fail(
|
|
187
|
+
new PaidAliasBindingError(
|
|
188
|
+
"set_paid_alias_account failed at finalization",
|
|
189
|
+
{
|
|
190
|
+
kind: narrowDispatchError(ev.dispatchError),
|
|
191
|
+
dispatchError: ev.dispatchError
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (ev.block) succeed(ev.block.hash);
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
error: (err) => {
|
|
201
|
+
fail(
|
|
202
|
+
err instanceof PaidAliasBindingError ? err : new PaidAliasBindingError(
|
|
203
|
+
err instanceof Error ? `RPC rejected extrinsic: ${err.message}` : "RPC error during submitAndWatch",
|
|
204
|
+
{ cause: err, kind: "RpcError" }
|
|
205
|
+
)
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
return { blockHash, alias };
|
|
211
|
+
};
|
|
212
|
+
var narrowDispatchError = (dispatchError) => {
|
|
213
|
+
if (typeof dispatchError === "object" && dispatchError !== null && "type" in dispatchError) {
|
|
214
|
+
const d = dispatchError;
|
|
215
|
+
if (d.type === "Module" && typeof d.value === "object" && d.value !== null) {
|
|
216
|
+
const v = d.value;
|
|
217
|
+
if (v.type === "AliasAccounts" && v.value?.type === "BadProof") {
|
|
218
|
+
return "BadProof";
|
|
219
|
+
}
|
|
220
|
+
if (v.type === "AliasAccounts" && v.value?.type === "PaidAliasFeeUnset") {
|
|
221
|
+
return "PaidAliasFeeUnset";
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return "DispatchError";
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
export {
|
|
229
|
+
PaidAliasBindingError,
|
|
230
|
+
bindPaidAliasToAccount
|
|
231
|
+
};
|