@shelby-protocol/sdk 0.3.1 → 0.4.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/browser/index.d.ts +9 -9
- package/dist/browser/index.mjs +1068 -589
- package/dist/core/clients/ShelbyBlobClient.d.ts +155 -40
- package/dist/core/clients/ShelbyBlobClient.mjs +314 -112
- package/dist/core/clients/ShelbyClient.d.ts +27 -4
- package/dist/core/clients/ShelbyClient.mjs +869 -551
- package/dist/core/clients/ShelbyClientConfig.d.ts +9 -1
- package/dist/core/clients/ShelbyMetadataClient.d.ts +38 -6
- package/dist/core/clients/ShelbyMetadataClient.mjs +95 -13
- package/dist/core/clients/ShelbyMicropaymentChannelClient.d.ts +42 -0
- package/dist/core/clients/ShelbyMicropaymentChannelClient.mjs +62 -7
- package/dist/core/clients/ShelbyPlacementGroupClient.mjs +10 -7
- package/dist/core/clients/ShelbyRPCClient.d.ts +55 -66
- package/dist/core/clients/ShelbyRPCClient.mjs +344 -360
- package/dist/core/clients/index.d.ts +3 -2
- package/dist/core/clients/index.mjs +933 -551
- package/dist/core/clients/utils.mjs +1 -1
- package/dist/core/commitments.d.ts +12 -1
- package/dist/core/commitments.mjs +7 -0
- package/dist/core/constants.d.ts +1 -1
- package/dist/core/constants.mjs +1 -1
- package/dist/core/erasure/constants.d.ts +16 -1
- package/dist/core/erasure/constants.mjs +15 -1
- package/dist/core/erasure/index.d.ts +1 -1
- package/dist/core/erasure/index.mjs +15 -1
- package/dist/core/errors.d.ts +20 -1
- package/dist/core/errors.mjs +29 -0
- package/dist/core/index.d.ts +9 -9
- package/dist/core/index.mjs +1068 -589
- package/dist/core/operations/generated/sdk.d.ts +798 -42
- package/dist/core/operations/generated/sdk.mjs +93 -9
- package/dist/core/operations/index.d.ts +1 -1
- package/dist/core/operations/index.mjs +94 -10
- package/dist/core/rpc-responses.d.ts +1 -57
- package/dist/core/rpc-responses.mjs +1 -21
- package/dist/core/sp/chunk_proof.d.ts +23 -0
- package/dist/core/sp/chunk_proof.mjs +113 -0
- package/dist/core/sp/index.d.ts +3 -0
- package/dist/core/sp/index.mjs +402 -0
- package/dist/core/sp/sp_write_client.d.ts +53 -0
- package/dist/core/sp/sp_write_client.mjs +302 -0
- package/dist/core/types/blobs.d.ts +24 -5
- package/dist/core/types/blobs.mjs +24 -0
- package/dist/core/types/index.d.ts +2 -2
- package/dist/core/types/index.mjs +46 -2
- package/dist/core/types/payments.mjs +1 -1
- package/dist/core/types/storage_providers.d.ts +32 -6
- package/dist/core/types/storage_providers.mjs +22 -0
- package/dist/gen/rpc_server_pb.d.ts +295 -0
- package/dist/gen/rpc_server_pb.mjs +28 -0
- package/dist/node/clients/ShelbyNodeClient.d.ts +1 -0
- package/dist/node/clients/ShelbyNodeClient.mjs +869 -551
- package/dist/node/clients/index.d.ts +1 -0
- package/dist/node/clients/index.mjs +867 -551
- package/dist/node/index.d.ts +9 -9
- package/dist/node/index.mjs +1068 -589
- package/dist/node/parallel/commitment_worker.mjs +36 -249
- package/dist/node/parallel/commitment_worker_pool.mjs +56 -3
- package/dist/node/parallel/coverage_flush.d.ts +16 -0
- package/dist/node/parallel/coverage_flush.mjs +43 -0
- package/dist/node/parallel/default_commitment_worker_pool.mjs +56 -3
- package/dist/node/parallel/index.d.ts +1 -0
- package/dist/node/parallel/index.mjs +72 -4
- package/dist/node/parallel/parallel_commitments.mjs +56 -3
- package/dist/node/parallel/worker_pool.mjs +56 -3
- package/package.json +11 -4
package/dist/browser/index.mjs
CHANGED
|
@@ -174,6 +174,18 @@ var ERASURE_CODE_PARAMS = {
|
|
|
174
174
|
enumIndex: 1
|
|
175
175
|
}
|
|
176
176
|
};
|
|
177
|
+
function findErasureSchemeByErasureN(erasureN) {
|
|
178
|
+
return Object.entries(ERASURE_CODE_PARAMS).find(
|
|
179
|
+
([, params]) => params.erasure_n === erasureN
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
function requiredAckCount(erasureN) {
|
|
183
|
+
const scheme = findErasureSchemeByErasureN(erasureN);
|
|
184
|
+
if (!scheme) {
|
|
185
|
+
throw new Error(`Unknown erasure coding scheme with erasure_n=${erasureN}`);
|
|
186
|
+
}
|
|
187
|
+
return scheme[1].erasure_d;
|
|
188
|
+
}
|
|
177
189
|
var DEFAULT_ERASURE_N = ERASURE_CODE_PARAMS["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */].erasure_n;
|
|
178
190
|
var DEFAULT_ERASURE_K = ERASURE_CODE_PARAMS["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */].erasure_k;
|
|
179
191
|
var DEFAULT_ERASURE_D = ERASURE_CODE_PARAMS["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */].erasure_d;
|
|
@@ -244,6 +256,12 @@ function expectedTotalChunksets(rawSize, chunksetSize = DEFAULT_CHUNKSET_SIZE_BY
|
|
|
244
256
|
if (rawSize === 0) return 1;
|
|
245
257
|
return Math.ceil(rawSize / chunksetSize);
|
|
246
258
|
}
|
|
259
|
+
function expectedChunksetInclusionProofHashes(numChunksets) {
|
|
260
|
+
if (numChunksets < 1) {
|
|
261
|
+
throw new Error("numChunksets must be positive");
|
|
262
|
+
}
|
|
263
|
+
return Math.ceil(Math.log2(numChunksets));
|
|
264
|
+
}
|
|
247
265
|
var BlobCommitmentsSchema = z.object({
|
|
248
266
|
schema_version: z.string(),
|
|
249
267
|
raw_data_size: z.number(),
|
|
@@ -357,7 +375,7 @@ import { Network as Network2 } from "@aptos-labs/ts-sdk";
|
|
|
357
375
|
var DEFAULT_PROJECT_NAME = "shelby";
|
|
358
376
|
var DEFAULT_PROJECT_DESCRIPTION = "High performance, decentralized storage";
|
|
359
377
|
var NetworkToShelbyRPCBaseUrl = {
|
|
360
|
-
[Network2.SHELBYNET]: "https://
|
|
378
|
+
[Network2.SHELBYNET]: "https://shelby.shelbynet.shelby.xyz/shelby",
|
|
361
379
|
[Network2.NETNA]: void 0,
|
|
362
380
|
[Network2.DEVNET]: void 0,
|
|
363
381
|
[Network2.TESTNET]: "https://api.testnet.shelby.xyz/shelby",
|
|
@@ -392,6 +410,27 @@ var SHELBYUSD_TOKEN_MODULE = "shelby_usd";
|
|
|
392
410
|
var SHELBYUSD_TOKEN_NAME = "ShelbyUSD";
|
|
393
411
|
var SHELBYUSD_FA_METADATA_ADDRESS = "0x1b18363a9f1fe5e6ebf247daba5cc1c18052bb232efdc4c50f556053922d98e1";
|
|
394
412
|
|
|
413
|
+
// src/core/types/blobs.ts
|
|
414
|
+
var BLOB_ENCRYPTION_TO_MOVE_ENUM_INDEX = {
|
|
415
|
+
Unencrypted: 0,
|
|
416
|
+
AES_GCM_V1: 1
|
|
417
|
+
};
|
|
418
|
+
function blobEncryptionToMoveEnumIndex(encryption) {
|
|
419
|
+
return BLOB_ENCRYPTION_TO_MOVE_ENUM_INDEX[encryption];
|
|
420
|
+
}
|
|
421
|
+
function blobEncryptionFromMoveVariant(variant) {
|
|
422
|
+
switch (variant) {
|
|
423
|
+
case "Unencrypted":
|
|
424
|
+
return "Unencrypted";
|
|
425
|
+
case "AES_GCM_V1":
|
|
426
|
+
return "AES_GCM_V1";
|
|
427
|
+
default:
|
|
428
|
+
throw new Error(
|
|
429
|
+
"Could not parse encryption from Shelby Smart Contract, this SDK is out of date."
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
395
434
|
// src/core/erasure/clay-codes.ts
|
|
396
435
|
import {
|
|
397
436
|
createDecoder,
|
|
@@ -640,31 +679,80 @@ var getShelbyRPCBaseUrl = (config) => {
|
|
|
640
679
|
|
|
641
680
|
// src/core/operations/generated/sdk.ts
|
|
642
681
|
import gql from "graphql-tag";
|
|
682
|
+
var Blob_Activities_Constraint = /* @__PURE__ */ ((Blob_Activities_Constraint2) => {
|
|
683
|
+
Blob_Activities_Constraint2["BlobActivitiesPkey"] = "blob_activities_pkey";
|
|
684
|
+
return Blob_Activities_Constraint2;
|
|
685
|
+
})(Blob_Activities_Constraint || {});
|
|
643
686
|
var Blob_Activities_Select_Column = /* @__PURE__ */ ((Blob_Activities_Select_Column2) => {
|
|
644
|
-
Blob_Activities_Select_Column2["BlobName"] = "blob_name";
|
|
645
687
|
Blob_Activities_Select_Column2["EventIndex"] = "event_index";
|
|
646
688
|
Blob_Activities_Select_Column2["EventType"] = "event_type";
|
|
689
|
+
Blob_Activities_Select_Column2["ObjectName"] = "object_name";
|
|
647
690
|
Blob_Activities_Select_Column2["Owner"] = "owner";
|
|
648
691
|
Blob_Activities_Select_Column2["Timestamp"] = "timestamp";
|
|
649
692
|
Blob_Activities_Select_Column2["TransactionHash"] = "transaction_hash";
|
|
650
693
|
Blob_Activities_Select_Column2["TransactionVersion"] = "transaction_version";
|
|
694
|
+
Blob_Activities_Select_Column2["Uid"] = "uid";
|
|
651
695
|
return Blob_Activities_Select_Column2;
|
|
652
696
|
})(Blob_Activities_Select_Column || {});
|
|
697
|
+
var Blob_Activities_Update_Column = /* @__PURE__ */ ((Blob_Activities_Update_Column2) => {
|
|
698
|
+
Blob_Activities_Update_Column2["EventIndex"] = "event_index";
|
|
699
|
+
Blob_Activities_Update_Column2["EventType"] = "event_type";
|
|
700
|
+
Blob_Activities_Update_Column2["ObjectName"] = "object_name";
|
|
701
|
+
Blob_Activities_Update_Column2["Owner"] = "owner";
|
|
702
|
+
Blob_Activities_Update_Column2["Timestamp"] = "timestamp";
|
|
703
|
+
Blob_Activities_Update_Column2["TransactionHash"] = "transaction_hash";
|
|
704
|
+
Blob_Activities_Update_Column2["TransactionVersion"] = "transaction_version";
|
|
705
|
+
Blob_Activities_Update_Column2["Uid"] = "uid";
|
|
706
|
+
return Blob_Activities_Update_Column2;
|
|
707
|
+
})(Blob_Activities_Update_Column || {});
|
|
708
|
+
var Blobs_Constraint = /* @__PURE__ */ ((Blobs_Constraint2) => {
|
|
709
|
+
Blobs_Constraint2["BlobsPkey"] = "blobs_pkey";
|
|
710
|
+
return Blobs_Constraint2;
|
|
711
|
+
})(Blobs_Constraint || {});
|
|
653
712
|
var Blobs_Select_Column = /* @__PURE__ */ ((Blobs_Select_Column2) => {
|
|
654
713
|
Blobs_Select_Column2["BlobCommitment"] = "blob_commitment";
|
|
655
|
-
Blobs_Select_Column2["BlobName"] = "blob_name";
|
|
656
714
|
Blobs_Select_Column2["CreatedAt"] = "created_at";
|
|
715
|
+
Blobs_Select_Column2["DeletionReason"] = "deletion_reason";
|
|
716
|
+
Blobs_Select_Column2["Encoding"] = "encoding";
|
|
717
|
+
Blobs_Select_Column2["Encryption"] = "encryption";
|
|
718
|
+
Blobs_Select_Column2["Etag"] = "etag";
|
|
657
719
|
Blobs_Select_Column2["ExpiresAt"] = "expires_at";
|
|
720
|
+
Blobs_Select_Column2["IsCommitted"] = "is_committed";
|
|
658
721
|
Blobs_Select_Column2["IsDeleted"] = "is_deleted";
|
|
659
|
-
Blobs_Select_Column2["
|
|
722
|
+
Blobs_Select_Column2["IsPersisted"] = "is_persisted";
|
|
660
723
|
Blobs_Select_Column2["NumChunksets"] = "num_chunksets";
|
|
724
|
+
Blobs_Select_Column2["ObjectName"] = "object_name";
|
|
661
725
|
Blobs_Select_Column2["Owner"] = "owner";
|
|
726
|
+
Blobs_Select_Column2["PaymentAmount"] = "payment_amount";
|
|
662
727
|
Blobs_Select_Column2["PlacementGroup"] = "placement_group";
|
|
663
728
|
Blobs_Select_Column2["Size"] = "size";
|
|
664
729
|
Blobs_Select_Column2["SliceAddress"] = "slice_address";
|
|
730
|
+
Blobs_Select_Column2["Uid"] = "uid";
|
|
665
731
|
Blobs_Select_Column2["UpdatedAt"] = "updated_at";
|
|
666
732
|
return Blobs_Select_Column2;
|
|
667
733
|
})(Blobs_Select_Column || {});
|
|
734
|
+
var Blobs_Update_Column = /* @__PURE__ */ ((Blobs_Update_Column2) => {
|
|
735
|
+
Blobs_Update_Column2["BlobCommitment"] = "blob_commitment";
|
|
736
|
+
Blobs_Update_Column2["CreatedAt"] = "created_at";
|
|
737
|
+
Blobs_Update_Column2["DeletionReason"] = "deletion_reason";
|
|
738
|
+
Blobs_Update_Column2["Encoding"] = "encoding";
|
|
739
|
+
Blobs_Update_Column2["Encryption"] = "encryption";
|
|
740
|
+
Blobs_Update_Column2["Etag"] = "etag";
|
|
741
|
+
Blobs_Update_Column2["ExpiresAt"] = "expires_at";
|
|
742
|
+
Blobs_Update_Column2["IsCommitted"] = "is_committed";
|
|
743
|
+
Blobs_Update_Column2["IsDeleted"] = "is_deleted";
|
|
744
|
+
Blobs_Update_Column2["IsPersisted"] = "is_persisted";
|
|
745
|
+
Blobs_Update_Column2["NumChunksets"] = "num_chunksets";
|
|
746
|
+
Blobs_Update_Column2["ObjectName"] = "object_name";
|
|
747
|
+
Blobs_Update_Column2["Owner"] = "owner";
|
|
748
|
+
Blobs_Update_Column2["PaymentAmount"] = "payment_amount";
|
|
749
|
+
Blobs_Update_Column2["PlacementGroup"] = "placement_group";
|
|
750
|
+
Blobs_Update_Column2["Size"] = "size";
|
|
751
|
+
Blobs_Update_Column2["SliceAddress"] = "slice_address";
|
|
752
|
+
Blobs_Update_Column2["Uid"] = "uid";
|
|
753
|
+
Blobs_Update_Column2["UpdatedAt"] = "updated_at";
|
|
754
|
+
return Blobs_Update_Column2;
|
|
755
|
+
})(Blobs_Update_Column || {});
|
|
668
756
|
var Cursor_Ordering = /* @__PURE__ */ ((Cursor_Ordering2) => {
|
|
669
757
|
Cursor_Ordering2["Asc"] = "ASC";
|
|
670
758
|
Cursor_Ordering2["Desc"] = "DESC";
|
|
@@ -679,6 +767,10 @@ var Order_By = /* @__PURE__ */ ((Order_By2) => {
|
|
|
679
767
|
Order_By2["DescNullsLast"] = "desc_nulls_last";
|
|
680
768
|
return Order_By2;
|
|
681
769
|
})(Order_By || {});
|
|
770
|
+
var Placement_Group_Slots_Constraint = /* @__PURE__ */ ((Placement_Group_Slots_Constraint2) => {
|
|
771
|
+
Placement_Group_Slots_Constraint2["PlacementGroupSlotsPkey"] = "placement_group_slots_pkey";
|
|
772
|
+
return Placement_Group_Slots_Constraint2;
|
|
773
|
+
})(Placement_Group_Slots_Constraint || {});
|
|
682
774
|
var Placement_Group_Slots_Select_Column = /* @__PURE__ */ ((Placement_Group_Slots_Select_Column2) => {
|
|
683
775
|
Placement_Group_Slots_Select_Column2["PlacementGroup"] = "placement_group";
|
|
684
776
|
Placement_Group_Slots_Select_Column2["SlotIndex"] = "slot_index";
|
|
@@ -687,27 +779,49 @@ var Placement_Group_Slots_Select_Column = /* @__PURE__ */ ((Placement_Group_Slot
|
|
|
687
779
|
Placement_Group_Slots_Select_Column2["UpdatedAt"] = "updated_at";
|
|
688
780
|
return Placement_Group_Slots_Select_Column2;
|
|
689
781
|
})(Placement_Group_Slots_Select_Column || {});
|
|
782
|
+
var Placement_Group_Slots_Update_Column = /* @__PURE__ */ ((Placement_Group_Slots_Update_Column2) => {
|
|
783
|
+
Placement_Group_Slots_Update_Column2["PlacementGroup"] = "placement_group";
|
|
784
|
+
Placement_Group_Slots_Update_Column2["SlotIndex"] = "slot_index";
|
|
785
|
+
Placement_Group_Slots_Update_Column2["Status"] = "status";
|
|
786
|
+
Placement_Group_Slots_Update_Column2["StorageProvider"] = "storage_provider";
|
|
787
|
+
Placement_Group_Slots_Update_Column2["UpdatedAt"] = "updated_at";
|
|
788
|
+
return Placement_Group_Slots_Update_Column2;
|
|
789
|
+
})(Placement_Group_Slots_Update_Column || {});
|
|
790
|
+
var Processor_Status_Constraint = /* @__PURE__ */ ((Processor_Status_Constraint2) => {
|
|
791
|
+
Processor_Status_Constraint2["ProcessorStatusPkey"] = "processor_status_pkey";
|
|
792
|
+
return Processor_Status_Constraint2;
|
|
793
|
+
})(Processor_Status_Constraint || {});
|
|
690
794
|
var Processor_Status_Select_Column = /* @__PURE__ */ ((Processor_Status_Select_Column2) => {
|
|
691
795
|
Processor_Status_Select_Column2["LastSuccessVersion"] = "last_success_version";
|
|
692
796
|
Processor_Status_Select_Column2["LastTransactionTimestamp"] = "last_transaction_timestamp";
|
|
693
797
|
Processor_Status_Select_Column2["LastUpdated"] = "last_updated";
|
|
798
|
+
Processor_Status_Select_Column2["Processor"] = "processor";
|
|
694
799
|
return Processor_Status_Select_Column2;
|
|
695
800
|
})(Processor_Status_Select_Column || {});
|
|
801
|
+
var Processor_Status_Update_Column = /* @__PURE__ */ ((Processor_Status_Update_Column2) => {
|
|
802
|
+
Processor_Status_Update_Column2["LastSuccessVersion"] = "last_success_version";
|
|
803
|
+
Processor_Status_Update_Column2["LastTransactionTimestamp"] = "last_transaction_timestamp";
|
|
804
|
+
Processor_Status_Update_Column2["LastUpdated"] = "last_updated";
|
|
805
|
+
Processor_Status_Update_Column2["Processor"] = "processor";
|
|
806
|
+
return Processor_Status_Update_Column2;
|
|
807
|
+
})(Processor_Status_Update_Column || {});
|
|
696
808
|
var GetBlobsDocument = gql`
|
|
697
809
|
query getBlobs($where: blobs_bool_exp, $orderBy: [blobs_order_by!], $limit: Int, $offset: Int) {
|
|
698
810
|
blobs(where: $where, order_by: $orderBy, limit: $limit, offset: $offset) {
|
|
811
|
+
uid
|
|
812
|
+
object_name
|
|
699
813
|
owner
|
|
700
814
|
blob_commitment
|
|
701
|
-
blob_name
|
|
702
815
|
created_at
|
|
703
816
|
expires_at
|
|
817
|
+
updated_at
|
|
704
818
|
num_chunksets
|
|
705
|
-
is_deleted
|
|
706
|
-
is_written
|
|
707
|
-
placement_group
|
|
708
819
|
size
|
|
709
|
-
updated_at
|
|
710
820
|
slice_address
|
|
821
|
+
placement_group
|
|
822
|
+
is_persisted
|
|
823
|
+
is_committed
|
|
824
|
+
is_deleted
|
|
711
825
|
}
|
|
712
826
|
}
|
|
713
827
|
`;
|
|
@@ -719,7 +833,8 @@ var GetBlobActivitiesDocument = gql`
|
|
|
719
833
|
limit: $limit
|
|
720
834
|
offset: $offset
|
|
721
835
|
) {
|
|
722
|
-
|
|
836
|
+
uid
|
|
837
|
+
object_name
|
|
723
838
|
event_index
|
|
724
839
|
event_type
|
|
725
840
|
transaction_hash
|
|
@@ -865,6 +980,33 @@ var MissingTransactionSubmitterError = class extends Error {
|
|
|
865
980
|
this.name = "MissingTransactionSubmitterError";
|
|
866
981
|
}
|
|
867
982
|
};
|
|
983
|
+
var COMMIT_REJECTION_REASONS = /* @__PURE__ */ new Set([
|
|
984
|
+
"AlreadyExists",
|
|
985
|
+
"NoPriorVersion",
|
|
986
|
+
"EtagMismatch"
|
|
987
|
+
]);
|
|
988
|
+
var ObjectCommitRejectedError = class extends Error {
|
|
989
|
+
constructor(blobName, uid, reason) {
|
|
990
|
+
super(
|
|
991
|
+
`commit_object rejected the write for '${blobName}' (uid ${uid}): ${reason}`
|
|
992
|
+
);
|
|
993
|
+
this.blobName = blobName;
|
|
994
|
+
this.uid = uid;
|
|
995
|
+
this.reason = reason;
|
|
996
|
+
this.name = "ObjectCommitRejectedError";
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
function encryptionFunctionArgs(params) {
|
|
1000
|
+
if (params.omitEncryptionArg) {
|
|
1001
|
+
if (params.encryption && params.encryption !== "Unencrypted") {
|
|
1002
|
+
throw new Error(
|
|
1003
|
+
`Blob encryption (${params.encryption}) is not supported on this network: the deployed contract predates the encryption upgrade (#1739).`
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
return [];
|
|
1007
|
+
}
|
|
1008
|
+
return [blobEncryptionToMoveEnumIndex(params.encryption ?? "Unencrypted")];
|
|
1009
|
+
}
|
|
868
1010
|
var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
869
1011
|
aptos;
|
|
870
1012
|
deployer;
|
|
@@ -913,7 +1055,10 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
913
1055
|
this.aptos = new Aptos(getAptosConfig(config));
|
|
914
1056
|
this.deployer = config.deployer ?? AccountAddress2.fromString(SHELBY_DEPLOYER);
|
|
915
1057
|
this.indexer = getShelbyIndexerClient(config);
|
|
916
|
-
this.defaultOptions =
|
|
1058
|
+
this.defaultOptions = {
|
|
1059
|
+
locationHint: config.locationHint,
|
|
1060
|
+
...defaultOptions
|
|
1061
|
+
};
|
|
917
1062
|
this.orderless = config.orderless ?? false;
|
|
918
1063
|
}
|
|
919
1064
|
/**
|
|
@@ -924,7 +1069,9 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
924
1069
|
build: options?.build ?? this.defaultOptions.build,
|
|
925
1070
|
submit: options?.submit ?? this.defaultOptions.submit,
|
|
926
1071
|
usdSponsor: options?.usdSponsor ?? this.defaultOptions.usdSponsor,
|
|
927
|
-
chunksetSizeBytes: options?.chunksetSizeBytes ?? this.defaultOptions.chunksetSizeBytes
|
|
1072
|
+
chunksetSizeBytes: options?.chunksetSizeBytes ?? this.defaultOptions.chunksetSizeBytes,
|
|
1073
|
+
selectedLocation: options?.selectedLocation ?? this.defaultOptions.selectedLocation,
|
|
1074
|
+
locationHint: options?.locationHint ?? this.defaultOptions.locationHint
|
|
928
1075
|
};
|
|
929
1076
|
}
|
|
930
1077
|
/**
|
|
@@ -966,17 +1113,17 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
966
1113
|
*
|
|
967
1114
|
* @example
|
|
968
1115
|
* ```typescript
|
|
969
|
-
* const metadata = await client.
|
|
1116
|
+
* const metadata = await client.getFullObjectMetadata({
|
|
970
1117
|
* account: AccountAddress.fromString("0x1"),
|
|
971
1118
|
* name: "foo/bar.txt",
|
|
972
1119
|
* });
|
|
973
1120
|
* ```
|
|
974
1121
|
*/
|
|
975
|
-
async
|
|
1122
|
+
async getFullObjectMetadata(params) {
|
|
976
1123
|
try {
|
|
977
1124
|
const rawMetadata = await this.aptos.view({
|
|
978
1125
|
payload: {
|
|
979
|
-
function: `${this.deployer.toString()}::blob_metadata::
|
|
1126
|
+
function: `${this.deployer.toString()}::blob_metadata::get_full_object_metadata`,
|
|
980
1127
|
functionArguments: [
|
|
981
1128
|
createBlobKey({
|
|
982
1129
|
account: params.account,
|
|
@@ -988,47 +1135,94 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
988
1135
|
if (!rawMetadata?.[0]?.vec?.[0]) {
|
|
989
1136
|
return void 0;
|
|
990
1137
|
}
|
|
991
|
-
const
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
encoding = {
|
|
995
|
-
variant: "clay",
|
|
996
|
-
...ERASURE_CODE_PARAMS[metadata.encoding.__variant__],
|
|
997
|
-
...ERASURE_CODE_AND_CHUNK_MAPPING[metadata.encoding.__variant__]
|
|
998
|
-
};
|
|
999
|
-
} else if (metadata.encoding.__variant__ === "ClayCode_4Total_2Data_3Helper") {
|
|
1000
|
-
encoding = {
|
|
1001
|
-
variant: "clay",
|
|
1002
|
-
...ERASURE_CODE_PARAMS[metadata.encoding.__variant__],
|
|
1003
|
-
...ERASURE_CODE_AND_CHUNK_MAPPING[metadata.encoding.__variant__]
|
|
1004
|
-
};
|
|
1005
|
-
} else {
|
|
1006
|
-
throw new Error(
|
|
1007
|
-
"Could not parse encoding from Shelby Smart Contract, this SDK is out of date."
|
|
1008
|
-
);
|
|
1009
|
-
}
|
|
1010
|
-
return {
|
|
1011
|
-
blobMerkleRoot: Hex3.fromHexInput(
|
|
1012
|
-
metadata.blob_commitment
|
|
1013
|
-
).toUint8Array(),
|
|
1014
|
-
owner: normalizeAddress(metadata.owner),
|
|
1138
|
+
const view = rawMetadata[0].vec[0];
|
|
1139
|
+
return this.parseBlobMetadata(view.blob_metadata, {
|
|
1140
|
+
uid: BigInt(view.object_metadata.current_blob_uid),
|
|
1015
1141
|
name: params.name,
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
creationMicros: Number(metadata.creation_micros),
|
|
1021
|
-
sliceAddress: normalizeAddress(metadata.slice.inner),
|
|
1022
|
-
isWritten: metadata.is_written
|
|
1023
|
-
};
|
|
1142
|
+
// Any blob bound under an object name has cleared the commit-time
|
|
1143
|
+
// `is_written()` check, so a resolved object is always written.
|
|
1144
|
+
isWritten: true
|
|
1145
|
+
});
|
|
1024
1146
|
} catch (error) {
|
|
1025
1147
|
if (error instanceof Error && // Depending on the network, the error message may show up differently.
|
|
1026
|
-
(error.message?.includes("sub_status: Some(404)") || error.message?.includes("EBLOB_NOT_FOUND"))) {
|
|
1148
|
+
(error.message?.includes("sub_status: Some(404)") || error.message?.includes("EBLOB_NOT_FOUND") || error.message?.includes("EOBJECT_NOT_FOUND"))) {
|
|
1149
|
+
return void 0;
|
|
1150
|
+
}
|
|
1151
|
+
throw error;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* Retrieves blob metadata directly by its on-chain UID, including blobs in
|
|
1156
|
+
* the pending (registered-but-not-yet-committed) state that
|
|
1157
|
+
* {@link getFullObjectMetadata} cannot resolve by object name. Returns `undefined`
|
|
1158
|
+
* if no blob has that UID.
|
|
1159
|
+
*
|
|
1160
|
+
* The returned `name`/`blobNameSuffix` are empty: the blob layer is keyed by
|
|
1161
|
+
* UID and carries no object name (a name binding is established only at
|
|
1162
|
+
* commit). `isWritten` reflects whether the blob has been committed.
|
|
1163
|
+
*/
|
|
1164
|
+
async getFullObjectMetadataByUid(uid) {
|
|
1165
|
+
try {
|
|
1166
|
+
const rawMetadata = await this.aptos.view(
|
|
1167
|
+
{
|
|
1168
|
+
payload: {
|
|
1169
|
+
function: `${this.deployer.toString()}::blob_metadata::get_blob_metadata`,
|
|
1170
|
+
functionArguments: [uid]
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
);
|
|
1174
|
+
if (!rawMetadata?.[0]?.vec?.[0]) {
|
|
1175
|
+
return void 0;
|
|
1176
|
+
}
|
|
1177
|
+
const raw = rawMetadata[0].vec[0];
|
|
1178
|
+
return this.parseBlobMetadata(raw, {
|
|
1179
|
+
uid,
|
|
1180
|
+
name: "",
|
|
1181
|
+
isWritten: raw.state.__variant__ === "CommittedObject"
|
|
1182
|
+
});
|
|
1183
|
+
} catch (error) {
|
|
1184
|
+
if (error instanceof Error && (error.message?.includes("sub_status: Some(404)") || error.message?.includes("EBLOB_NOT_FOUND"))) {
|
|
1027
1185
|
return void 0;
|
|
1028
1186
|
}
|
|
1029
1187
|
throw error;
|
|
1030
1188
|
}
|
|
1031
1189
|
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Parse the on-chain `BlobMetadata::V1` view shape into the SDK
|
|
1192
|
+
* {@link FullObjectMetadata}. `uid` / `name` / `isWritten` are supplied by the
|
|
1193
|
+
* caller since they depend on the lookup path (by object name vs by UID).
|
|
1194
|
+
*/
|
|
1195
|
+
parseBlobMetadata(raw, extra) {
|
|
1196
|
+
const { content } = raw;
|
|
1197
|
+
const variant = content.encoding.__variant__;
|
|
1198
|
+
if (variant !== "ClayCode_16Total_10Data_13Helper" && variant !== "ClayCode_4Total_2Data_3Helper") {
|
|
1199
|
+
throw new Error(
|
|
1200
|
+
"Could not parse encoding from Shelby Smart Contract, this SDK is out of date."
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
const encoding = {
|
|
1204
|
+
variant: "clay",
|
|
1205
|
+
...ERASURE_CODE_PARAMS[variant],
|
|
1206
|
+
...ERASURE_CODE_AND_CHUNK_MAPPING[variant]
|
|
1207
|
+
};
|
|
1208
|
+
const encryption = blobEncryptionFromMoveVariant(
|
|
1209
|
+
content.encryption?.__variant__ ?? "Unencrypted"
|
|
1210
|
+
);
|
|
1211
|
+
return {
|
|
1212
|
+
uid: extra.uid,
|
|
1213
|
+
blobMerkleRoot: Hex3.fromHexInput(content.blob_commitment).toUint8Array(),
|
|
1214
|
+
owner: normalizeAddress(raw.owner),
|
|
1215
|
+
name: extra.name,
|
|
1216
|
+
blobNameSuffix: extra.name ? getBlobNameSuffix(extra.name) : "",
|
|
1217
|
+
size: Number(content.blob_size),
|
|
1218
|
+
encoding,
|
|
1219
|
+
encryption,
|
|
1220
|
+
expirationMicros: Number(raw.expiration_micros),
|
|
1221
|
+
creationMicros: Number(raw.creation_micros),
|
|
1222
|
+
sliceAddress: normalizeAddress(raw.slice.inner),
|
|
1223
|
+
isWritten: extra.isWritten
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1032
1226
|
/**
|
|
1033
1227
|
* Retrieves all the blobs and their metadata for an account from the
|
|
1034
1228
|
* blockchain.
|
|
@@ -1040,7 +1234,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1040
1234
|
*
|
|
1041
1235
|
* @example
|
|
1042
1236
|
* ```typescript
|
|
1043
|
-
* //
|
|
1237
|
+
* // FullObjectMetadata[]
|
|
1044
1238
|
* const blobs = await client.getAccountBlobs({
|
|
1045
1239
|
* account: AccountAddress.fromString("0x1"),
|
|
1046
1240
|
* });
|
|
@@ -1057,6 +1251,25 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1057
1251
|
orderBy: rest.orderBy
|
|
1058
1252
|
});
|
|
1059
1253
|
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Object-facing default filter: only committed, non-deleted, unexpired rows.
|
|
1256
|
+
* The blobs table is UID-keyed, so during an atomic overwrite a single
|
|
1257
|
+
* object_name transiently has two non-deleted rows — the currently committed
|
|
1258
|
+
* blob and the new pending (is_committed = "0") blob. Filtering on
|
|
1259
|
+
* is_committed keeps name lookups/listings pinned to the committed object and
|
|
1260
|
+
* avoids returning or duplicating the in-flight pending row. Applied to
|
|
1261
|
+
* getBlobs *and* the getBlobsCount / getTotalBlobsSize aggregates so counts
|
|
1262
|
+
* and sizes agree with the listing mid-overwrite. Callers can override any
|
|
1263
|
+
* key (e.g. is_committed) via their own `where`.
|
|
1264
|
+
*/
|
|
1265
|
+
activeBlobsWhere(where) {
|
|
1266
|
+
const defaultActiveFilter = {
|
|
1267
|
+
expires_at: { _gte: String(Date.now() * 1e3) },
|
|
1268
|
+
is_deleted: { _eq: "0" },
|
|
1269
|
+
is_committed: { _eq: "1" }
|
|
1270
|
+
};
|
|
1271
|
+
return { ...defaultActiveFilter, ...where };
|
|
1272
|
+
}
|
|
1060
1273
|
/**
|
|
1061
1274
|
* Retrieves blobs and their metadata from the blockchain.
|
|
1062
1275
|
*
|
|
@@ -1067,7 +1280,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1067
1280
|
*
|
|
1068
1281
|
* @example
|
|
1069
1282
|
* ```typescript
|
|
1070
|
-
* //
|
|
1283
|
+
* // FullObjectMetadata[]
|
|
1071
1284
|
* const blobs = await client.getBlobs({
|
|
1072
1285
|
* where: { owner: { _eq: AccountAddress.fromString("0x1").toString() } },
|
|
1073
1286
|
* });
|
|
@@ -1076,12 +1289,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1076
1289
|
async getBlobs(params = {}) {
|
|
1077
1290
|
const { limit, offset } = params.pagination ?? {};
|
|
1078
1291
|
const { orderBy, where } = params;
|
|
1079
|
-
const
|
|
1080
|
-
const defaultActiveFilter = {
|
|
1081
|
-
expires_at: { _gte: currentMicros },
|
|
1082
|
-
is_deleted: { _eq: "0" }
|
|
1083
|
-
};
|
|
1084
|
-
const finalWhere = where !== void 0 ? { ...defaultActiveFilter, ...where } : defaultActiveFilter;
|
|
1292
|
+
const finalWhere = this.activeBlobsWhere(where);
|
|
1085
1293
|
const { blobs } = await this.indexer.getBlobs({
|
|
1086
1294
|
where: finalWhere,
|
|
1087
1295
|
limit,
|
|
@@ -1090,9 +1298,10 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1090
1298
|
});
|
|
1091
1299
|
return blobs.map(
|
|
1092
1300
|
(blob) => ({
|
|
1301
|
+
uid: BigInt(blob.uid),
|
|
1093
1302
|
owner: normalizeAddress(blob.owner),
|
|
1094
|
-
name: blob.
|
|
1095
|
-
blobNameSuffix: getBlobNameSuffix(blob.
|
|
1303
|
+
name: blob.object_name,
|
|
1304
|
+
blobNameSuffix: getBlobNameSuffix(blob.object_name),
|
|
1096
1305
|
blobMerkleRoot: Hex3.fromHexInput(blob.blob_commitment).toUint8Array(),
|
|
1097
1306
|
size: Number(blob.size),
|
|
1098
1307
|
// TODO: Add encoding when supported in NCI
|
|
@@ -1104,7 +1313,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1104
1313
|
expirationMicros: Number(blob.expires_at),
|
|
1105
1314
|
creationMicros: Number(blob.created_at),
|
|
1106
1315
|
sliceAddress: normalizeAddress(blob.slice_address),
|
|
1107
|
-
isWritten: Boolean(Number(blob.
|
|
1316
|
+
isWritten: Boolean(Number(blob.is_persisted)),
|
|
1108
1317
|
isDeleted: Boolean(Number(blob.is_deleted))
|
|
1109
1318
|
})
|
|
1110
1319
|
);
|
|
@@ -1122,12 +1331,15 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1122
1331
|
[`${this.deployer.toStringLong()}::blob_metadata::BlobRegisteredEvent`]: "register_blob",
|
|
1123
1332
|
[`${this.deployer.toStringLong()}::blob_metadata::BlobDeletedEvent`]: "delete_blob",
|
|
1124
1333
|
[`${this.deployer.toStringLong()}::blob_metadata::BlobExpirationExtendedEvent`]: "extend_blob_expiration",
|
|
1125
|
-
[`${this.deployer.toStringLong()}::blob_metadata::
|
|
1334
|
+
[`${this.deployer.toStringLong()}::blob_metadata::BlobPersistedEvent`]: "write_blob",
|
|
1335
|
+
[`${this.deployer.toStringLong()}::blob_metadata::ObjectCommittedEvent`]: "commit_object",
|
|
1336
|
+
[`${this.deployer.toStringLong()}::blob_metadata::ObjectDeletedEvent`]: "delete_object",
|
|
1337
|
+
[`${this.deployer.toStringLong()}::blob_metadata::ObjectCommitRejectedEvent`]: "reject_object_commit"
|
|
1126
1338
|
};
|
|
1127
1339
|
return blob_activities.map(
|
|
1128
1340
|
(activity) => ({
|
|
1129
|
-
blobName: activity.
|
|
1130
|
-
accountAddress: normalizeAddress(activity.
|
|
1341
|
+
blobName: activity.object_name,
|
|
1342
|
+
accountAddress: normalizeAddress(activity.object_name.substring(1, 65)),
|
|
1131
1343
|
type: activityTypeMapping[activity.event_type] ?? "unknown",
|
|
1132
1344
|
eventType: activity.event_type,
|
|
1133
1345
|
eventIndex: Number(activity.event_index),
|
|
@@ -1150,9 +1362,10 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1150
1362
|
* const count = await client.getBlobsCount();
|
|
1151
1363
|
* ```
|
|
1152
1364
|
*/
|
|
1153
|
-
async getBlobsCount(params) {
|
|
1154
|
-
const {
|
|
1155
|
-
|
|
1365
|
+
async getBlobsCount(params = {}) {
|
|
1366
|
+
const { blobs_aggregate } = await this.indexer.getBlobsCount({
|
|
1367
|
+
where: this.activeBlobsWhere(params.where)
|
|
1368
|
+
});
|
|
1156
1369
|
return blobs_aggregate?.aggregate?.count ?? 0;
|
|
1157
1370
|
}
|
|
1158
1371
|
/**
|
|
@@ -1167,8 +1380,9 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1167
1380
|
* ```
|
|
1168
1381
|
*/
|
|
1169
1382
|
async getTotalBlobsSize(params = {}) {
|
|
1170
|
-
const {
|
|
1171
|
-
|
|
1383
|
+
const { blobs_aggregate } = await this.indexer.getTotalBlobsSize({
|
|
1384
|
+
where: this.activeBlobsWhere(params.where)
|
|
1385
|
+
});
|
|
1172
1386
|
return Number(blobs_aggregate?.aggregate?.sum?.size ?? 0);
|
|
1173
1387
|
}
|
|
1174
1388
|
/**
|
|
@@ -1227,12 +1441,15 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1227
1441
|
deployer: this.deployer,
|
|
1228
1442
|
account: params.account.accountAddress,
|
|
1229
1443
|
blobName: params.blobName,
|
|
1444
|
+
selectedLocation: options.selectedLocation,
|
|
1445
|
+
locationHint: options.locationHint,
|
|
1230
1446
|
blobSize: params.size,
|
|
1231
1447
|
blobMerkleRoot: params.blobMerkleRoot,
|
|
1232
1448
|
numChunksets: expectedTotalChunksets(params.size, chunksetSize),
|
|
1233
1449
|
expirationMicros: params.expirationMicros,
|
|
1234
1450
|
useSponsoredUsdVariant: options.usdSponsor !== void 0,
|
|
1235
|
-
encoding: config.enumIndex
|
|
1451
|
+
encoding: config.enumIndex,
|
|
1452
|
+
encryption: params.encryption
|
|
1236
1453
|
}),
|
|
1237
1454
|
sender: params.account.accountAddress
|
|
1238
1455
|
};
|
|
@@ -1260,16 +1477,16 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1260
1477
|
* @example
|
|
1261
1478
|
* ```typescript
|
|
1262
1479
|
*
|
|
1263
|
-
* const { transaction } = await client.
|
|
1480
|
+
* const { transaction } = await client.deleteObject({
|
|
1264
1481
|
* account: signer,
|
|
1265
1482
|
* blobName: "foo/bar.txt",
|
|
1266
1483
|
* });
|
|
1267
1484
|
* ```
|
|
1268
1485
|
*/
|
|
1269
|
-
async
|
|
1486
|
+
async deleteObject(params) {
|
|
1270
1487
|
const transaction = await this.aptos.transaction.build.simple({
|
|
1271
1488
|
options: this.orderlessTxOptions(params.options),
|
|
1272
|
-
data: _ShelbyBlobClient.
|
|
1489
|
+
data: _ShelbyBlobClient.createDeleteObjectPayload({
|
|
1273
1490
|
deployer: this.deployer,
|
|
1274
1491
|
blobName: params.blobName
|
|
1275
1492
|
}),
|
|
@@ -1285,10 +1502,6 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1285
1502
|
/**
|
|
1286
1503
|
* Deletes multiple blobs on the blockchain in a single atomic transaction.
|
|
1287
1504
|
*
|
|
1288
|
-
* **Note:** This function requires the `delete_multiple_blobs` entry function
|
|
1289
|
-
* which will be deployed to the smart contract on 2026-02-04. Using this
|
|
1290
|
-
* function before that date will result in a transaction failure.
|
|
1291
|
-
*
|
|
1292
1505
|
* This operation is atomic: if any blob deletion fails (e.g., blob not found),
|
|
1293
1506
|
* the entire transaction fails and no blobs are deleted.
|
|
1294
1507
|
*
|
|
@@ -1303,16 +1516,16 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1303
1516
|
* @example
|
|
1304
1517
|
* ```typescript
|
|
1305
1518
|
*
|
|
1306
|
-
* const { transaction } = await client.
|
|
1519
|
+
* const { transaction } = await client.deleteMultipleObjects({
|
|
1307
1520
|
* account: signer,
|
|
1308
1521
|
* blobNames: ["foo/bar.txt", "baz.txt"],
|
|
1309
1522
|
* });
|
|
1310
1523
|
* ```
|
|
1311
1524
|
*/
|
|
1312
|
-
async
|
|
1525
|
+
async deleteMultipleObjects(params) {
|
|
1313
1526
|
const transaction = await this.aptos.transaction.build.simple({
|
|
1314
1527
|
options: this.orderlessTxOptions(params.options),
|
|
1315
|
-
data: _ShelbyBlobClient.
|
|
1528
|
+
data: _ShelbyBlobClient.createDeleteMultipleObjectsPayload({
|
|
1316
1529
|
deployer: this.deployer,
|
|
1317
1530
|
blobNames: params.blobNames
|
|
1318
1531
|
}),
|
|
@@ -1370,6 +1583,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1370
1583
|
data: _ShelbyBlobClient.createBatchRegisterBlobsPayload({
|
|
1371
1584
|
deployer: this.deployer,
|
|
1372
1585
|
account: params.account.accountAddress,
|
|
1586
|
+
selectedLocation: options.selectedLocation,
|
|
1587
|
+
locationHint: options.locationHint,
|
|
1373
1588
|
expirationMicros: params.expirationMicros,
|
|
1374
1589
|
blobs: params.blobs.map((blob) => ({
|
|
1375
1590
|
blobName: blob.blobName,
|
|
@@ -1378,7 +1593,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1378
1593
|
numChunksets: expectedTotalChunksets(blob.blobSize, chunksetSize)
|
|
1379
1594
|
})),
|
|
1380
1595
|
useSponsoredUsdVariant: options.usdSponsor !== void 0,
|
|
1381
|
-
encoding: config.enumIndex
|
|
1596
|
+
encoding: config.enumIndex,
|
|
1597
|
+
encryption: params.encryption
|
|
1382
1598
|
})
|
|
1383
1599
|
};
|
|
1384
1600
|
const transaction = options.usdSponsor ? await this.aptos.transaction.build.multiAgent({
|
|
@@ -1393,6 +1609,55 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1393
1609
|
})
|
|
1394
1610
|
};
|
|
1395
1611
|
}
|
|
1612
|
+
/**
|
|
1613
|
+
* Extracts the on-chain UIDs assigned at registration from a committed
|
|
1614
|
+
* register transaction's events.
|
|
1615
|
+
*
|
|
1616
|
+
* `register_blob` / `register_multiple_blobs` create *pending* blobs and emit
|
|
1617
|
+
* one `BlobRegisteredEvent` per blob. The UID is published only on this event
|
|
1618
|
+
* (the blob is not yet in the `objects` map, so it cannot be read back by
|
|
1619
|
+
* name), so callers must parse it here before uploading bytes or committing.
|
|
1620
|
+
*
|
|
1621
|
+
* @param events - The committed transaction's events (from `waitForTransaction`).
|
|
1622
|
+
* @param deployer - The contract deployer address.
|
|
1623
|
+
* @returns One entry per registered blob, keyed by its full object name
|
|
1624
|
+
* (`@<owner>/<suffix>`, matching {@link createBlobKey}).
|
|
1625
|
+
*/
|
|
1626
|
+
static registeredBlobUids(events, deployer) {
|
|
1627
|
+
const eventType = `${deployer.toStringLong()}::blob_metadata::BlobRegisteredEvent`;
|
|
1628
|
+
return events.filter((event) => event.type === eventType).map((event) => {
|
|
1629
|
+
const data = event.data;
|
|
1630
|
+
return { objectName: data.object_name, uid: BigInt(data.uid) };
|
|
1631
|
+
});
|
|
1632
|
+
}
|
|
1633
|
+
/**
|
|
1634
|
+
* Detects whether `commit_object` rejected the write for `uid` rather than
|
|
1635
|
+
* applying it. A rejected commit is still a *successful* transaction — the
|
|
1636
|
+
* contract tears down the pending blob and emits `ObjectCommitRejectedEvent`
|
|
1637
|
+
* instead of aborting — so callers must inspect the finalized transaction's
|
|
1638
|
+
* events to tell a durable write apart from a silent no-op.
|
|
1639
|
+
*
|
|
1640
|
+
* @param events - The committed transaction's events (from `waitForTransaction`).
|
|
1641
|
+
* @param deployer - The contract deployer address.
|
|
1642
|
+
* @param uid - The UID passed to `commit_object`.
|
|
1643
|
+
* @returns The rejection reason, or `undefined` if the commit was applied.
|
|
1644
|
+
*/
|
|
1645
|
+
static findObjectCommitRejection(events, deployer, uid) {
|
|
1646
|
+
const eventType = `${deployer.toStringLong()}::blob_metadata::ObjectCommitRejectedEvent`;
|
|
1647
|
+
const rejection = events.find(
|
|
1648
|
+
(event) => event.type === eventType && BigInt(event.data.uid) === uid
|
|
1649
|
+
);
|
|
1650
|
+
if (!rejection) {
|
|
1651
|
+
return void 0;
|
|
1652
|
+
}
|
|
1653
|
+
const reason = rejection.data.rejection_reason.__variant__;
|
|
1654
|
+
if (!COMMIT_REJECTION_REASONS.has(reason)) {
|
|
1655
|
+
throw new Error(
|
|
1656
|
+
`Unrecognized ObjectCommitRejectedEvent rejection_reason '${reason}' for uid ${uid}`
|
|
1657
|
+
);
|
|
1658
|
+
}
|
|
1659
|
+
return reason;
|
|
1660
|
+
}
|
|
1396
1661
|
/**
|
|
1397
1662
|
* Creates a transaction payload to register a blob on the blockchain.
|
|
1398
1663
|
* This is a static helper method for constructing the Move function call payload.
|
|
@@ -1406,8 +1671,6 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1406
1671
|
* @param params.numChunksets - The total number of chunksets in the blob.
|
|
1407
1672
|
*
|
|
1408
1673
|
* @returns An Aptos transaction payload data object for the register_blob Move function.
|
|
1409
|
-
*
|
|
1410
|
-
* @see https://github.com/shelby/shelby/blob/e08e84742cf2b80ad8bb7227deb3013398076d53/move/shelby_contract/sources/global_metadata.move#L357
|
|
1411
1674
|
*/
|
|
1412
1675
|
static createRegisterBlobPayload(params) {
|
|
1413
1676
|
const functionName = params.useSponsoredUsdVariant ? "register_blob_with_sponsor" : "register_blob";
|
|
@@ -1415,6 +1678,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1415
1678
|
function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::${functionName}`,
|
|
1416
1679
|
functionArguments: [
|
|
1417
1680
|
params.blobName,
|
|
1681
|
+
params.selectedLocation ?? null,
|
|
1682
|
+
params.locationHint ?? null,
|
|
1418
1683
|
params.expirationMicros,
|
|
1419
1684
|
Hex3.fromHexString(params.blobMerkleRoot).toUint8Array(),
|
|
1420
1685
|
params.numChunksets,
|
|
@@ -1422,7 +1687,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1422
1687
|
// TODO
|
|
1423
1688
|
0,
|
|
1424
1689
|
// payment tier
|
|
1425
|
-
params.encoding
|
|
1690
|
+
params.encoding,
|
|
1691
|
+
...encryptionFunctionArgs(params)
|
|
1426
1692
|
]
|
|
1427
1693
|
};
|
|
1428
1694
|
}
|
|
@@ -1440,8 +1706,6 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1440
1706
|
* @param params.blobs.numChunksets - The total number of chunksets in the blob.
|
|
1441
1707
|
*
|
|
1442
1708
|
* @returns An Aptos transaction payload data object for the register_multiple_blobs Move function.
|
|
1443
|
-
*
|
|
1444
|
-
* @see https://github.com/shelby/shelby/blob/e08e84742cf2b80ad8bb7227deb3013398076d53/move/shelby_contract/sources/global_metadata.move#L357
|
|
1445
1709
|
*/
|
|
1446
1710
|
static createBatchRegisterBlobsPayload(params) {
|
|
1447
1711
|
const functionName = params.useSponsoredUsdVariant ? "register_multiple_blobs_with_sponsor" : "register_multiple_blobs";
|
|
@@ -1461,6 +1725,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1461
1725
|
function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::${functionName}`,
|
|
1462
1726
|
functionArguments: [
|
|
1463
1727
|
blobNames,
|
|
1728
|
+
params.selectedLocation ?? null,
|
|
1729
|
+
params.locationHint ?? null,
|
|
1464
1730
|
params.expirationMicros,
|
|
1465
1731
|
blobMerkleRoots,
|
|
1466
1732
|
blobNumChunksets,
|
|
@@ -1468,7 +1734,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1468
1734
|
// TODO
|
|
1469
1735
|
0,
|
|
1470
1736
|
// payment tier
|
|
1471
|
-
params.encoding
|
|
1737
|
+
params.encoding,
|
|
1738
|
+
...encryptionFunctionArgs(params)
|
|
1472
1739
|
]
|
|
1473
1740
|
};
|
|
1474
1741
|
}
|
|
@@ -1479,24 +1746,20 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1479
1746
|
* @param params.deployer - Optional deployer account address. Defaults to SHELBY_DEPLOYER.
|
|
1480
1747
|
* @param params.blobName - The blob name (e.g. "bar.txt", without the account address prefix).
|
|
1481
1748
|
*
|
|
1482
|
-
* @returns An Aptos transaction payload data object for the
|
|
1483
|
-
*
|
|
1484
|
-
* @see https://github.com/shelby/shelby/blob/64e9d7b4f0005e586faeb1e4085c79159234b6b6/move/shelby_contract/sources/global_metadata.move#L616
|
|
1749
|
+
* @returns An Aptos transaction payload data object for the delete_object Move function.
|
|
1485
1750
|
*/
|
|
1486
|
-
static
|
|
1751
|
+
static createDeleteObjectPayload(params) {
|
|
1487
1752
|
return {
|
|
1488
|
-
function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::
|
|
1489
|
-
|
|
1753
|
+
function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::delete_object`,
|
|
1754
|
+
// Second arg is `if_match_etag: Option<vector<u8>>`; `null` => None
|
|
1755
|
+
// (unconditional delete).
|
|
1756
|
+
functionArguments: [params.blobName, null]
|
|
1490
1757
|
};
|
|
1491
1758
|
}
|
|
1492
1759
|
/**
|
|
1493
1760
|
* Creates a transaction payload to delete multiple blobs on the blockchain.
|
|
1494
1761
|
* This is a static helper method for constructing the Move function call payload.
|
|
1495
1762
|
*
|
|
1496
|
-
* **Note:** This function requires the `delete_multiple_blobs` entry function
|
|
1497
|
-
* which will be deployed to the smart contract on 2026-02-04. Using this
|
|
1498
|
-
* function before that date will result in a transaction failure.
|
|
1499
|
-
*
|
|
1500
1763
|
* This operation is atomic: if any blob deletion fails (e.g., blob not found),
|
|
1501
1764
|
* the entire transaction fails and no blobs are deleted.
|
|
1502
1765
|
*
|
|
@@ -1505,42 +1768,71 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1505
1768
|
* (e.g. ["foo/bar.txt", "baz.txt"], NOT ["0x1/foo/bar.txt"]). The account address
|
|
1506
1769
|
* prefix is automatically derived from the transaction sender.
|
|
1507
1770
|
*
|
|
1508
|
-
* @returns An Aptos transaction payload data object for the
|
|
1509
|
-
*
|
|
1510
|
-
* @see https://github.com/shelby/shelby/blob/main/move/shelby_contract/sources/blob_metadata.move
|
|
1771
|
+
* @returns An Aptos transaction payload data object for the delete_multiple_objects Move function.
|
|
1511
1772
|
*/
|
|
1512
|
-
static
|
|
1773
|
+
static createDeleteMultipleObjectsPayload(params) {
|
|
1513
1774
|
return {
|
|
1514
|
-
function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::
|
|
1515
|
-
|
|
1775
|
+
function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::delete_multiple_objects`,
|
|
1776
|
+
// Second arg is `if_match_etags: vector<Option<vector<u8>>>`; an empty
|
|
1777
|
+
// vector means "no etag check on any object" (unconditional delete).
|
|
1778
|
+
functionArguments: [params.blobNames, []]
|
|
1516
1779
|
};
|
|
1517
1780
|
}
|
|
1518
|
-
|
|
1519
|
-
|
|
1781
|
+
/**
|
|
1782
|
+
* Sort acks by slot and reduce to the `(ack_bits, signatures)` pair the
|
|
1783
|
+
* contract expects: it walks the set bits low-to-high and consumes the
|
|
1784
|
+
* signatures in that same order.
|
|
1785
|
+
*/
|
|
1786
|
+
static encodeAcks(storageProviderAcks) {
|
|
1787
|
+
const sortedAcks = [...storageProviderAcks].sort((a, b) => a.slot - b.slot);
|
|
1788
|
+
const ackBitMask = sortedAcks.reduce(
|
|
1520
1789
|
(acc, ack) => acc | 1 << ack.slot,
|
|
1521
1790
|
0
|
|
1522
1791
|
);
|
|
1523
1792
|
return {
|
|
1524
|
-
|
|
1793
|
+
ackBits: new U32(Number(ackBitMask)),
|
|
1794
|
+
signatures: sortedAcks.map((ack) => ack.signature)
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
/**
|
|
1798
|
+
* Payload for `commit_object(uid, object_name_suffix, overwrite, if_match_etag,
|
|
1799
|
+
* ack_bits, signatures)` — binds a written pending blob under its object name,
|
|
1800
|
+
* finalizing the upload. SP acks may be batched in here (the contract applies
|
|
1801
|
+
* them before the `is_written` check), so register → upload → commit needs
|
|
1802
|
+
* only a single finalize transaction.
|
|
1803
|
+
*
|
|
1804
|
+
* @param params.uid - The blob UID returned at registration.
|
|
1805
|
+
* @param params.blobName - The object name suffix the blob was registered under.
|
|
1806
|
+
* @param params.overwrite - Allow replacing an existing binding under this name.
|
|
1807
|
+
* @param params.storageProviderAcks - Acks applied atomically with the commit.
|
|
1808
|
+
*/
|
|
1809
|
+
static createCommitObjectPayload(params) {
|
|
1810
|
+
const { ackBits, signatures } = _ShelbyBlobClient.encodeAcks(
|
|
1811
|
+
params.storageProviderAcks
|
|
1812
|
+
);
|
|
1813
|
+
return {
|
|
1814
|
+
function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::commit_object`,
|
|
1525
1815
|
functionArguments: [
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1816
|
+
params.uid,
|
|
1817
|
+
params.blobName,
|
|
1818
|
+
params.overwrite,
|
|
1819
|
+
// `if_match_etag: Option<vector<u8>>` is `null` => None; conditional
|
|
1820
|
+
// (CAS) writes are not yet exposed by the SDK.
|
|
1821
|
+
null,
|
|
1822
|
+
ackBits,
|
|
1823
|
+
signatures
|
|
1533
1824
|
]
|
|
1534
1825
|
};
|
|
1535
1826
|
}
|
|
1536
|
-
async
|
|
1827
|
+
async commitObject(params) {
|
|
1537
1828
|
const transaction = await this.aptos.transaction.build.simple({
|
|
1538
1829
|
...params.options?.build,
|
|
1539
1830
|
options: this.orderlessTxOptions(params.options?.build?.options),
|
|
1540
|
-
data: _ShelbyBlobClient.
|
|
1541
|
-
|
|
1831
|
+
data: _ShelbyBlobClient.createCommitObjectPayload({
|
|
1832
|
+
deployer: this.deployer,
|
|
1833
|
+
uid: params.uid,
|
|
1542
1834
|
blobName: params.blobName,
|
|
1543
|
-
|
|
1835
|
+
overwrite: params.overwrite,
|
|
1544
1836
|
storageProviderAcks: params.storageProviderAcks
|
|
1545
1837
|
}),
|
|
1546
1838
|
sender: params.account.accountAddress
|
|
@@ -1563,12 +1855,99 @@ import {
|
|
|
1563
1855
|
} from "@aptos-labs/ts-sdk";
|
|
1564
1856
|
import pLimit from "p-limit";
|
|
1565
1857
|
|
|
1858
|
+
// src/core/errors.ts
|
|
1859
|
+
var ShelbyErrorCodes = {
|
|
1860
|
+
// blob_metadata.move errors
|
|
1861
|
+
E_BLOB_NOT_FOUND: "E_BLOB_NOT_FOUND",
|
|
1862
|
+
E_INVALID_EXPIRATION_TIME: "E_INVALID_EXPIRATION_TIME",
|
|
1863
|
+
E_TEST_ENCODING_NOT_ALLOWED: "E_TEST_ENCODING_NOT_ALLOWED",
|
|
1864
|
+
E_BLOB_NOT_EXPIRED: "E_BLOB_NOT_EXPIRED",
|
|
1865
|
+
E_INVALID_CHUNKSET_COUNT: "E_INVALID_CHUNKSET_COUNT",
|
|
1866
|
+
E_NOT_BLOB_OWNER: "E_NOT_BLOB_OWNER",
|
|
1867
|
+
E_NOT_ADMIN: "E_NOT_ADMIN",
|
|
1868
|
+
E_BLOB_EXPIRED: "E_BLOB_EXPIRED",
|
|
1869
|
+
E_BLOB_NAME_TOO_LONG: "E_BLOB_NAME_TOO_LONG",
|
|
1870
|
+
E_INVALID_PAYMENT_EPOCHS: "E_INVALID_PAYMENT_EPOCHS",
|
|
1871
|
+
E_NO_SLICES_AVAILABLE: "E_NO_SLICES_AVAILABLE",
|
|
1872
|
+
// Common Aptos/Move errors
|
|
1873
|
+
EALREADY_EXISTS: "EALREADY_EXISTS"
|
|
1874
|
+
};
|
|
1875
|
+
function isBlobAlreadyExistsError(errorMessage) {
|
|
1876
|
+
return errorMessage.includes(ShelbyErrorCodes.EALREADY_EXISTS) || errorMessage.includes("already exists");
|
|
1877
|
+
}
|
|
1878
|
+
function isAccessDeniedError(errorMessage) {
|
|
1879
|
+
return errorMessage.includes(ShelbyErrorCodes.E_NOT_BLOB_OWNER) || errorMessage.includes(ShelbyErrorCodes.E_NOT_ADMIN) || errorMessage.includes("ENOT_AUTHORIZED") || errorMessage.includes("not authorized") || errorMessage.includes("permission denied");
|
|
1880
|
+
}
|
|
1881
|
+
function isBlobNotFoundError(errorMessage) {
|
|
1882
|
+
return errorMessage.includes(ShelbyErrorCodes.E_BLOB_NOT_FOUND);
|
|
1883
|
+
}
|
|
1884
|
+
function isBlobExpiredError(errorMessage) {
|
|
1885
|
+
return errorMessage.includes(ShelbyErrorCodes.E_BLOB_EXPIRED);
|
|
1886
|
+
}
|
|
1887
|
+
var ShelbyLocationErrorCodes = {
|
|
1888
|
+
E_LOCATION_NOT_FOUND: "E_LOCATION_NOT_FOUND",
|
|
1889
|
+
E_SELECTED_LOCATION_CONFLICTS_WITH_LOCK: "E_SELECTED_LOCATION_CONFLICTS_WITH_LOCK",
|
|
1890
|
+
E_NO_LOCATION_SELECTED: "E_NO_LOCATION_SELECTED",
|
|
1891
|
+
E_LOCATION_WRITES_FROZEN: "E_LOCATION_WRITES_FROZEN",
|
|
1892
|
+
E_LOCATION_NOT_ACTIVATED: "E_LOCATION_NOT_ACTIVATED"
|
|
1893
|
+
};
|
|
1894
|
+
function describeLocationError(errorMessage) {
|
|
1895
|
+
if (errorMessage.includes(ShelbyLocationErrorCodes.E_LOCATION_WRITES_FROZEN)) {
|
|
1896
|
+
return "Cannot write: the resolved location is frozen and not currently accepting new data.";
|
|
1897
|
+
}
|
|
1898
|
+
if (errorMessage.includes(ShelbyLocationErrorCodes.E_LOCATION_NOT_ACTIVATED)) {
|
|
1899
|
+
return "Cannot write: the resolved location is not activated yet.";
|
|
1900
|
+
}
|
|
1901
|
+
if (errorMessage.includes(
|
|
1902
|
+
ShelbyLocationErrorCodes.E_SELECTED_LOCATION_CONFLICTS_WITH_LOCK
|
|
1903
|
+
)) {
|
|
1904
|
+
return "Cannot write: the selected location conflicts with the account's locked location preference.";
|
|
1905
|
+
}
|
|
1906
|
+
if (errorMessage.includes(ShelbyLocationErrorCodes.E_NO_LOCATION_SELECTED)) {
|
|
1907
|
+
return "No write location could be resolved: none was selected and the account has no default location or location hint.";
|
|
1908
|
+
}
|
|
1909
|
+
if (errorMessage.includes(ShelbyLocationErrorCodes.E_LOCATION_NOT_FOUND)) {
|
|
1910
|
+
return "Cannot write: the requested location does not exist.";
|
|
1911
|
+
}
|
|
1912
|
+
return void 0;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1566
1915
|
// src/core/clients/ShelbyMetadataClient.ts
|
|
1567
1916
|
import {
|
|
1568
1917
|
AccountAddress as AccountAddress3,
|
|
1569
1918
|
Aptos as Aptos2,
|
|
1570
1919
|
Hex as Hex4
|
|
1571
1920
|
} from "@aptos-labs/ts-sdk";
|
|
1921
|
+
|
|
1922
|
+
// src/core/types/storage_providers.ts
|
|
1923
|
+
var ACTIVE_PROVIDER_CONDITIONS = [
|
|
1924
|
+
"Normal",
|
|
1925
|
+
"Faulty",
|
|
1926
|
+
"Leaving",
|
|
1927
|
+
"Evicted",
|
|
1928
|
+
"PendingLeaving"
|
|
1929
|
+
];
|
|
1930
|
+
function isActiveProviderCondition(value) {
|
|
1931
|
+
return typeof value === "string" && ACTIVE_PROVIDER_CONDITIONS.includes(value);
|
|
1932
|
+
}
|
|
1933
|
+
var TASK_ELIGIBLE_CONDITIONS = /* @__PURE__ */ new Set([
|
|
1934
|
+
"Normal",
|
|
1935
|
+
"PendingLeaving"
|
|
1936
|
+
]);
|
|
1937
|
+
function isActiveForTasks(condition) {
|
|
1938
|
+
return TASK_ELIGIBLE_CONDITIONS.has(condition);
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
// src/core/clients/ShelbyMetadataClient.ts
|
|
1942
|
+
function parseActiveProviderCondition(raw) {
|
|
1943
|
+
const variant = raw?.__variant__;
|
|
1944
|
+
if (!isActiveProviderCondition(variant)) {
|
|
1945
|
+
throw new Error(
|
|
1946
|
+
`Unknown ActiveProviderCondition variant: ${JSON.stringify(raw)}`
|
|
1947
|
+
);
|
|
1948
|
+
}
|
|
1949
|
+
return variant;
|
|
1950
|
+
}
|
|
1572
1951
|
function parseStorageProviderState(raw) {
|
|
1573
1952
|
switch (raw.__variant__) {
|
|
1574
1953
|
case "Active":
|
|
@@ -1576,8 +1955,7 @@ function parseStorageProviderState(raw) {
|
|
|
1576
1955
|
variant: "Active",
|
|
1577
1956
|
quota: raw.quota.value,
|
|
1578
1957
|
stakeAtStartOfStakingEpoch: raw.stake_at_start_of_staking_epoch,
|
|
1579
|
-
|
|
1580
|
-
leaving: raw.leaving
|
|
1958
|
+
condition: parseActiveProviderCondition(raw.condition)
|
|
1581
1959
|
};
|
|
1582
1960
|
case "Waitlisted":
|
|
1583
1961
|
return {
|
|
@@ -1590,6 +1968,10 @@ function parseStorageProviderState(raw) {
|
|
|
1590
1968
|
frozenFrom: raw.frozen_from,
|
|
1591
1969
|
frozenTill: raw.frozen_till
|
|
1592
1970
|
};
|
|
1971
|
+
default:
|
|
1972
|
+
throw new Error(
|
|
1973
|
+
`Unknown StorageProviderStateDetails variant: ${JSON.stringify(raw)}`
|
|
1974
|
+
);
|
|
1593
1975
|
}
|
|
1594
1976
|
}
|
|
1595
1977
|
var ShelbyMetadataClient = class {
|
|
@@ -1648,28 +2030,52 @@ var ShelbyMetadataClient = class {
|
|
|
1648
2030
|
}
|
|
1649
2031
|
}
|
|
1650
2032
|
/**
|
|
1651
|
-
* Retrieves the
|
|
2033
|
+
* Retrieves the names of every activated location (region). Locations that are
|
|
2034
|
+
* registered but not yet brought online are admin-internal and not listed.
|
|
2035
|
+
*
|
|
2036
|
+
* @returns The location name list.
|
|
2037
|
+
*
|
|
2038
|
+
* @example
|
|
2039
|
+
* ```typescript
|
|
2040
|
+
* const locations = await client.getLocationNames();
|
|
2041
|
+
* ```
|
|
2042
|
+
*/
|
|
2043
|
+
async getLocationNames() {
|
|
2044
|
+
const names = await this.aptos.view({
|
|
2045
|
+
payload: {
|
|
2046
|
+
function: `${this.deployer.toString()}::location::activated_location_names`,
|
|
2047
|
+
functionArguments: []
|
|
2048
|
+
}
|
|
2049
|
+
});
|
|
2050
|
+
return names[0];
|
|
2051
|
+
}
|
|
2052
|
+
/**
|
|
2053
|
+
* Retrieves the list of placement group addresses in a location.
|
|
1652
2054
|
*
|
|
2055
|
+
* @param locationName - The location whose placement groups to list.
|
|
1653
2056
|
* @returns The placement group address list, or an empty array if none exist.
|
|
1654
2057
|
*
|
|
1655
2058
|
* @example
|
|
1656
2059
|
* ```typescript
|
|
1657
|
-
* const pgList = await client.getPlacementGroupAddresses();
|
|
2060
|
+
* const pgList = await client.getPlacementGroupAddresses("us-east-1");
|
|
1658
2061
|
* ```
|
|
1659
2062
|
*/
|
|
1660
|
-
async getPlacementGroupAddresses() {
|
|
2063
|
+
async getPlacementGroupAddresses(locationName) {
|
|
1661
2064
|
try {
|
|
1662
2065
|
const pgSizeMetadata = await this.aptos.view({
|
|
1663
2066
|
payload: {
|
|
1664
2067
|
function: `${this.deployer.toString()}::placement_group_registry::get_number_of_placement_groups`,
|
|
1665
|
-
functionArguments: []
|
|
2068
|
+
functionArguments: [locationName]
|
|
1666
2069
|
}
|
|
1667
2070
|
});
|
|
2071
|
+
if (Number(pgSizeMetadata[0]) === 0) {
|
|
2072
|
+
return [];
|
|
2073
|
+
}
|
|
1668
2074
|
const finalPlacementGroupIndex = pgSizeMetadata[0] - 1;
|
|
1669
2075
|
const addressMetadataArray = await this.aptos.view({
|
|
1670
2076
|
payload: {
|
|
1671
2077
|
function: `${this.deployer.toString()}::placement_group_registry::get_placement_group_addresses`,
|
|
1672
|
-
functionArguments: [0, finalPlacementGroupIndex]
|
|
2078
|
+
functionArguments: [locationName, 0, finalPlacementGroupIndex]
|
|
1673
2079
|
}
|
|
1674
2080
|
});
|
|
1675
2081
|
const metadata = addressMetadataArray[0];
|
|
@@ -1683,28 +2089,32 @@ var ShelbyMetadataClient = class {
|
|
|
1683
2089
|
}
|
|
1684
2090
|
}
|
|
1685
2091
|
/**
|
|
1686
|
-
* Retrieves the list of slice addresses.
|
|
2092
|
+
* Retrieves the list of slice addresses in a location.
|
|
1687
2093
|
*
|
|
2094
|
+
* @param locationName - The location whose slices to list.
|
|
1688
2095
|
* @returns The slice group list, or an empty array if none exist.
|
|
1689
2096
|
*
|
|
1690
2097
|
* @example
|
|
1691
2098
|
* ```typescript
|
|
1692
|
-
* const pgList = await client.getSliceAddresses();
|
|
2099
|
+
* const pgList = await client.getSliceAddresses("us-east-1");
|
|
1693
2100
|
* ```
|
|
1694
2101
|
*/
|
|
1695
|
-
async getSliceAddresses() {
|
|
2102
|
+
async getSliceAddresses(locationName) {
|
|
1696
2103
|
try {
|
|
1697
2104
|
const sliceSizeMetadata = await this.aptos.view({
|
|
1698
2105
|
payload: {
|
|
1699
2106
|
function: `${this.deployer.toString()}::slice_registry::get_number_of_slices`,
|
|
1700
|
-
functionArguments: []
|
|
2107
|
+
functionArguments: [locationName]
|
|
1701
2108
|
}
|
|
1702
2109
|
});
|
|
2110
|
+
if (Number(sliceSizeMetadata[0]) === 0) {
|
|
2111
|
+
return [];
|
|
2112
|
+
}
|
|
1703
2113
|
const finalSliceIndex = sliceSizeMetadata[0] - 1;
|
|
1704
2114
|
const addressMetadataArray = await this.aptos.view({
|
|
1705
2115
|
payload: {
|
|
1706
2116
|
function: `${this.deployer.toString()}::slice_registry::get_slice_addresses`,
|
|
1707
|
-
functionArguments: [0, finalSliceIndex]
|
|
2117
|
+
functionArguments: [locationName, 0, finalSliceIndex]
|
|
1708
2118
|
}
|
|
1709
2119
|
});
|
|
1710
2120
|
const metadata = addressMetadataArray[0];
|
|
@@ -1764,6 +2174,36 @@ var ShelbyMetadataClient = class {
|
|
|
1764
2174
|
(opt) => opt.vec.length > 0 ? normalizeAddress(opt.vec[0]) : null
|
|
1765
2175
|
);
|
|
1766
2176
|
}
|
|
2177
|
+
/**
|
|
2178
|
+
* Retrieves the active storage providers for a slice.
|
|
2179
|
+
*
|
|
2180
|
+
* Active SPs have a complete copy of the data for the slot, and are not in any data transfer/repair/reconstruction phase.
|
|
2181
|
+
* Active SP can be audited for the data it contains.
|
|
2182
|
+
* Each slot has at most one active SP.
|
|
2183
|
+
*
|
|
2184
|
+
* @param params.account - The address of the slice account.
|
|
2185
|
+
* @returns An array where result[i] is the active SP for slot i, or null if no SP is active.
|
|
2186
|
+
*
|
|
2187
|
+
* @example
|
|
2188
|
+
* ```typescript
|
|
2189
|
+
* const providers = await client.getActiveStorageProvidersForSlice({ account: sliceAddress });
|
|
2190
|
+
* ```
|
|
2191
|
+
*/
|
|
2192
|
+
async getActiveStorageProvidersForSlice(params) {
|
|
2193
|
+
const placementGroupAddress = await this.getPlacementGroupAddressForSlice(
|
|
2194
|
+
params.account
|
|
2195
|
+
);
|
|
2196
|
+
const rawMetadata = await this.aptos.view({
|
|
2197
|
+
payload: {
|
|
2198
|
+
function: `${this.deployer.toString()}::placement_group::get_active_storage_providers`,
|
|
2199
|
+
functionArguments: [placementGroupAddress]
|
|
2200
|
+
}
|
|
2201
|
+
});
|
|
2202
|
+
const providers = rawMetadata[0];
|
|
2203
|
+
return providers.map(
|
|
2204
|
+
(opt) => opt.vec.length > 0 ? normalizeAddress(opt.vec[0]) : null
|
|
2205
|
+
);
|
|
2206
|
+
}
|
|
1767
2207
|
/**
|
|
1768
2208
|
* Retrieves the serving storage providers for a slice.
|
|
1769
2209
|
*
|
|
@@ -1852,22 +2292,6 @@ var ChallengeResponseSchema = z3.object({
|
|
|
1852
2292
|
challenge: z3.string(),
|
|
1853
2293
|
expiresAt: z3.number()
|
|
1854
2294
|
});
|
|
1855
|
-
var MultipartUploadStatusResponseSchema = z3.object({
|
|
1856
|
-
uploadId: z3.string(),
|
|
1857
|
-
completedParts: z3.array(z3.number()),
|
|
1858
|
-
partSize: z3.number(),
|
|
1859
|
-
nParts: z3.number(),
|
|
1860
|
-
uploadedBytes: z3.number()
|
|
1861
|
-
});
|
|
1862
|
-
var StartMultipartUploadResponseSchema = z3.object({
|
|
1863
|
-
uploadId: z3.string()
|
|
1864
|
-
});
|
|
1865
|
-
var UploadPartResponseSchema = z3.object({
|
|
1866
|
-
success: z3.literal(true)
|
|
1867
|
-
});
|
|
1868
|
-
var CompleteMultipartUploadResponseSchema = z3.object({
|
|
1869
|
-
success: z3.literal(true)
|
|
1870
|
-
});
|
|
1871
2295
|
var RPCErrorResponseSchema = z3.object({
|
|
1872
2296
|
error: z3.string()
|
|
1873
2297
|
});
|
|
@@ -2084,6 +2508,7 @@ var BLOB_OWNER_AUTH_SCHEME_HEADER = "X-Shelby-Auth-Scheme";
|
|
|
2084
2508
|
var BLOB_OWNER_IDENTITY_HEADER = "X-Shelby-Identity";
|
|
2085
2509
|
var BLOB_OWNER_DOMAIN_HEADER = "X-Shelby-Domain";
|
|
2086
2510
|
var BLOB_OWNER_AUTH_FUNCTION_HEADER = "X-Shelby-Auth-Function";
|
|
2511
|
+
var INCLUSION_PROOF_HEADER = "X-Shelby-Inclusion-Proof";
|
|
2087
2512
|
function buildAuthHeaders(auth) {
|
|
2088
2513
|
const signatureBase64 = btoa(
|
|
2089
2514
|
Array.from(auth.signature, (byte) => String.fromCharCode(byte)).join("")
|
|
@@ -2107,6 +2532,58 @@ function buildAuthHeaders(auth) {
|
|
|
2107
2532
|
function encodeURIComponentKeepSlashes(str) {
|
|
2108
2533
|
return encodeURIComponent(str).replace(/%2F/g, "/");
|
|
2109
2534
|
}
|
|
2535
|
+
async function generateChunksetInclusionProof(chunksetRoots, chunksetIndex) {
|
|
2536
|
+
if (chunksetRoots.length === 0) {
|
|
2537
|
+
throw new Error("Cannot generate inclusion proof for empty chunkset roots");
|
|
2538
|
+
}
|
|
2539
|
+
if (chunksetIndex < 0 || chunksetIndex >= chunksetRoots.length) {
|
|
2540
|
+
throw new Error(
|
|
2541
|
+
`Chunkset index ${chunksetIndex} out of range [0, ${chunksetRoots.length})`
|
|
2542
|
+
);
|
|
2543
|
+
}
|
|
2544
|
+
if (chunksetRoots.length === 1) {
|
|
2545
|
+
return [];
|
|
2546
|
+
}
|
|
2547
|
+
const zeroHash = new Uint8Array(32);
|
|
2548
|
+
const siblings = [];
|
|
2549
|
+
let currentLeaves = chunksetRoots.map((h) => h.toUint8Array());
|
|
2550
|
+
let currentIdx = chunksetIndex;
|
|
2551
|
+
while (currentLeaves.length > 1) {
|
|
2552
|
+
if (currentLeaves.length % 2 !== 0) {
|
|
2553
|
+
currentLeaves.push(zeroHash);
|
|
2554
|
+
}
|
|
2555
|
+
const siblingIdx = currentIdx % 2 === 0 ? currentIdx + 1 : currentIdx - 1;
|
|
2556
|
+
siblings.push(currentLeaves[siblingIdx]);
|
|
2557
|
+
const nextLeaves = [];
|
|
2558
|
+
for (let i = 0; i < currentLeaves.length; i += 2) {
|
|
2559
|
+
const combined = await concatHashes([
|
|
2560
|
+
currentLeaves[i],
|
|
2561
|
+
currentLeaves[i + 1]
|
|
2562
|
+
]);
|
|
2563
|
+
nextLeaves.push(combined.toUint8Array());
|
|
2564
|
+
}
|
|
2565
|
+
currentLeaves = nextLeaves;
|
|
2566
|
+
currentIdx = Math.floor(currentIdx / 2);
|
|
2567
|
+
}
|
|
2568
|
+
return siblings;
|
|
2569
|
+
}
|
|
2570
|
+
function encodeInclusionProof(siblings) {
|
|
2571
|
+
if (siblings.length === 0) {
|
|
2572
|
+
return "NONE";
|
|
2573
|
+
}
|
|
2574
|
+
const totalBytes = siblings.length * 32;
|
|
2575
|
+
const combined = new Uint8Array(totalBytes);
|
|
2576
|
+
let offset = 0;
|
|
2577
|
+
for (const sibling of siblings) {
|
|
2578
|
+
combined.set(sibling, offset);
|
|
2579
|
+
offset += 32;
|
|
2580
|
+
}
|
|
2581
|
+
const binaryString = Array.from(
|
|
2582
|
+
combined,
|
|
2583
|
+
(byte) => String.fromCharCode(byte)
|
|
2584
|
+
).join("");
|
|
2585
|
+
return btoa(binaryString);
|
|
2586
|
+
}
|
|
2110
2587
|
function validateTotalBytes(totalBytes) {
|
|
2111
2588
|
if (!Number.isInteger(totalBytes) || totalBytes < 0) {
|
|
2112
2589
|
throw new Error("totalBytes must be a non-negative integer");
|
|
@@ -2138,7 +2615,7 @@ var ShelbyRPCClient = class {
|
|
|
2138
2615
|
* @param config - The client configuration object.
|
|
2139
2616
|
* @param config.network - The Shelby network to use.
|
|
2140
2617
|
* @param options.signChallengeHandler - Optional override for challenge
|
|
2141
|
-
* signing. When set, `
|
|
2618
|
+
* signing. When set, `putBlobChunksets` uses this instead of the built-in
|
|
2142
2619
|
* `signChallenge`. Intended for kit-level overrides (e.g. Solana DAA).
|
|
2143
2620
|
*
|
|
2144
2621
|
* @example
|
|
@@ -2189,43 +2666,6 @@ var ShelbyRPCClient = class {
|
|
|
2189
2666
|
}
|
|
2190
2667
|
return ChallengeResponseSchema.parse(await response.json());
|
|
2191
2668
|
}
|
|
2192
|
-
/**
|
|
2193
|
-
* Check if there's an existing multipart upload for a blob.
|
|
2194
|
-
* Returns the upload status including which parts have been uploaded.
|
|
2195
|
-
*
|
|
2196
|
-
* @param account - The account that owns the blob.
|
|
2197
|
-
* @param blobName - The name of the blob.
|
|
2198
|
-
* @returns The upload status, or undefined if no pending upload exists.
|
|
2199
|
-
*
|
|
2200
|
-
* @example
|
|
2201
|
-
* ```typescript
|
|
2202
|
-
* const status = await client.getMultipartUploadStatus(account, "myblob.txt");
|
|
2203
|
-
* if (status) {
|
|
2204
|
-
* console.log(`Resuming upload ${status.uploadId}, ${status.completedParts.length} parts done`);
|
|
2205
|
-
* }
|
|
2206
|
-
* ```
|
|
2207
|
-
*/
|
|
2208
|
-
async getMultipartUploadStatus(account, blobName) {
|
|
2209
|
-
const url = new URL(buildRequestUrl("/v1/multipart-uploads", this.baseUrl));
|
|
2210
|
-
url.searchParams.set("account", account.toString());
|
|
2211
|
-
url.searchParams.set("blobName", blobName);
|
|
2212
|
-
const response = await fetch(url.toString(), {
|
|
2213
|
-
method: "GET",
|
|
2214
|
-
headers: {
|
|
2215
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
2216
|
-
}
|
|
2217
|
-
});
|
|
2218
|
-
if (response.status === 404) {
|
|
2219
|
-
return void 0;
|
|
2220
|
-
}
|
|
2221
|
-
if (!response.ok) {
|
|
2222
|
-
const errorBody = await response.text().catch(() => "");
|
|
2223
|
-
throw new Error(
|
|
2224
|
-
`Failed to get multipart upload status: status ${response.status}, body: ${errorBody}`
|
|
2225
|
-
);
|
|
2226
|
-
}
|
|
2227
|
-
return MultipartUploadStatusResponseSchema.parse(await response.json());
|
|
2228
|
-
}
|
|
2229
2669
|
/**
|
|
2230
2670
|
* Sign a challenge using the given account and return auth credentials.
|
|
2231
2671
|
*
|
|
@@ -2242,164 +2682,142 @@ var ShelbyRPCClient = class {
|
|
|
2242
2682
|
publicKey: account.publicKey.toUint8Array()
|
|
2243
2683
|
};
|
|
2244
2684
|
}
|
|
2245
|
-
|
|
2246
|
-
|
|
2685
|
+
/**
|
|
2686
|
+
* Upload a single chunkset via the v2 chunkset API.
|
|
2687
|
+
*/
|
|
2688
|
+
async #uploadChunkset(params) {
|
|
2689
|
+
const maxNonBusyRetries = 5;
|
|
2247
2690
|
let lastResponse;
|
|
2248
2691
|
let lastError;
|
|
2249
2692
|
let attempts = 0;
|
|
2250
|
-
|
|
2251
|
-
|
|
2693
|
+
let consecutive429s = 0;
|
|
2694
|
+
let nonBusyRetries = 0;
|
|
2695
|
+
const chunksetUrl = buildRequestUrl(
|
|
2696
|
+
`/v2/chunksets/${params.account}/${params.chunksetIndex}/${params.uid}`,
|
|
2252
2697
|
this.baseUrl
|
|
2253
2698
|
);
|
|
2254
|
-
|
|
2699
|
+
const authHeaders = buildAuthHeaders(params.auth);
|
|
2700
|
+
while (true) {
|
|
2701
|
+
if (params.signal?.aborted) {
|
|
2702
|
+
throw new DOMException("Upload aborted", "AbortError");
|
|
2703
|
+
}
|
|
2255
2704
|
attempts++;
|
|
2256
2705
|
try {
|
|
2257
|
-
lastResponse = await fetch(
|
|
2706
|
+
lastResponse = await fetch(chunksetUrl, {
|
|
2258
2707
|
method: "PUT",
|
|
2259
2708
|
headers: {
|
|
2260
2709
|
"Content-Type": "application/octet-stream",
|
|
2261
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
2710
|
+
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {},
|
|
2711
|
+
...authHeaders,
|
|
2712
|
+
[INCLUSION_PROOF_HEADER]: params.inclusionProof
|
|
2262
2713
|
},
|
|
2263
|
-
body:
|
|
2714
|
+
body: params.chunksetData,
|
|
2715
|
+
signal: params.signal
|
|
2264
2716
|
});
|
|
2265
2717
|
lastError = void 0;
|
|
2266
2718
|
} catch (error) {
|
|
2719
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
2720
|
+
throw error;
|
|
2721
|
+
}
|
|
2267
2722
|
lastError = error;
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2723
|
+
consecutive429s = 0;
|
|
2724
|
+
nonBusyRetries++;
|
|
2725
|
+
if (nonBusyRetries < maxNonBusyRetries) {
|
|
2726
|
+
const delay2 = 2 ** nonBusyRetries * 100;
|
|
2727
|
+
await sleep(delay2);
|
|
2271
2728
|
continue;
|
|
2272
2729
|
}
|
|
2273
2730
|
break;
|
|
2274
2731
|
}
|
|
2275
|
-
if (lastResponse.ok)
|
|
2732
|
+
if (lastResponse.ok) {
|
|
2733
|
+
const json = await lastResponse.json();
|
|
2734
|
+
const spAcks = json.spAcks?.map((ack) => ({
|
|
2735
|
+
slot: ack.slot,
|
|
2736
|
+
signature: Uint8Array.from(
|
|
2737
|
+
atob(ack.signature),
|
|
2738
|
+
(c) => c.charCodeAt(0)
|
|
2739
|
+
)
|
|
2740
|
+
}));
|
|
2741
|
+
return {
|
|
2742
|
+
success: json.success,
|
|
2743
|
+
acksReceived: json.acksReceived,
|
|
2744
|
+
spAcks
|
|
2745
|
+
};
|
|
2746
|
+
}
|
|
2747
|
+
if (lastResponse.status === 429) {
|
|
2748
|
+
consecutive429s++;
|
|
2749
|
+
const baseDelay = 500;
|
|
2750
|
+
const jitter = Math.random() * 200;
|
|
2751
|
+
const delay2 = Math.min(
|
|
2752
|
+
3e4,
|
|
2753
|
+
2 ** consecutive429s * baseDelay + jitter
|
|
2754
|
+
);
|
|
2755
|
+
await sleep(delay2);
|
|
2756
|
+
continue;
|
|
2757
|
+
}
|
|
2758
|
+
consecutive429s = 0;
|
|
2276
2759
|
if (!isRetryableStatus(lastResponse.status)) {
|
|
2277
2760
|
break;
|
|
2278
2761
|
}
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2762
|
+
nonBusyRetries++;
|
|
2763
|
+
if (nonBusyRetries >= maxNonBusyRetries) {
|
|
2764
|
+
break;
|
|
2282
2765
|
}
|
|
2766
|
+
const delay = 2 ** nonBusyRetries * 100;
|
|
2767
|
+
await sleep(delay);
|
|
2283
2768
|
}
|
|
2284
2769
|
if (lastError !== void 0) {
|
|
2285
2770
|
const errorCode = getErrorCode(lastError);
|
|
2286
2771
|
const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);
|
|
2287
2772
|
throw new Error(
|
|
2288
|
-
`Failed to upload
|
|
2773
|
+
`Failed to upload chunkset ${params.chunksetIndex} after ${attempts} attempt${attempts === 1 ? "" : "s"}. ${errorCode ? `(${errorCode}) ` : ""}Last error: ${errorMessage}`,
|
|
2289
2774
|
{ cause: lastError }
|
|
2290
2775
|
);
|
|
2291
2776
|
}
|
|
2292
2777
|
const errorBody = await lastResponse?.text().catch(() => "");
|
|
2293
2778
|
throw new Error(
|
|
2294
|
-
`Failed to upload
|
|
2779
|
+
`Failed to upload chunkset ${params.chunksetIndex} after ${attempts} attempt${attempts === 1 ? "" : "s"}. status: ${lastResponse?.status}, body: ${errorBody}`
|
|
2295
2780
|
);
|
|
2296
2781
|
}
|
|
2297
|
-
async #putBlobMultipart(account, blobName, blobData, totalBytes, partSize = 5 * 1024 * 1024, onProgress) {
|
|
2298
|
-
validateTotalBytes(totalBytes);
|
|
2299
|
-
const startResponse = await fetch(
|
|
2300
|
-
buildRequestUrl("/v1/multipart-uploads", this.baseUrl),
|
|
2301
|
-
{
|
|
2302
|
-
method: "POST",
|
|
2303
|
-
headers: {
|
|
2304
|
-
"Content-Type": "application/json",
|
|
2305
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
2306
|
-
},
|
|
2307
|
-
body: JSON.stringify({
|
|
2308
|
-
rawAccount: account.toString(),
|
|
2309
|
-
rawBlobName: blobName,
|
|
2310
|
-
rawPartSize: partSize
|
|
2311
|
-
})
|
|
2312
|
-
}
|
|
2313
|
-
);
|
|
2314
|
-
if (!startResponse.ok) {
|
|
2315
|
-
let errorBodyText = "Could not read error body";
|
|
2316
|
-
try {
|
|
2317
|
-
errorBodyText = await startResponse.text();
|
|
2318
|
-
} catch (_e) {
|
|
2319
|
-
}
|
|
2320
|
-
throw new Error(
|
|
2321
|
-
`Failed to start multipart upload! status: ${startResponse.status}, body: ${errorBodyText}`
|
|
2322
|
-
);
|
|
2323
|
-
}
|
|
2324
|
-
const { uploadId } = StartMultipartUploadResponseSchema.parse(
|
|
2325
|
-
await startResponse.json()
|
|
2326
|
-
);
|
|
2327
|
-
const totalParts = Math.ceil(totalBytes / partSize);
|
|
2328
|
-
let uploadedBytes = 0;
|
|
2329
|
-
for await (const [partIdx, partData] of readInChunks(blobData, partSize)) {
|
|
2330
|
-
await this.#uploadPart(uploadId, partIdx, partData);
|
|
2331
|
-
uploadedBytes += partData.length;
|
|
2332
|
-
onProgress?.({
|
|
2333
|
-
phase: "uploading",
|
|
2334
|
-
partIdx,
|
|
2335
|
-
totalParts,
|
|
2336
|
-
partBytes: partData.length,
|
|
2337
|
-
uploadedBytes,
|
|
2338
|
-
totalBytes
|
|
2339
|
-
});
|
|
2340
|
-
}
|
|
2341
|
-
if (uploadedBytes !== totalBytes) {
|
|
2342
|
-
throw new Error(
|
|
2343
|
-
`Uploaded bytes (${uploadedBytes}) did not match declared totalBytes (${totalBytes})`
|
|
2344
|
-
);
|
|
2345
|
-
}
|
|
2346
|
-
const finalPartIdx = totalParts > 0 ? totalParts - 1 : 0;
|
|
2347
|
-
onProgress?.({
|
|
2348
|
-
phase: "finalizing",
|
|
2349
|
-
partIdx: finalPartIdx,
|
|
2350
|
-
totalParts,
|
|
2351
|
-
// no part uploaded in this phase
|
|
2352
|
-
partBytes: 0,
|
|
2353
|
-
uploadedBytes: totalBytes,
|
|
2354
|
-
totalBytes
|
|
2355
|
-
});
|
|
2356
|
-
const completeResponse = await fetch(
|
|
2357
|
-
buildRequestUrl(
|
|
2358
|
-
`/v1/multipart-uploads/${uploadId}/complete`,
|
|
2359
|
-
this.baseUrl
|
|
2360
|
-
),
|
|
2361
|
-
{
|
|
2362
|
-
method: "POST",
|
|
2363
|
-
headers: {
|
|
2364
|
-
"Content-Type": "application/json",
|
|
2365
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
2366
|
-
}
|
|
2367
|
-
}
|
|
2368
|
-
);
|
|
2369
|
-
if (!completeResponse.ok) {
|
|
2370
|
-
let errorBodyText = "Could not read error body";
|
|
2371
|
-
try {
|
|
2372
|
-
errorBodyText = await completeResponse.text();
|
|
2373
|
-
} catch (_e) {
|
|
2374
|
-
}
|
|
2375
|
-
throw new Error(
|
|
2376
|
-
`Failed to complete multipart upload! status: ${completeResponse.status}, body: ${errorBodyText}`
|
|
2377
|
-
);
|
|
2378
|
-
}
|
|
2379
|
-
}
|
|
2380
2782
|
/**
|
|
2381
|
-
* Uploads blob data to the Shelby RPC node
|
|
2382
|
-
* This method
|
|
2383
|
-
*
|
|
2783
|
+
* Uploads blob data to the Shelby RPC node using the v2 chunkset API.
|
|
2784
|
+
* This method authenticates using challenge-response and uploads chunksets
|
|
2785
|
+
* directly to storage providers via the RPC's worker pool.
|
|
2384
2786
|
*
|
|
2385
|
-
*
|
|
2386
|
-
*
|
|
2787
|
+
* This method:
|
|
2788
|
+
* - Sends raw chunkset data directly to the RPC for erasure encoding
|
|
2789
|
+
* - Requires pre-computed blob commitments to generate inclusion proofs
|
|
2790
|
+
* - Does not support resume (each chunkset is idempotent on the SP side)
|
|
2791
|
+
*
|
|
2792
|
+
* @param params.account - The Aptos Account (with signing capability) that owns the blob.
|
|
2793
|
+
* @param params.uid - The blob's on-chain UID (from `BlobRegisteredEvent` at registration).
|
|
2387
2794
|
* @param params.blobData - The raw blob data as a Uint8Array or ReadableStream.
|
|
2795
|
+
* @param params.commitments - Pre-computed blob commitments (from generateCommitments).
|
|
2388
2796
|
* @param params.totalBytes - Total byte length. Required for streams; optional for Uint8Array.
|
|
2797
|
+
* @param params.chunksetConcurrency - Number of chunksets to upload in parallel. Defaults to 4.
|
|
2798
|
+
* @param params.onProgress - Optional callback for upload progress.
|
|
2799
|
+
* @param params.signal - Optional AbortSignal for cancellation. When aborted, in-flight
|
|
2800
|
+
* HTTP requests are cancelled and an AbortError is thrown.
|
|
2389
2801
|
*
|
|
2390
2802
|
* @example
|
|
2391
2803
|
* ```typescript
|
|
2392
|
-
*
|
|
2804
|
+
* // First, generate commitments for the blob
|
|
2805
|
+
* const commitments = await generateCommitments(provider, fileData);
|
|
2393
2806
|
*
|
|
2394
|
-
*
|
|
2395
|
-
*
|
|
2396
|
-
*
|
|
2397
|
-
*
|
|
2807
|
+
* // Register the blob on chain, then read its UID from the register tx's
|
|
2808
|
+
* // BlobRegisteredEvent (see ShelbyBlobClient.registeredBlobUids).
|
|
2809
|
+
*
|
|
2810
|
+
* // Upload using chunkset API
|
|
2811
|
+
* await rpcClient.putBlobChunksets({
|
|
2812
|
+
* account: myAccount,
|
|
2813
|
+
* uid: blobUid,
|
|
2814
|
+
* blobData: fileData,
|
|
2815
|
+
* commitments,
|
|
2816
|
+
* chunksetConcurrency: 8,
|
|
2398
2817
|
* });
|
|
2399
2818
|
* ```
|
|
2400
2819
|
*/
|
|
2401
|
-
async
|
|
2402
|
-
BlobNameSchema.parse(params.blobName);
|
|
2820
|
+
async putBlobChunksets(params) {
|
|
2403
2821
|
let totalBytes;
|
|
2404
2822
|
if (params.blobData instanceof Uint8Array) {
|
|
2405
2823
|
totalBytes = params.totalBytes ?? params.blobData.length;
|
|
@@ -2417,215 +2835,146 @@ var ShelbyRPCClient = class {
|
|
|
2417
2835
|
totalBytes = params.totalBytes;
|
|
2418
2836
|
}
|
|
2419
2837
|
validateTotalBytes(totalBytes);
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
totalBytes,
|
|
2425
|
-
void 0,
|
|
2426
|
-
params.onProgress
|
|
2427
|
-
);
|
|
2428
|
-
}
|
|
2429
|
-
/**
|
|
2430
|
-
* Upload a part with authentication headers.
|
|
2431
|
-
*/
|
|
2432
|
-
async #uploadPartWithAuth(uploadId, partIdx, partData, auth) {
|
|
2433
|
-
const nRetries = 5;
|
|
2434
|
-
let lastResponse;
|
|
2435
|
-
let lastError;
|
|
2436
|
-
let attempts = 0;
|
|
2437
|
-
const partUrl = buildRequestUrl(
|
|
2438
|
-
`/v1/multipart-uploads/${uploadId}/parts/${partIdx}`,
|
|
2439
|
-
this.baseUrl
|
|
2440
|
-
);
|
|
2441
|
-
const authHeaders = buildAuthHeaders(auth);
|
|
2442
|
-
for (let i = 0; i < nRetries; ++i) {
|
|
2443
|
-
attempts++;
|
|
2444
|
-
try {
|
|
2445
|
-
lastResponse = await fetch(partUrl, {
|
|
2446
|
-
method: "PUT",
|
|
2447
|
-
headers: {
|
|
2448
|
-
"Content-Type": "application/octet-stream",
|
|
2449
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {},
|
|
2450
|
-
...authHeaders
|
|
2451
|
-
},
|
|
2452
|
-
body: partData
|
|
2453
|
-
});
|
|
2454
|
-
lastError = void 0;
|
|
2455
|
-
} catch (error) {
|
|
2456
|
-
lastError = error;
|
|
2457
|
-
if (i < nRetries - 1) {
|
|
2458
|
-
const delay = 2 ** i * 100;
|
|
2459
|
-
await sleep(delay);
|
|
2460
|
-
continue;
|
|
2461
|
-
}
|
|
2462
|
-
break;
|
|
2463
|
-
}
|
|
2464
|
-
if (lastResponse.ok) return;
|
|
2465
|
-
if (!isRetryableStatus(lastResponse.status)) {
|
|
2466
|
-
break;
|
|
2467
|
-
}
|
|
2468
|
-
if (i < nRetries - 1) {
|
|
2469
|
-
const delay = 2 ** i * 100;
|
|
2470
|
-
await sleep(delay);
|
|
2471
|
-
}
|
|
2472
|
-
}
|
|
2473
|
-
if (lastError !== void 0) {
|
|
2474
|
-
const errorCode = getErrorCode(lastError);
|
|
2475
|
-
const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);
|
|
2838
|
+
const chunksetConcurrency = params.chunksetConcurrency ?? 4;
|
|
2839
|
+
const totalChunksets = params.commitments.chunkset_commitments.length;
|
|
2840
|
+
const rawDataSizeFromCommitments = params.commitments.raw_data_size;
|
|
2841
|
+
if (rawDataSizeFromCommitments !== totalBytes) {
|
|
2476
2842
|
throw new Error(
|
|
2477
|
-
`
|
|
2478
|
-
{ cause: lastError }
|
|
2843
|
+
`Data size mismatch: commitments were generated for ${rawDataSizeFromCommitments} bytes, but totalBytes=${totalBytes}. This will cause inclusion proof verification to fail.`
|
|
2479
2844
|
);
|
|
2480
2845
|
}
|
|
2481
|
-
const
|
|
2482
|
-
|
|
2483
|
-
`Failed to upload part ${partIdx} for multipart upload ${uploadId} after ${attempts} attempt${attempts === 1 ? "" : "s"}. status: ${lastResponse?.status}, body: ${errorBody}`
|
|
2846
|
+
const chunksetRoots = params.commitments.chunkset_commitments.map(
|
|
2847
|
+
(c) => Hex6.fromHexString(c.chunkset_root)
|
|
2484
2848
|
);
|
|
2485
|
-
}
|
|
2486
|
-
/**
|
|
2487
|
-
* Uploads blob data to the Shelby RPC node with authentication and resume support.
|
|
2488
|
-
* This method authenticates using challenge-response and can resume interrupted uploads.
|
|
2489
|
-
*
|
|
2490
|
-
* @param params.account - The Aptos Account (with signing capability) that owns the blob.
|
|
2491
|
-
* @param params.blobName - The name/path of the blob (e.g. "folder/file.txt").
|
|
2492
|
-
* @param params.blobData - The raw blob data as a Uint8Array or ReadableStream.
|
|
2493
|
-
* @param params.totalBytes - Total byte length. Required for streams; optional for Uint8Array.
|
|
2494
|
-
* @param params.onProgress - Optional callback for upload progress.
|
|
2495
|
-
*
|
|
2496
|
-
* @example
|
|
2497
|
-
* ```typescript
|
|
2498
|
-
* await client.putBlobResumable({
|
|
2499
|
-
* account: myAccount, // Aptos Account with signing capability
|
|
2500
|
-
* blobName: "documents/report.pdf",
|
|
2501
|
-
* blobData: fileData,
|
|
2502
|
-
* totalBytes: fileData.length,
|
|
2503
|
-
* });
|
|
2504
|
-
* ```
|
|
2505
|
-
*/
|
|
2506
|
-
async putBlobResumable(params) {
|
|
2507
|
-
BlobNameSchema.parse(params.blobName);
|
|
2508
|
-
let totalBytes;
|
|
2509
|
-
if (params.blobData instanceof Uint8Array) {
|
|
2510
|
-
totalBytes = params.totalBytes ?? params.blobData.length;
|
|
2511
|
-
if (totalBytes !== params.blobData.length) {
|
|
2512
|
-
throw new Error(
|
|
2513
|
-
"totalBytes must match blobData.length when blobData is a Uint8Array"
|
|
2514
|
-
);
|
|
2515
|
-
}
|
|
2516
|
-
} else {
|
|
2517
|
-
if (params.totalBytes === void 0) {
|
|
2518
|
-
throw new Error(
|
|
2519
|
-
"totalBytes is required when blobData is a ReadableStream"
|
|
2520
|
-
);
|
|
2521
|
-
}
|
|
2522
|
-
totalBytes = params.totalBytes;
|
|
2523
|
-
}
|
|
2524
|
-
validateTotalBytes(totalBytes);
|
|
2525
|
-
const partSize = params.partSize ?? 5 * 1024 * 1024;
|
|
2526
2849
|
const { challenge } = await this.getChallenge(
|
|
2527
2850
|
params.account.accountAddress
|
|
2528
2851
|
);
|
|
2529
2852
|
const signFn = this.#signChallengeOverride ?? this.signChallenge.bind(this);
|
|
2530
2853
|
const auth = signFn(params.account, challenge);
|
|
2531
|
-
const
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
uploadId = existingUpload.uploadId;
|
|
2541
|
-
completedPartsSet = new Set(existingUpload.completedParts);
|
|
2542
|
-
totalParts = existingUpload.nParts;
|
|
2543
|
-
if (existingUpload.partSize !== partSize) {
|
|
2544
|
-
throw new Error(
|
|
2545
|
-
`Cannot resume upload: part size mismatch. Existing upload uses ${existingUpload.partSize} bytes, but ${partSize} was requested.`
|
|
2546
|
-
);
|
|
2547
|
-
}
|
|
2548
|
-
} else {
|
|
2549
|
-
const startResponse = await fetch(
|
|
2550
|
-
buildRequestUrl("/v1/multipart-uploads", this.baseUrl),
|
|
2551
|
-
{
|
|
2552
|
-
method: "POST",
|
|
2553
|
-
headers: {
|
|
2554
|
-
"Content-Type": "application/json",
|
|
2555
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {},
|
|
2556
|
-
...authHeaders
|
|
2557
|
-
},
|
|
2558
|
-
body: JSON.stringify({
|
|
2559
|
-
rawAccount: params.account.accountAddress.toString(),
|
|
2560
|
-
rawBlobName: params.blobName,
|
|
2561
|
-
rawPartSize: partSize
|
|
2562
|
-
})
|
|
2563
|
-
}
|
|
2854
|
+
const firstChunkset = params.commitments.chunkset_commitments[0];
|
|
2855
|
+
if (!firstChunkset) {
|
|
2856
|
+
throw new Error("Commitments must have at least one chunkset");
|
|
2857
|
+
}
|
|
2858
|
+
const erasure_n = firstChunkset.chunk_commitments.length;
|
|
2859
|
+
const matchingEntry = findErasureSchemeByErasureN(erasure_n);
|
|
2860
|
+
if (!matchingEntry) {
|
|
2861
|
+
throw new Error(
|
|
2862
|
+
`Unknown erasure coding scheme with erasure_n=${erasure_n}`
|
|
2564
2863
|
);
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2864
|
+
}
|
|
2865
|
+
const [schemeKey, matchingParams] = matchingEntry;
|
|
2866
|
+
const erasure_k = matchingParams.erasure_k;
|
|
2867
|
+
const { chunkSizeBytes } = ERASURE_CODE_AND_CHUNK_MAPPING[schemeKey];
|
|
2868
|
+
const chunksetSize = erasure_k * chunkSizeBytes;
|
|
2869
|
+
const expectedChunksetCount = totalBytes === 0 ? 1 : Math.ceil(totalBytes / chunksetSize);
|
|
2870
|
+
if (expectedChunksetCount !== totalChunksets) {
|
|
2871
|
+
throw new Error(
|
|
2872
|
+
`Chunkset count mismatch: expected ${expectedChunksetCount} chunksets for ${totalBytes} bytes with chunksetSize=${chunksetSize}, but commitments have ${totalChunksets} chunksets. This suggests the commitments were generated with a different encoding scheme.`
|
|
2573
2873
|
);
|
|
2574
|
-
uploadId = parsed.uploadId;
|
|
2575
|
-
completedPartsSet = /* @__PURE__ */ new Set();
|
|
2576
|
-
totalParts = Math.ceil(totalBytes / partSize);
|
|
2577
2874
|
}
|
|
2578
2875
|
let uploadedBytes = 0;
|
|
2579
|
-
let
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
if (completedPartsSet.has(partIdx)) {
|
|
2586
|
-
uploadedBytes += partData.length;
|
|
2587
|
-
continue;
|
|
2876
|
+
let bytesReadFromSource = 0;
|
|
2877
|
+
const inFlight = /* @__PURE__ */ new Set();
|
|
2878
|
+
async function* chunksetsFromBlob() {
|
|
2879
|
+
if (totalBytes === 0) {
|
|
2880
|
+
yield [0, new Uint8Array(chunksetSize)];
|
|
2881
|
+
return;
|
|
2588
2882
|
}
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2883
|
+
yield* readInChunks(params.blobData, chunksetSize);
|
|
2884
|
+
}
|
|
2885
|
+
const chunksetIterator = chunksetsFromBlob();
|
|
2886
|
+
const aggregatedAcks = /* @__PURE__ */ new Map();
|
|
2887
|
+
const internalAbort = new AbortController();
|
|
2888
|
+
if (params.signal?.aborted) {
|
|
2889
|
+
internalAbort.abort();
|
|
2890
|
+
} else if (params.signal) {
|
|
2891
|
+
params.signal.addEventListener("abort", () => internalAbort.abort(), {
|
|
2892
|
+
once: true
|
|
2598
2893
|
});
|
|
2599
2894
|
}
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
...authHeaders
|
|
2895
|
+
let iteratorDone = false;
|
|
2896
|
+
let firstError = null;
|
|
2897
|
+
while (!iteratorDone || inFlight.size > 0) {
|
|
2898
|
+
if (internalAbort.signal.aborted) {
|
|
2899
|
+
throw firstError ?? new DOMException("Upload aborted", "AbortError");
|
|
2900
|
+
}
|
|
2901
|
+
while (inFlight.size < chunksetConcurrency && !iteratorDone) {
|
|
2902
|
+
const { value, done } = await chunksetIterator.next();
|
|
2903
|
+
if (done) {
|
|
2904
|
+
iteratorDone = true;
|
|
2905
|
+
break;
|
|
2906
|
+
}
|
|
2907
|
+
const [chunksetIdx, chunksetData] = value;
|
|
2908
|
+
bytesReadFromSource += totalBytes === 0 ? 0 : chunksetData.byteLength;
|
|
2909
|
+
const expectedCommitment = params.commitments.chunkset_commitments[chunksetIdx];
|
|
2910
|
+
if (!expectedCommitment) {
|
|
2911
|
+
throw new Error(
|
|
2912
|
+
`Chunkset index ${chunksetIdx} out of range. Commitments only have ${totalChunksets} chunksets. This suggests a chunkset size mismatch between commitment generation and upload.`
|
|
2913
|
+
);
|
|
2620
2914
|
}
|
|
2915
|
+
const proofSiblings = await generateChunksetInclusionProof(
|
|
2916
|
+
chunksetRoots,
|
|
2917
|
+
chunksetIdx
|
|
2918
|
+
);
|
|
2919
|
+
const inclusionProof = encodeInclusionProof(proofSiblings);
|
|
2920
|
+
const chunksetDataCopy = new Uint8Array(chunksetData);
|
|
2921
|
+
const chunksetBytes = chunksetDataCopy.length;
|
|
2922
|
+
const uploadPromise = (async () => {
|
|
2923
|
+
const result = await this.#uploadChunkset({
|
|
2924
|
+
account: params.account.accountAddress.toString(),
|
|
2925
|
+
uid: params.uid,
|
|
2926
|
+
chunksetIndex: chunksetIdx,
|
|
2927
|
+
inclusionProof,
|
|
2928
|
+
chunksetData: chunksetDataCopy,
|
|
2929
|
+
auth,
|
|
2930
|
+
signal: internalAbort.signal
|
|
2931
|
+
});
|
|
2932
|
+
const chunksetSpAcks = result.spAcks?.map((ack) => ({
|
|
2933
|
+
slot: ack.slot,
|
|
2934
|
+
signature: ack.signature
|
|
2935
|
+
}));
|
|
2936
|
+
if (chunksetSpAcks) {
|
|
2937
|
+
for (const ack of chunksetSpAcks) {
|
|
2938
|
+
aggregatedAcks.set(ack.slot, ack.signature);
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
uploadedBytes += chunksetBytes;
|
|
2942
|
+
params.onProgress?.({
|
|
2943
|
+
phase: "uploading",
|
|
2944
|
+
chunksetIdx,
|
|
2945
|
+
totalChunksets,
|
|
2946
|
+
chunksetBytes,
|
|
2947
|
+
uploadedBytes,
|
|
2948
|
+
totalBytes,
|
|
2949
|
+
acksReceived: result.acksReceived,
|
|
2950
|
+
spAcks: chunksetSpAcks
|
|
2951
|
+
});
|
|
2952
|
+
})().catch((err) => {
|
|
2953
|
+
if (!firstError) {
|
|
2954
|
+
firstError = err;
|
|
2955
|
+
internalAbort.abort();
|
|
2956
|
+
}
|
|
2957
|
+
}).finally(() => {
|
|
2958
|
+
inFlight.delete(uploadPromise);
|
|
2959
|
+
});
|
|
2960
|
+
inFlight.add(uploadPromise);
|
|
2621
2961
|
}
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2962
|
+
if (inFlight.size > 0) {
|
|
2963
|
+
await Promise.race(inFlight);
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
if (firstError) {
|
|
2967
|
+
throw firstError;
|
|
2968
|
+
}
|
|
2969
|
+
if (bytesReadFromSource !== totalBytes) {
|
|
2625
2970
|
throw new Error(
|
|
2626
|
-
`
|
|
2971
|
+
`Data source produced ${bytesReadFromSource} bytes, but expected ${totalBytes} bytes. The stream may have ended prematurely, resulting in an incomplete upload.`
|
|
2627
2972
|
);
|
|
2628
2973
|
}
|
|
2974
|
+
const spAcks = Array.from(
|
|
2975
|
+
aggregatedAcks.entries()
|
|
2976
|
+
).map(([slot, signature]) => ({ slot, signature }));
|
|
2977
|
+
return { spAcks };
|
|
2629
2978
|
}
|
|
2630
2979
|
/**
|
|
2631
2980
|
* Downloads a blob from the Shelby RPC node.
|
|
@@ -2877,6 +3226,59 @@ var ShelbyClient = class {
|
|
|
2877
3226
|
}
|
|
2878
3227
|
return this._provider;
|
|
2879
3228
|
}
|
|
3229
|
+
/**
|
|
3230
|
+
* Build orderless transaction options (a random replay-protection nonce) for
|
|
3231
|
+
* the per-blob commit transactions. batchUpload finalizes blobs
|
|
3232
|
+
* concurrently, so without orderless replay protection the parallel
|
|
3233
|
+
* same-account submissions collide on the sequence number ("transaction
|
|
3234
|
+
* already in mempool with a different payload"). The nonce makes each commit
|
|
3235
|
+
* independent regardless of the client's `orderless` config flag.
|
|
3236
|
+
*/
|
|
3237
|
+
orderlessCommitOptions() {
|
|
3238
|
+
return {
|
|
3239
|
+
build: {
|
|
3240
|
+
options: {
|
|
3241
|
+
replayProtectionNonce: crypto.getRandomValues(new Uint32Array(1))[0]
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
};
|
|
3245
|
+
}
|
|
3246
|
+
/**
|
|
3247
|
+
* Resolve the on-chain UID assigned to `blobName` from a committed register
|
|
3248
|
+
* transaction. `register_blob` only publishes the uid -> name mapping via
|
|
3249
|
+
* `BlobRegisteredEvent` (a pending blob is not yet in the `objects` map, so it
|
|
3250
|
+
* cannot be read back by name), so the upload flow must parse it here before
|
|
3251
|
+
* uploading bytes or committing.
|
|
3252
|
+
*/
|
|
3253
|
+
uidFromRegisterTx(tx, account, blobName) {
|
|
3254
|
+
const events = "events" in tx ? tx.events : [];
|
|
3255
|
+
const objectName = createBlobKey({ account, blobName });
|
|
3256
|
+
const match = ShelbyBlobClient.registeredBlobUids(
|
|
3257
|
+
events,
|
|
3258
|
+
this.coordination.deployer
|
|
3259
|
+
).find((registered) => registered.objectName === objectName);
|
|
3260
|
+
if (match === void 0) {
|
|
3261
|
+
throw new Error(
|
|
3262
|
+
`No BlobRegisteredEvent for '${blobName}' in register transaction ${tx.hash}`
|
|
3263
|
+
);
|
|
3264
|
+
}
|
|
3265
|
+
return match.uid;
|
|
3266
|
+
}
|
|
3267
|
+
/**
|
|
3268
|
+
* Await a blob-registration transaction, rephrasing on-chain location
|
|
3269
|
+
* failures into a human-readable message.
|
|
3270
|
+
*/
|
|
3271
|
+
async waitForRegistration(transactionHash) {
|
|
3272
|
+
try {
|
|
3273
|
+
return await this.coordination.aptos.waitForTransaction({
|
|
3274
|
+
transactionHash
|
|
3275
|
+
});
|
|
3276
|
+
} catch (error) {
|
|
3277
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3278
|
+
const described = describeLocationError(message);
|
|
3279
|
+
throw described ? new Error(described, { cause: error }) : error;
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
2880
3282
|
/**
|
|
2881
3283
|
* The base URL for the Shelby RPC node.
|
|
2882
3284
|
*/
|
|
@@ -2890,8 +3292,8 @@ var ShelbyClient = class {
|
|
|
2890
3292
|
*
|
|
2891
3293
|
* Note: This method accepts only `Uint8Array` and buffers the entire blob in memory.
|
|
2892
3294
|
* For streaming uploads of large files (e.g. >2 GiB), orchestrate the steps manually
|
|
2893
|
-
* using `generateCommitments()`, `coordination.registerBlob()`,
|
|
2894
|
-
* with a `ReadableStream`.
|
|
3295
|
+
* using `generateCommitments()`, `coordination.registerBlob()`, `rpc.putBlobChunksets()`,
|
|
3296
|
+
* and `coordination.commitObject()` with a `ReadableStream`.
|
|
2895
3297
|
*
|
|
2896
3298
|
* @param params.blobData - The raw data to upload as a Uint8Array.
|
|
2897
3299
|
* @param params.signer - The account that signs and pays for the transaction.
|
|
@@ -2914,34 +3316,57 @@ var ShelbyClient = class {
|
|
|
2914
3316
|
* ```
|
|
2915
3317
|
*/
|
|
2916
3318
|
async upload(params) {
|
|
2917
|
-
const
|
|
2918
|
-
|
|
2919
|
-
|
|
3319
|
+
const provider = await this.getProvider();
|
|
3320
|
+
const blobCommitments = await generateCommitments(
|
|
3321
|
+
provider,
|
|
3322
|
+
params.blobData
|
|
3323
|
+
);
|
|
3324
|
+
const { transaction: pendingRegisterBlobTransaction } = await this.coordination.registerBlob({
|
|
3325
|
+
account: params.signer,
|
|
3326
|
+
blobName: params.blobName,
|
|
3327
|
+
blobMerkleRoot: blobCommitments.blob_merkle_root,
|
|
3328
|
+
size: params.blobData.length,
|
|
3329
|
+
expirationMicros: params.expirationMicros,
|
|
3330
|
+
config: provider.config,
|
|
3331
|
+
options: params.options
|
|
3332
|
+
});
|
|
3333
|
+
const registerTx = await this.waitForRegistration(
|
|
3334
|
+
pendingRegisterBlobTransaction.hash
|
|
3335
|
+
);
|
|
3336
|
+
const uid = this.uidFromRegisterTx(
|
|
3337
|
+
registerTx,
|
|
3338
|
+
params.signer.accountAddress,
|
|
3339
|
+
params.blobName
|
|
3340
|
+
);
|
|
3341
|
+
const { spAcks } = await this.rpc.putBlobChunksets({
|
|
3342
|
+
account: params.signer,
|
|
3343
|
+
uid,
|
|
3344
|
+
blobData: params.blobData,
|
|
3345
|
+
commitments: blobCommitments,
|
|
3346
|
+
totalBytes: params.blobData.length
|
|
2920
3347
|
});
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
provider,
|
|
2925
|
-
params.blobData
|
|
3348
|
+
const requiredAcks = requiredAckCount(provider.config.erasure_n);
|
|
3349
|
+
if (spAcks.length < requiredAcks) {
|
|
3350
|
+
throw new Error(
|
|
3351
|
+
`Insufficient storage provider acknowledgements for '${params.blobName}': got ${spAcks.length}, need ${requiredAcks} (erasure_d) to finalize on chain`
|
|
2926
3352
|
);
|
|
2927
|
-
const { transaction: pendingRegisterBlobTransaction } = await this.coordination.registerBlob({
|
|
2928
|
-
account: params.signer,
|
|
2929
|
-
blobName: params.blobName,
|
|
2930
|
-
blobMerkleRoot: blobCommitments.blob_merkle_root,
|
|
2931
|
-
size: params.blobData.length,
|
|
2932
|
-
expirationMicros: params.expirationMicros,
|
|
2933
|
-
config: provider.config,
|
|
2934
|
-
options: params.options
|
|
2935
|
-
});
|
|
2936
|
-
await this.coordination.aptos.waitForTransaction({
|
|
2937
|
-
transactionHash: pendingRegisterBlobTransaction.hash
|
|
2938
|
-
});
|
|
2939
3353
|
}
|
|
2940
|
-
await this.
|
|
3354
|
+
const { transaction: pendingCommitTransaction } = await this.coordination.commitObject({
|
|
2941
3355
|
account: params.signer,
|
|
3356
|
+
uid,
|
|
2942
3357
|
blobName: params.blobName,
|
|
2943
|
-
|
|
3358
|
+
overwrite: true,
|
|
3359
|
+
storageProviderAcks: spAcks,
|
|
3360
|
+
options: this.orderlessCommitOptions()
|
|
2944
3361
|
});
|
|
3362
|
+
const confirmedTx = await this.coordination.aptos.waitForTransaction({
|
|
3363
|
+
transactionHash: pendingCommitTransaction.hash
|
|
3364
|
+
});
|
|
3365
|
+
if (!confirmedTx.success) {
|
|
3366
|
+
throw new Error(
|
|
3367
|
+
`commit_object tx failed for '${params.blobName}': ${confirmedTx.vm_status}`
|
|
3368
|
+
);
|
|
3369
|
+
}
|
|
2945
3370
|
}
|
|
2946
3371
|
/**
|
|
2947
3372
|
* Uploads a batch of blobs to the Shelby network.
|
|
@@ -2950,8 +3375,8 @@ var ShelbyClient = class {
|
|
|
2950
3375
|
*
|
|
2951
3376
|
* Note: This method accepts only `Uint8Array` and buffers each blob in memory.
|
|
2952
3377
|
* For streaming uploads of large files, orchestrate the steps manually using
|
|
2953
|
-
* `generateCommitments()`, `coordination.registerBlob()`,
|
|
2954
|
-
* with a `ReadableStream`.
|
|
3378
|
+
* `generateCommitments()`, `coordination.registerBlob()`, `rpc.putBlobChunksets()`,
|
|
3379
|
+
* and `coordination.commitObject()` with a `ReadableStream`.
|
|
2955
3380
|
*
|
|
2956
3381
|
* @param params.blobs - The blobs to upload.
|
|
2957
3382
|
* @param params.blobs.blobData - The raw data to upload as a Uint8Array.
|
|
@@ -2976,59 +3401,77 @@ var ShelbyClient = class {
|
|
|
2976
3401
|
* ```
|
|
2977
3402
|
*/
|
|
2978
3403
|
async batchUpload(params) {
|
|
2979
|
-
const
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
3404
|
+
const provider = await this.getProvider();
|
|
3405
|
+
const prepared = await Promise.all(
|
|
3406
|
+
params.blobs.map(async (blob) => ({
|
|
3407
|
+
blob,
|
|
3408
|
+
commitments: await generateCommitments(provider, blob.blobData)
|
|
3409
|
+
}))
|
|
3410
|
+
);
|
|
3411
|
+
const { transaction: pendingRegisterBlobTransaction } = await this.coordination.batchRegisterBlobs({
|
|
3412
|
+
account: params.signer,
|
|
3413
|
+
expirationMicros: params.expirationMicros,
|
|
3414
|
+
blobs: prepared.map((p) => ({
|
|
3415
|
+
blobName: p.blob.blobName,
|
|
3416
|
+
blobSize: p.blob.blobData.length,
|
|
3417
|
+
blobMerkleRoot: p.commitments.blob_merkle_root
|
|
3418
|
+
})),
|
|
3419
|
+
config: provider.config,
|
|
3420
|
+
options: params.options
|
|
2990
3421
|
});
|
|
2991
|
-
const
|
|
2992
|
-
|
|
2993
|
-
(existingBlob) => existingBlob.name === createBlobKey({
|
|
2994
|
-
account: params.signer.accountAddress,
|
|
2995
|
-
blobName: blob.blobName
|
|
2996
|
-
})
|
|
2997
|
-
)
|
|
3422
|
+
const registerTx = await this.waitForRegistration(
|
|
3423
|
+
pendingRegisterBlobTransaction.hash
|
|
2998
3424
|
);
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
const { transaction: pendingRegisterBlobTransaction } = await this.coordination.batchRegisterBlobs({
|
|
3007
|
-
account: params.signer,
|
|
3008
|
-
expirationMicros: params.expirationMicros,
|
|
3009
|
-
blobs: blobsToRegister.map((blob, index) => ({
|
|
3010
|
-
blobName: blob.blobName,
|
|
3011
|
-
blobSize: blob.blobData.length,
|
|
3012
|
-
blobMerkleRoot: blobCommitments[index].blob_merkle_root
|
|
3013
|
-
})),
|
|
3014
|
-
config: provider.config,
|
|
3015
|
-
options: params.options
|
|
3016
|
-
});
|
|
3017
|
-
await this.coordination.aptos.waitForTransaction({
|
|
3018
|
-
transactionHash: pendingRegisterBlobTransaction.hash,
|
|
3019
|
-
options: { waitForIndexer: true }
|
|
3020
|
-
});
|
|
3021
|
-
}
|
|
3425
|
+
const uidByObjectName = new Map(
|
|
3426
|
+
ShelbyBlobClient.registeredBlobUids(
|
|
3427
|
+
"events" in registerTx ? registerTx.events : [],
|
|
3428
|
+
this.coordination.deployer
|
|
3429
|
+
).map((registered) => [registered.objectName, registered.uid])
|
|
3430
|
+
);
|
|
3431
|
+
const requiredAcks = requiredAckCount(provider.config.erasure_n);
|
|
3022
3432
|
const limit = pLimit(3);
|
|
3023
3433
|
await Promise.all(
|
|
3024
|
-
|
|
3025
|
-
(
|
|
3026
|
-
|
|
3434
|
+
prepared.map(
|
|
3435
|
+
(p) => limit(async () => {
|
|
3436
|
+
const objectName = createBlobKey({
|
|
3437
|
+
account: params.signer.accountAddress,
|
|
3438
|
+
blobName: p.blob.blobName
|
|
3439
|
+
});
|
|
3440
|
+
const uid = uidByObjectName.get(objectName);
|
|
3441
|
+
if (uid === void 0) {
|
|
3442
|
+
throw new Error(
|
|
3443
|
+
`No BlobRegisteredEvent for '${p.blob.blobName}' in batch register transaction ${registerTx.hash}`
|
|
3444
|
+
);
|
|
3445
|
+
}
|
|
3446
|
+
const { spAcks } = await this.rpc.putBlobChunksets({
|
|
3027
3447
|
account: params.signer,
|
|
3028
|
-
|
|
3029
|
-
blobData: blob.blobData
|
|
3030
|
-
|
|
3031
|
-
|
|
3448
|
+
uid,
|
|
3449
|
+
blobData: p.blob.blobData,
|
|
3450
|
+
commitments: p.commitments,
|
|
3451
|
+
totalBytes: p.blob.blobData.length
|
|
3452
|
+
});
|
|
3453
|
+
if (spAcks.length < requiredAcks) {
|
|
3454
|
+
throw new Error(
|
|
3455
|
+
`Insufficient storage provider acknowledgements for '${p.blob.blobName}': got ${spAcks.length}, need ${requiredAcks} (erasure_d) to finalize on chain`
|
|
3456
|
+
);
|
|
3457
|
+
}
|
|
3458
|
+
const { transaction: pendingCommitTransaction } = await this.coordination.commitObject({
|
|
3459
|
+
account: params.signer,
|
|
3460
|
+
uid,
|
|
3461
|
+
blobName: p.blob.blobName,
|
|
3462
|
+
overwrite: true,
|
|
3463
|
+
storageProviderAcks: spAcks,
|
|
3464
|
+
options: this.orderlessCommitOptions()
|
|
3465
|
+
});
|
|
3466
|
+
const confirmedTx = await this.coordination.aptos.waitForTransaction({
|
|
3467
|
+
transactionHash: pendingCommitTransaction.hash
|
|
3468
|
+
});
|
|
3469
|
+
if (!confirmedTx.success) {
|
|
3470
|
+
throw new Error(
|
|
3471
|
+
`commit_object tx failed for '${p.blob.blobName}': ${confirmedTx.vm_status}`
|
|
3472
|
+
);
|
|
3473
|
+
}
|
|
3474
|
+
})
|
|
3032
3475
|
)
|
|
3033
3476
|
);
|
|
3034
3477
|
}
|
|
@@ -3274,6 +3717,58 @@ var ShelbyMicropaymentChannelClient = class _ShelbyMicropaymentChannelClient {
|
|
|
3274
3717
|
]
|
|
3275
3718
|
};
|
|
3276
3719
|
}
|
|
3720
|
+
/**
|
|
3721
|
+
* Withdraws funds from a micropayment channel as the sender.
|
|
3722
|
+
*
|
|
3723
|
+
* @param params.sender - The account that is withdrawing funds.
|
|
3724
|
+
* @param params.receiver - The account the channel is configured to send funds to.
|
|
3725
|
+
* @param params.fungibleAssetAddress - The account address of the fungible asset.
|
|
3726
|
+
* @param params.options - Optional transaction generation options.
|
|
3727
|
+
*
|
|
3728
|
+
* @returns An object containing the pending transaction.
|
|
3729
|
+
*
|
|
3730
|
+
* @example
|
|
3731
|
+
* ```typescript
|
|
3732
|
+
* const { transaction } = await client.senderWithdraw({
|
|
3733
|
+
* sender: sender,
|
|
3734
|
+
* receiver: receiver,
|
|
3735
|
+
* fungibleAssetAddress: fungibleAssetAddress,
|
|
3736
|
+
* });
|
|
3737
|
+
* ```
|
|
3738
|
+
*/
|
|
3739
|
+
async senderWithdraw(params) {
|
|
3740
|
+
const transaction = await this.aptos.transaction.build.simple({
|
|
3741
|
+
options: params.options,
|
|
3742
|
+
data: _ShelbyMicropaymentChannelClient.createSenderWithdrawPayload({
|
|
3743
|
+
deployer: this.deployer,
|
|
3744
|
+
receiver: params.receiver,
|
|
3745
|
+
fungibleAssetAddress: params.fungibleAssetAddress
|
|
3746
|
+
}),
|
|
3747
|
+
sender: params.sender.accountAddress
|
|
3748
|
+
});
|
|
3749
|
+
return {
|
|
3750
|
+
transaction: await this.aptos.signAndSubmitTransaction({
|
|
3751
|
+
signer: params.sender,
|
|
3752
|
+
transaction
|
|
3753
|
+
})
|
|
3754
|
+
};
|
|
3755
|
+
}
|
|
3756
|
+
/**
|
|
3757
|
+
* Creates a static payload for the sender_withdraw Move function.
|
|
3758
|
+
* This is a helper method for constructing the transaction payload without signing.
|
|
3759
|
+
*
|
|
3760
|
+
* @param params.deployer - Optional deployer account address. Defaults to MICROPAYMENTS_DEPLOYER.
|
|
3761
|
+
* @param params.receiver - The account address of the receiver.
|
|
3762
|
+
* @param params.fungibleAssetAddress - The account address of the fungible asset.
|
|
3763
|
+
*
|
|
3764
|
+
* @returns An Aptos transaction payload data object for the sender_withdraw Move function.
|
|
3765
|
+
*/
|
|
3766
|
+
static createSenderWithdrawPayload(params) {
|
|
3767
|
+
return {
|
|
3768
|
+
function: `${(params.deployer ?? MICROPAYMENTS_DEPLOYER).toString()}::micropayments::sender_withdraw`,
|
|
3769
|
+
functionArguments: [params.receiver, params.fungibleAssetAddress]
|
|
3770
|
+
};
|
|
3771
|
+
}
|
|
3277
3772
|
/**
|
|
3278
3773
|
* Creates a micropayment that can be sent to a receiver.
|
|
3279
3774
|
* The sender signs a WithdrawApproval message that authorizes the receiver
|
|
@@ -3645,36 +4140,6 @@ var ShelbyPlacementGroupClient = class {
|
|
|
3645
4140
|
}
|
|
3646
4141
|
};
|
|
3647
4142
|
|
|
3648
|
-
// src/core/errors.ts
|
|
3649
|
-
var ShelbyErrorCodes = {
|
|
3650
|
-
// blob_metadata.move errors
|
|
3651
|
-
E_BLOB_NOT_FOUND: "E_BLOB_NOT_FOUND",
|
|
3652
|
-
E_INVALID_EXPIRATION_TIME: "E_INVALID_EXPIRATION_TIME",
|
|
3653
|
-
E_TEST_ENCODING_NOT_ALLOWED: "E_TEST_ENCODING_NOT_ALLOWED",
|
|
3654
|
-
E_BLOB_NOT_EXPIRED: "E_BLOB_NOT_EXPIRED",
|
|
3655
|
-
E_INVALID_CHUNKSET_COUNT: "E_INVALID_CHUNKSET_COUNT",
|
|
3656
|
-
E_NOT_BLOB_OWNER: "E_NOT_BLOB_OWNER",
|
|
3657
|
-
E_NOT_ADMIN: "E_NOT_ADMIN",
|
|
3658
|
-
E_BLOB_EXPIRED: "E_BLOB_EXPIRED",
|
|
3659
|
-
E_BLOB_NAME_TOO_LONG: "E_BLOB_NAME_TOO_LONG",
|
|
3660
|
-
E_INVALID_PAYMENT_EPOCHS: "E_INVALID_PAYMENT_EPOCHS",
|
|
3661
|
-
E_NO_SLICES_AVAILABLE: "E_NO_SLICES_AVAILABLE",
|
|
3662
|
-
// Common Aptos/Move errors
|
|
3663
|
-
EALREADY_EXISTS: "EALREADY_EXISTS"
|
|
3664
|
-
};
|
|
3665
|
-
function isBlobAlreadyExistsError(errorMessage) {
|
|
3666
|
-
return errorMessage.includes(ShelbyErrorCodes.EALREADY_EXISTS) || errorMessage.includes("already exists");
|
|
3667
|
-
}
|
|
3668
|
-
function isAccessDeniedError(errorMessage) {
|
|
3669
|
-
return errorMessage.includes(ShelbyErrorCodes.E_NOT_BLOB_OWNER) || errorMessage.includes(ShelbyErrorCodes.E_NOT_ADMIN) || errorMessage.includes("ENOT_AUTHORIZED") || errorMessage.includes("not authorized") || errorMessage.includes("permission denied");
|
|
3670
|
-
}
|
|
3671
|
-
function isBlobNotFoundError(errorMessage) {
|
|
3672
|
-
return errorMessage.includes(ShelbyErrorCodes.E_BLOB_NOT_FOUND);
|
|
3673
|
-
}
|
|
3674
|
-
function isBlobExpiredError(errorMessage) {
|
|
3675
|
-
return errorMessage.includes(ShelbyErrorCodes.E_BLOB_EXPIRED);
|
|
3676
|
-
}
|
|
3677
|
-
|
|
3678
4143
|
// src/core/networks.ts
|
|
3679
4144
|
import { Network as Network5 } from "@aptos-labs/ts-sdk";
|
|
3680
4145
|
var shelbyNetworks = [
|
|
@@ -3725,8 +4190,12 @@ function generateCommitmentsParallel(provider, data, _options) {
|
|
|
3725
4190
|
export {
|
|
3726
4191
|
BlobCommitmentsSchema,
|
|
3727
4192
|
BlobNameSchema,
|
|
4193
|
+
Blob_Activities_Constraint,
|
|
3728
4194
|
Blob_Activities_Select_Column,
|
|
4195
|
+
Blob_Activities_Update_Column,
|
|
4196
|
+
Blobs_Constraint,
|
|
3729
4197
|
Blobs_Select_Column,
|
|
4198
|
+
Blobs_Update_Column,
|
|
3730
4199
|
CHUNK_SIZE_PARAMS,
|
|
3731
4200
|
COMMITMENT_SCHEMA_VERSION,
|
|
3732
4201
|
ChallengeResponseSchema,
|
|
@@ -3734,7 +4203,6 @@ export {
|
|
|
3734
4203
|
ChunkSizeScheme,
|
|
3735
4204
|
ChunksetCommitmentSchema,
|
|
3736
4205
|
ClayErasureCodingProvider,
|
|
3737
|
-
CompleteMultipartUploadResponseSchema,
|
|
3738
4206
|
Cursor_Ordering,
|
|
3739
4207
|
DEFAULT_CHUNKSET_SIZE_BYTES,
|
|
3740
4208
|
DEFAULT_CHUNK_SIZE_BYTES,
|
|
@@ -3758,13 +4226,17 @@ export {
|
|
|
3758
4226
|
GetTotalBlobsSizeDocument,
|
|
3759
4227
|
MICROPAYMENTS_DEPLOYER,
|
|
3760
4228
|
MissingTransactionSubmitterError,
|
|
3761
|
-
MultipartUploadStatusResponseSchema,
|
|
3762
4229
|
NetworkToGasStationBaseUrl,
|
|
3763
4230
|
NetworkToShelbyBlobIndexerBaseUrl,
|
|
3764
4231
|
NetworkToShelbyRPCBaseUrl,
|
|
4232
|
+
ObjectCommitRejectedError,
|
|
3765
4233
|
Order_By,
|
|
4234
|
+
Placement_Group_Slots_Constraint,
|
|
3766
4235
|
Placement_Group_Slots_Select_Column,
|
|
4236
|
+
Placement_Group_Slots_Update_Column,
|
|
4237
|
+
Processor_Status_Constraint,
|
|
3767
4238
|
Processor_Status_Select_Column,
|
|
4239
|
+
Processor_Status_Update_Column,
|
|
3768
4240
|
RPCErrorResponseSchema,
|
|
3769
4241
|
ReedSolomonErasureCodingProvider,
|
|
3770
4242
|
SHELBYUSD_FA_METADATA_ADDRESS,
|
|
@@ -3776,25 +4248,29 @@ export {
|
|
|
3776
4248
|
ShelbyBlobClient,
|
|
3777
4249
|
ShelbyClient,
|
|
3778
4250
|
ShelbyErrorCodes,
|
|
4251
|
+
ShelbyLocationErrorCodes,
|
|
3779
4252
|
ShelbyMetadataClient,
|
|
3780
4253
|
ShelbyMicropaymentChannelClient,
|
|
3781
4254
|
ShelbyPlacementGroupClient,
|
|
3782
4255
|
ShelbyRPCClient,
|
|
3783
4256
|
StaleChannelStateError,
|
|
3784
4257
|
StaleMicropaymentErrorResponseSchema,
|
|
3785
|
-
StartMultipartUploadResponseSchema,
|
|
3786
4258
|
TOKEN_DEPLOYER,
|
|
3787
4259
|
TOKEN_OBJECT_ADDRESS,
|
|
3788
|
-
|
|
4260
|
+
blobEncryptionFromMoveVariant,
|
|
4261
|
+
blobEncryptionToMoveEnumIndex,
|
|
3789
4262
|
buildRequestUrl,
|
|
3790
4263
|
concatHashes,
|
|
3791
4264
|
createBlobKey,
|
|
3792
4265
|
createDefaultErasureCodingProvider,
|
|
3793
4266
|
createShelbyIndexerClient,
|
|
3794
4267
|
defaultErasureCodingConfig,
|
|
4268
|
+
describeLocationError,
|
|
3795
4269
|
erasureCodingConfig16Total10Data13Helper,
|
|
3796
4270
|
erasureCodingConfig4Total2Data3Helper,
|
|
4271
|
+
expectedChunksetInclusionProofHashes,
|
|
3797
4272
|
expectedTotalChunksets,
|
|
4273
|
+
findErasureSchemeByErasureN,
|
|
3798
4274
|
generateCommitments,
|
|
3799
4275
|
generateCommitmentsParallel,
|
|
3800
4276
|
generateMerkleRoot,
|
|
@@ -3807,12 +4283,15 @@ export {
|
|
|
3807
4283
|
getShelbyBlobExplorerUrl,
|
|
3808
4284
|
getShelbyIndexerClient,
|
|
3809
4285
|
isAccessDeniedError,
|
|
4286
|
+
isActiveForTasks,
|
|
4287
|
+
isActiveProviderCondition,
|
|
3810
4288
|
isBlobAlreadyExistsError,
|
|
3811
4289
|
isBlobExpiredError,
|
|
3812
4290
|
isBlobNotFoundError,
|
|
3813
4291
|
isShelbyNetwork,
|
|
3814
4292
|
normalizeAddress,
|
|
3815
4293
|
readInChunks,
|
|
4294
|
+
requiredAckCount,
|
|
3816
4295
|
shelbyNetworks,
|
|
3817
4296
|
zeroPadBytes
|
|
3818
4297
|
};
|