@shelby-protocol/sdk 0.0.1-experimental.1 → 0.0.1-experimental.3
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/README.md +0 -12
- package/dist/browser/index.d.ts +10 -6
- package/dist/browser/index.mjs +29 -5
- package/dist/chunk-5Z3RVWU3.mjs +67 -0
- package/dist/{chunk-EFE5Y7IE.mjs → chunk-B3CB2YEO.mjs} +4 -17
- package/dist/chunk-G263DBCY.mjs +105 -0
- package/dist/chunk-HMKVGTZV.mjs +11 -0
- package/dist/{chunk-DBTBUKCW.mjs → chunk-IAHEBEM6.mjs} +55 -61
- package/dist/chunk-P7BVGLTV.mjs +32 -0
- package/dist/chunk-QKT5R735.mjs +0 -0
- package/dist/{chunk-77TSD6TQ.mjs → chunk-RYJCDQEK.mjs} +40 -21
- package/dist/core/blobs.d.ts +0 -5
- package/dist/{node → core}/clients/ShelbyBlobClient.d.ts +10 -18
- package/dist/core/clients/ShelbyBlobClient.mjs +9 -0
- package/dist/core/clients/ShelbyClient.d.ts +99 -0
- package/dist/core/clients/ShelbyClient.mjs +16 -0
- package/dist/core/clients/ShelbyClientConfig.d.ts +13 -0
- package/dist/core/clients/ShelbyClientConfig.mjs +0 -0
- package/dist/{node → core}/clients/ShelbyRPCClient.d.ts +8 -8
- package/dist/core/clients/ShelbyRPCClient.mjs +10 -0
- package/dist/core/clients/index.d.ts +11 -0
- package/dist/core/clients/index.mjs +23 -0
- package/dist/core/commitments.d.ts +30 -1
- package/dist/core/commitments.mjs +7 -3
- package/dist/core/constants.d.ts +0 -1
- package/dist/core/erasure.d.ts +6 -0
- package/dist/{node → core}/erasure.mjs +1 -1
- package/dist/core/index.d.ts +10 -6
- package/dist/core/index.mjs +29 -5
- package/dist/core/utils.d.ts +30 -0
- package/dist/{node/readableUtil.mjs → core/utils.mjs} +3 -1
- package/dist/node/clients/ShelbyNodeClient.d.ts +8 -87
- package/dist/node/clients/ShelbyNodeClient.mjs +7 -12
- package/dist/node/clients/index.d.ts +5 -5
- package/dist/node/clients/index.mjs +9 -20
- package/dist/node/index.d.ts +10 -12
- package/dist/node/index.mjs +28 -25
- package/package.json +4 -17
- package/dist/chunk-E3QOKRQ4.mjs +0 -50
- package/dist/chunk-NPM7WXK3.mjs +0 -49
- package/dist/chunk-OWIIKLFI.mjs +0 -43
- package/dist/chunk-VLLCOFH7.mjs +0 -73
- package/dist/chunk-YV67F5NY.mjs +0 -38
- package/dist/core/ShelbyClient.d.ts +0 -34
- package/dist/core/ShelbyClient.mjs +0 -8
- package/dist/node/clients/ShelbyBlobClient.mjs +0 -19
- package/dist/node/clients/ShelbyRPCClient.mjs +0 -17
- package/dist/node/commitments.d.ts +0 -35
- package/dist/node/commitments.mjs +0 -18
- package/dist/node/erasure.d.ts +0 -12
- package/dist/node/readableUtil.d.ts +0 -2
- package/dist/readableUtil-BW_7enT-.d.ts +0 -12
- /package/dist/{chunk-PZPMURE4.mjs → chunk-7S6RVKYB.mjs} +0 -0
- /package/dist/{chunk-WVWL2OPB.mjs → chunk-PLUDE5C3.mjs} +0 -0
package/README.md
CHANGED
|
@@ -7,9 +7,6 @@ A TypeScript SDK providing core encoding and decoding utilities for both Node.js
|
|
|
7
7
|
```bash
|
|
8
8
|
# Installing the shelby sdk
|
|
9
9
|
pnpm install @shelby-protocol/sdk @aptos-labs/ts-sdk
|
|
10
|
-
|
|
11
|
-
# If you plan to use the Node.js entrypoint, also install its peer dependencies:
|
|
12
|
-
pnpm install fs-extra glob node-fetch yaml
|
|
13
10
|
```
|
|
14
11
|
|
|
15
12
|
## Usage
|
|
@@ -36,15 +33,6 @@ import { ShelbyBlob } from '@shelby-protocol/sdk/browser';
|
|
|
36
33
|
|
|
37
34
|
- `@aptos-labs/ts-sdk`
|
|
38
35
|
|
|
39
|
-
When using the **Node.js** entrypoint (`@shelby-protocol/sdk/node`), make sure you have the following installed in your project:
|
|
40
|
-
|
|
41
|
-
- `fs-extra`
|
|
42
|
-
- `glob`
|
|
43
|
-
- `node-fetch`
|
|
44
|
-
- `yaml`
|
|
45
|
-
|
|
46
|
-
These are marked as **peerDependencies** and are **optional** for browser usage.
|
|
47
|
-
|
|
48
36
|
## Scripts
|
|
49
37
|
|
|
50
38
|
```bash
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
1
|
+
export { ShelbyBlob, createBlobKey } from '../core/blobs.js';
|
|
2
|
+
export { ShelbyBlobClient } from '../core/clients/ShelbyBlobClient.js';
|
|
3
|
+
export { ShelbyClient } from '../core/clients/ShelbyClient.js';
|
|
4
|
+
export { ShelbyClientConfig } from '../core/clients/ShelbyClientConfig.js';
|
|
5
|
+
export { ShelbyRPCClient } from '../core/clients/ShelbyRPCClient.js';
|
|
6
|
+
export { BlobCommitments, BlobCommitmentsSchema, ChunksetCommitment, ChunksetCommitmentSchema, generateCommitments } from '../core/commitments.js';
|
|
3
7
|
export { CHUNKSET_SIZE_BYTES, DEFAULT_PROJECT_DESCRIPTION, DEFAULT_PROJECT_NAME, DEFAULT_SHELBY_BASE_URL, ERASURE_K, ERASURE_M, SHELBY_DEPLOYER, TOKEN_DEPLOYER, TOKEN_OBJECT_ADDRESS, getChunkSizeBytes, getChunksetSizeBytes } from '../core/constants.js';
|
|
8
|
+
export { erasureEncode } from '../core/erasure.js';
|
|
9
|
+
export { BlobName, BlobNameSchema, ChunkKey, allChunksForBlob, roundSize } from '../core/layout.js';
|
|
4
10
|
export { BlobChunk, BlobEncoding, BlobMetadata, ChunkLocation, ClayEncoding, PendingChunkLocation, SignedChunkCommitment, StoredChunkLocation } from '../core/types/blobs.js';
|
|
5
11
|
export { EncodingOptions } from '../core/types/encodings.js';
|
|
6
|
-
export {
|
|
7
|
-
export { ShelbyClient, ShelbyClientConfig } from '../core/ShelbyClient.js';
|
|
8
|
-
import 'zod';
|
|
12
|
+
export { concatHashes, readInChunks, zeroPadBuffer } from '../core/utils.js';
|
|
9
13
|
import '@aptos-labs/ts-sdk';
|
|
10
|
-
import '
|
|
14
|
+
import 'zod';
|
package/dist/browser/index.mjs
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-PLUDE5C3.mjs";
|
|
2
2
|
import "../chunk-MWDW4ROU.mjs";
|
|
3
3
|
import "../chunk-ZHXCVRZX.mjs";
|
|
4
4
|
import "../chunk-IHTPXUYI.mjs";
|
|
5
|
+
import "../chunk-QKT5R735.mjs";
|
|
5
6
|
import {
|
|
6
7
|
ShelbyClient
|
|
7
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-RYJCDQEK.mjs";
|
|
9
|
+
import {
|
|
10
|
+
ShelbyBlobClient
|
|
11
|
+
} from "../chunk-B3CB2YEO.mjs";
|
|
12
|
+
import {
|
|
13
|
+
ShelbyRPCClient
|
|
14
|
+
} from "../chunk-IAHEBEM6.mjs";
|
|
8
15
|
import {
|
|
9
16
|
createBlobKey
|
|
10
17
|
} from "../chunk-QEMIORTL.mjs";
|
|
11
18
|
import {
|
|
12
19
|
BlobCommitmentsSchema,
|
|
13
|
-
ChunksetCommitmentSchema
|
|
14
|
-
|
|
20
|
+
ChunksetCommitmentSchema,
|
|
21
|
+
generateCommitments
|
|
22
|
+
} from "../chunk-G263DBCY.mjs";
|
|
23
|
+
import {
|
|
24
|
+
concatHashes,
|
|
25
|
+
readInChunks,
|
|
26
|
+
zeroPadBuffer
|
|
27
|
+
} from "../chunk-5Z3RVWU3.mjs";
|
|
28
|
+
import {
|
|
29
|
+
erasureEncode
|
|
30
|
+
} from "../chunk-P7BVGLTV.mjs";
|
|
15
31
|
import {
|
|
16
32
|
BlobNameSchema,
|
|
17
33
|
ChunkKey,
|
|
@@ -31,6 +47,7 @@ import {
|
|
|
31
47
|
getChunkSizeBytes,
|
|
32
48
|
getChunksetSizeBytes
|
|
33
49
|
} from "../chunk-D2FERD4A.mjs";
|
|
50
|
+
import "../chunk-I6NG5GNL.mjs";
|
|
34
51
|
import "../chunk-7P6ASYW6.mjs";
|
|
35
52
|
export {
|
|
36
53
|
BlobCommitmentsSchema,
|
|
@@ -44,12 +61,19 @@ export {
|
|
|
44
61
|
ERASURE_K,
|
|
45
62
|
ERASURE_M,
|
|
46
63
|
SHELBY_DEPLOYER,
|
|
64
|
+
ShelbyBlobClient,
|
|
47
65
|
ShelbyClient,
|
|
66
|
+
ShelbyRPCClient,
|
|
48
67
|
TOKEN_DEPLOYER,
|
|
49
68
|
TOKEN_OBJECT_ADDRESS,
|
|
50
69
|
allChunksForBlob,
|
|
70
|
+
concatHashes,
|
|
51
71
|
createBlobKey,
|
|
72
|
+
erasureEncode,
|
|
73
|
+
generateCommitments,
|
|
52
74
|
getChunkSizeBytes,
|
|
53
75
|
getChunksetSizeBytes,
|
|
54
|
-
|
|
76
|
+
readInChunks,
|
|
77
|
+
roundSize,
|
|
78
|
+
zeroPadBuffer
|
|
55
79
|
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// src/core/utils.ts
|
|
2
|
+
import { Hex } from "@aptos-labs/ts-sdk";
|
|
3
|
+
async function* readInChunks(input, chunkSize) {
|
|
4
|
+
let idx = 0;
|
|
5
|
+
if (Buffer.isBuffer(input)) {
|
|
6
|
+
for (let offset = 0; offset < input.length; offset += chunkSize) {
|
|
7
|
+
yield [idx++, Buffer.from(input.subarray(offset, offset + chunkSize))];
|
|
8
|
+
}
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const reader = input.getReader();
|
|
12
|
+
let buffer = new Uint8Array(chunkSize);
|
|
13
|
+
let bufferWriteOffset = 0;
|
|
14
|
+
try {
|
|
15
|
+
while (true) {
|
|
16
|
+
const { value, done } = await reader.read();
|
|
17
|
+
if (done) break;
|
|
18
|
+
if (value === void 0) continue;
|
|
19
|
+
let srcOffset = 0;
|
|
20
|
+
while (srcOffset < value.length) {
|
|
21
|
+
const remainingCapacity = chunkSize - bufferWriteOffset;
|
|
22
|
+
const bytesToCopy = Math.min(
|
|
23
|
+
remainingCapacity,
|
|
24
|
+
value.length - srcOffset
|
|
25
|
+
);
|
|
26
|
+
buffer.set(
|
|
27
|
+
value.subarray(srcOffset, srcOffset + bytesToCopy),
|
|
28
|
+
bufferWriteOffset
|
|
29
|
+
);
|
|
30
|
+
bufferWriteOffset += bytesToCopy;
|
|
31
|
+
srcOffset += bytesToCopy;
|
|
32
|
+
if (bufferWriteOffset >= chunkSize) {
|
|
33
|
+
yield [idx++, Buffer.from(buffer)];
|
|
34
|
+
buffer = new Uint8Array(chunkSize);
|
|
35
|
+
bufferWriteOffset = 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
} finally {
|
|
40
|
+
reader.releaseLock();
|
|
41
|
+
}
|
|
42
|
+
if (bufferWriteOffset > 0) {
|
|
43
|
+
yield [idx++, Buffer.from(buffer.subarray(0, bufferWriteOffset))];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function zeroPadBuffer(buffer, desiredLength) {
|
|
47
|
+
if (buffer.length >= desiredLength) {
|
|
48
|
+
return buffer;
|
|
49
|
+
}
|
|
50
|
+
const paddedBuffer = Buffer.alloc(desiredLength);
|
|
51
|
+
buffer.copy(paddedBuffer);
|
|
52
|
+
return paddedBuffer;
|
|
53
|
+
}
|
|
54
|
+
async function concatHashes(parts) {
|
|
55
|
+
const combined = Buffer.concat(
|
|
56
|
+
parts.map((part) => Hex.fromHexInput(part).toUint8Array())
|
|
57
|
+
);
|
|
58
|
+
return Hex.fromHexInput(
|
|
59
|
+
new Uint8Array(await crypto.subtle.digest("SHA-256", combined))
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
readInChunks,
|
|
65
|
+
zeroPadBuffer,
|
|
66
|
+
concatHashes
|
|
67
|
+
};
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
generateCommitments
|
|
3
|
-
} from "./chunk-VLLCOFH7.mjs";
|
|
4
1
|
import {
|
|
5
2
|
createBlobKey
|
|
6
3
|
} from "./chunk-QEMIORTL.mjs";
|
|
@@ -8,8 +5,7 @@ import {
|
|
|
8
5
|
SHELBY_DEPLOYER
|
|
9
6
|
} from "./chunk-D2FERD4A.mjs";
|
|
10
7
|
|
|
11
|
-
// src/
|
|
12
|
-
import { Readable } from "stream";
|
|
8
|
+
// src/core/clients/ShelbyBlobClient.ts
|
|
13
9
|
import {
|
|
14
10
|
AccountAddress,
|
|
15
11
|
Aptos,
|
|
@@ -34,7 +30,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
34
30
|
*/
|
|
35
31
|
constructor(config) {
|
|
36
32
|
this.aptos = new Aptos(config.aptos.config);
|
|
37
|
-
this.deployer = config.
|
|
33
|
+
this.deployer = config.shelby?.deployer ?? AccountAddress.fromString(SHELBY_DEPLOYER);
|
|
38
34
|
}
|
|
39
35
|
/**
|
|
40
36
|
* Retrieves the blob metadata from the blockchain. If it does not exist,
|
|
@@ -181,7 +177,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
181
177
|
*
|
|
182
178
|
* @example
|
|
183
179
|
* ```typescript
|
|
184
|
-
* const blobCommitments = await generateCommitments(
|
|
180
|
+
* const blobCommitments = await generateCommitments(data);
|
|
185
181
|
*
|
|
186
182
|
* const { blobCommitments, transaction } = await client.writeBlobCommitments({
|
|
187
183
|
* signer,
|
|
@@ -192,16 +188,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
192
188
|
* ```
|
|
193
189
|
*/
|
|
194
190
|
async writeBlobCommitments(params) {
|
|
195
|
-
|
|
196
|
-
if ("blobCommitments" in params) {
|
|
197
|
-
blobCommitments = params.blobCommitments;
|
|
198
|
-
} else {
|
|
199
|
-
blobCommitments = await generateCommitments(
|
|
200
|
-
Readable.from(params.blobData),
|
|
201
|
-
void 0,
|
|
202
|
-
params.options?.encoding
|
|
203
|
-
);
|
|
204
|
-
}
|
|
191
|
+
const blobCommitments = params.blobCommitments;
|
|
205
192
|
const transaction = await this.aptos.transaction.build.simple({
|
|
206
193
|
...params.options?.build,
|
|
207
194
|
data: _ShelbyBlobClient.createWriteBlobCommitmentsPayload({
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {
|
|
2
|
+
concatHashes,
|
|
3
|
+
readInChunks,
|
|
4
|
+
zeroPadBuffer
|
|
5
|
+
} from "./chunk-5Z3RVWU3.mjs";
|
|
6
|
+
import {
|
|
7
|
+
erasureEncode
|
|
8
|
+
} from "./chunk-P7BVGLTV.mjs";
|
|
9
|
+
import {
|
|
10
|
+
roundSize
|
|
11
|
+
} from "./chunk-GGYTHP5F.mjs";
|
|
12
|
+
import {
|
|
13
|
+
ERASURE_K,
|
|
14
|
+
ERASURE_M,
|
|
15
|
+
getChunksetSizeBytes
|
|
16
|
+
} from "./chunk-D2FERD4A.mjs";
|
|
17
|
+
|
|
18
|
+
// src/core/commitments.ts
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
var ChunksetCommitmentSchema = z.object({
|
|
21
|
+
// Chunkset root (vector commitment of child chunks)
|
|
22
|
+
chunkset_root: z.string().nullable(),
|
|
23
|
+
// the size is known statically from the current configuration
|
|
24
|
+
chunk_commitments: z.array(z.string())
|
|
25
|
+
}).refine(
|
|
26
|
+
(data) => {
|
|
27
|
+
return data.chunk_commitments.length === ERASURE_K + ERASURE_M;
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
message: `Chunkset must have exactly ${ERASURE_K + ERASURE_M} chunks (ERASURE_K + ERASURE_M = ${ERASURE_K} + ${ERASURE_M})`,
|
|
31
|
+
path: ["chunk_commitments"]
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
function expectedTotalChunksets(rawSize) {
|
|
35
|
+
return roundSize(rawSize) / getChunksetSizeBytes();
|
|
36
|
+
}
|
|
37
|
+
var BlobCommitmentsSchema = z.object({
|
|
38
|
+
schema_version: z.string(),
|
|
39
|
+
raw_data_size: z.number(),
|
|
40
|
+
// FIXME I am not sure about this being here, or if it should be somewhere else
|
|
41
|
+
blob_merkle_root: z.string(),
|
|
42
|
+
chunkset_commitments: z.array(ChunksetCommitmentSchema)
|
|
43
|
+
}).refine(
|
|
44
|
+
(data) => {
|
|
45
|
+
return expectedTotalChunksets(data.raw_data_size) === data.chunkset_commitments.length;
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
message: "Total chunkset count mismatches with raw data size",
|
|
49
|
+
// FIXME put more details in here
|
|
50
|
+
path: ["chunkset_commitments"]
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
async function generateCommitments(fullData, onChunk, options) {
|
|
54
|
+
const chunksetCommitments = [];
|
|
55
|
+
const chunksetCommitmentHashes = [];
|
|
56
|
+
let rawDataSize = 0;
|
|
57
|
+
const chunksetGen = readInChunks(
|
|
58
|
+
fullData,
|
|
59
|
+
options?.chunksetSize ?? getChunksetSizeBytes()
|
|
60
|
+
);
|
|
61
|
+
for await (const [chunksetIdx, chunksetData] of chunksetGen) {
|
|
62
|
+
const chunkCommitments = [];
|
|
63
|
+
rawDataSize += chunksetData.length;
|
|
64
|
+
const paddedChunksetData = zeroPadBuffer(
|
|
65
|
+
chunksetData,
|
|
66
|
+
options?.chunksetSize ?? getChunksetSizeBytes()
|
|
67
|
+
);
|
|
68
|
+
const chunks = await erasureEncode(
|
|
69
|
+
paddedChunksetData,
|
|
70
|
+
options?.erasureK ?? ERASURE_K,
|
|
71
|
+
options?.erasureM ?? ERASURE_M
|
|
72
|
+
);
|
|
73
|
+
let chunkIdx = 0;
|
|
74
|
+
for (const chunkData of chunks) {
|
|
75
|
+
if (onChunk !== void 0) {
|
|
76
|
+
await onChunk(chunksetIdx, chunkIdx, chunkData);
|
|
77
|
+
}
|
|
78
|
+
const chunkHash = await concatHashes([chunkData]);
|
|
79
|
+
chunkCommitments.push(chunkHash);
|
|
80
|
+
chunkIdx += 1;
|
|
81
|
+
}
|
|
82
|
+
const h = await concatHashes(
|
|
83
|
+
chunkCommitments.map((chunk) => chunk.toUint8Array())
|
|
84
|
+
);
|
|
85
|
+
chunksetCommitments.push({
|
|
86
|
+
chunkset_root: h.toString(),
|
|
87
|
+
chunk_commitments: chunkCommitments.map((chunk) => chunk.toString())
|
|
88
|
+
});
|
|
89
|
+
chunksetCommitmentHashes.push(h);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
schema_version: "1.3",
|
|
93
|
+
raw_data_size: rawDataSize,
|
|
94
|
+
blob_merkle_root: (await concatHashes(
|
|
95
|
+
chunksetCommitmentHashes.map((chunk) => chunk.toUint8Array())
|
|
96
|
+
)).toString(),
|
|
97
|
+
chunkset_commitments: chunksetCommitments
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export {
|
|
102
|
+
ChunksetCommitmentSchema,
|
|
103
|
+
BlobCommitmentsSchema,
|
|
104
|
+
generateCommitments
|
|
105
|
+
};
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ShelbyClient
|
|
3
|
-
} from "./chunk-YV67F5NY.mjs";
|
|
4
1
|
import {
|
|
5
2
|
BlobNameSchema
|
|
6
3
|
} from "./chunk-GGYTHP5F.mjs";
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_SHELBY_BASE_URL
|
|
6
|
+
} from "./chunk-D2FERD4A.mjs";
|
|
7
7
|
import {
|
|
8
8
|
sleep
|
|
9
9
|
} from "./chunk-I6NG5GNL.mjs";
|
|
10
10
|
|
|
11
|
-
// src/
|
|
12
|
-
import { Readable, Transform } from "stream";
|
|
11
|
+
// src/core/clients/ShelbyRPCClient.ts
|
|
13
12
|
import { AccountAddress } from "@aptos-labs/ts-sdk";
|
|
14
13
|
function encodeURIComponentKeepSlashes(str) {
|
|
15
14
|
return encodeURIComponent(str).replace(/%2F/g, "/");
|
|
16
15
|
}
|
|
17
|
-
var ShelbyRPCClient = class
|
|
16
|
+
var ShelbyRPCClient = class {
|
|
17
|
+
baseUrl;
|
|
18
18
|
/**
|
|
19
19
|
* The ShelbyRPCClient is used to interact with the Shelby RPC node. This
|
|
20
20
|
* includes functions like uploading blobs after they have been committed to the
|
|
@@ -25,19 +25,18 @@ var ShelbyRPCClient = class extends ShelbyClient {
|
|
|
25
25
|
*
|
|
26
26
|
* @example
|
|
27
27
|
* ```typescript
|
|
28
|
-
* const aptos = new Aptos(new AptosConfig({ network: Network.
|
|
28
|
+
* const aptos = new Aptos(new AptosConfig({ network: Network.TESTNET }));
|
|
29
29
|
* const client = new ShelbyRPCClient({ aptos, shelby: { baseUrl: "https://api.shelby.dev" } });
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
|
-
// biome-ignore lint/complexity/noUselessConstructor: Add JSDoc
|
|
33
32
|
constructor(config) {
|
|
34
|
-
|
|
33
|
+
this.baseUrl = config.shelby?.baseUrl ?? DEFAULT_SHELBY_BASE_URL;
|
|
35
34
|
}
|
|
36
35
|
async #uploadPart(uploadId, partIdx, partData) {
|
|
37
36
|
const nRetries = 5;
|
|
38
37
|
for (let i = 0; i < nRetries; ++i) {
|
|
39
38
|
const partResponse = await fetch(
|
|
40
|
-
`${this.baseUrl}/
|
|
39
|
+
`${this.baseUrl}/v1/multipart-uploads/${uploadId}/parts/${partIdx}`,
|
|
41
40
|
{
|
|
42
41
|
method: "PUT",
|
|
43
42
|
headers: {
|
|
@@ -55,25 +54,22 @@ var ShelbyRPCClient = class extends ShelbyClient {
|
|
|
55
54
|
throw new Error(`Failed to upload part ${partIdx}.`);
|
|
56
55
|
}
|
|
57
56
|
async #putBlobMultipart(account, blobName, blobData, partSize = 5 * 1024 * 1024) {
|
|
58
|
-
const startResponse = await fetch(
|
|
59
|
-
|
|
60
|
-
{
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
);
|
|
57
|
+
const startResponse = await fetch(`${this.baseUrl}/v1/multipart-uploads`, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: {
|
|
60
|
+
"Content-Type": "application/json"
|
|
61
|
+
},
|
|
62
|
+
body: JSON.stringify({
|
|
63
|
+
rawAccount: account.toString(),
|
|
64
|
+
rawBlobName: blobName,
|
|
65
|
+
rawPartSize: partSize
|
|
66
|
+
})
|
|
67
|
+
});
|
|
72
68
|
if (!startResponse.ok) {
|
|
73
69
|
let errorBodyText = "Could not read error body";
|
|
74
70
|
try {
|
|
75
71
|
errorBodyText = await startResponse.text();
|
|
76
|
-
} catch (
|
|
72
|
+
} catch (_e) {
|
|
77
73
|
}
|
|
78
74
|
throw new Error(
|
|
79
75
|
`Failed to start multipart upload! status: ${startResponse.status}, body: ${errorBodyText}`
|
|
@@ -84,11 +80,11 @@ var ShelbyRPCClient = class extends ShelbyClient {
|
|
|
84
80
|
for (let partIdx = 0; partIdx < totalParts; partIdx++) {
|
|
85
81
|
const start = partIdx * partSize;
|
|
86
82
|
const end = Math.min(start + partSize, blobData.length);
|
|
87
|
-
const partData = blobData.
|
|
83
|
+
const partData = blobData.slice(start, end);
|
|
88
84
|
await this.#uploadPart(uploadId, partIdx, partData);
|
|
89
85
|
}
|
|
90
86
|
const completeResponse = await fetch(
|
|
91
|
-
`${this.baseUrl}/
|
|
87
|
+
`${this.baseUrl}/v1/multipart-uploads/${uploadId}/complete`,
|
|
92
88
|
{
|
|
93
89
|
method: "POST",
|
|
94
90
|
headers: {
|
|
@@ -100,7 +96,7 @@ var ShelbyRPCClient = class extends ShelbyClient {
|
|
|
100
96
|
let errorBodyText = "Could not read error body";
|
|
101
97
|
try {
|
|
102
98
|
errorBodyText = await completeResponse.text();
|
|
103
|
-
} catch (
|
|
99
|
+
} catch (_e) {
|
|
104
100
|
}
|
|
105
101
|
throw new Error(
|
|
106
102
|
`Failed to complete multipart upload! status: ${completeResponse.status}, body: ${errorBodyText}`
|
|
@@ -117,7 +113,7 @@ var ShelbyRPCClient = class extends ShelbyClient {
|
|
|
117
113
|
*
|
|
118
114
|
* @example
|
|
119
115
|
* ```typescript
|
|
120
|
-
* const blobData =
|
|
116
|
+
* const blobData = new TextEncoder().encode("Hello, world!");
|
|
121
117
|
*
|
|
122
118
|
* await client.putBlob({ account, blobName: "foo/bar.txt", blobData });
|
|
123
119
|
* ```
|
|
@@ -186,45 +182,43 @@ var ShelbyRPCClient = class extends ShelbyClient {
|
|
|
186
182
|
`Invalid content-length header received: ${contentLengthHeader}`
|
|
187
183
|
);
|
|
188
184
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (done) {
|
|
196
|
-
this.push(null);
|
|
197
|
-
} else {
|
|
198
|
-
this.push(Buffer.from(value));
|
|
199
|
-
}
|
|
200
|
-
} catch (error) {
|
|
201
|
-
this.destroy(error);
|
|
185
|
+
const validatingStream = new ReadableStream({
|
|
186
|
+
start(controller) {
|
|
187
|
+
const maybeReader = response.body?.getReader();
|
|
188
|
+
if (!maybeReader) {
|
|
189
|
+
controller.error(new Error("Response body reader is unavailable"));
|
|
190
|
+
return;
|
|
202
191
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
192
|
+
const reader = maybeReader;
|
|
193
|
+
let bytesReceived = 0;
|
|
194
|
+
function pump() {
|
|
195
|
+
return reader.read().then(({ done, value }) => {
|
|
196
|
+
if (done) {
|
|
197
|
+
if (bytesReceived !== expectedContentLength) {
|
|
198
|
+
controller.error(
|
|
199
|
+
new Error(
|
|
200
|
+
`Downloaded data size (${bytesReceived} bytes) does not match content-length header (${expectedContentLength} bytes). This might indicate a partial or corrupted download.`
|
|
201
|
+
)
|
|
202
|
+
);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
controller.close();
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
bytesReceived += value.byteLength;
|
|
209
|
+
controller.enqueue(value);
|
|
210
|
+
return pump();
|
|
211
|
+
}).catch((error) => {
|
|
212
|
+
controller.error(error);
|
|
213
|
+
});
|
|
219
214
|
}
|
|
215
|
+
return pump();
|
|
220
216
|
}
|
|
221
217
|
});
|
|
222
|
-
sourceStream.pipe(validationTransform);
|
|
223
218
|
return {
|
|
224
219
|
account: AccountAddress.from(params.account),
|
|
225
220
|
name: params.blobName,
|
|
226
|
-
readable:
|
|
227
|
-
stream: validationTransform,
|
|
221
|
+
readable: validatingStream,
|
|
228
222
|
contentLength: expectedContentLength
|
|
229
223
|
};
|
|
230
224
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// src/core/erasure.ts
|
|
2
|
+
import { createWasmReedSolomonBinding } from "@shelby-protocol/reed-solomon";
|
|
3
|
+
function erasureEncode(data, k, m) {
|
|
4
|
+
const rawShardSize = Math.ceil(data.length / k);
|
|
5
|
+
const shardSize = Math.ceil(rawShardSize / 8) * 8;
|
|
6
|
+
const dataSize = shardSize * k;
|
|
7
|
+
const paritySize = shardSize * m;
|
|
8
|
+
const reedSolomon = createWasmReedSolomonBinding();
|
|
9
|
+
const dataBuf = Buffer.alloc(dataSize);
|
|
10
|
+
data.copy(dataBuf, 0);
|
|
11
|
+
const shards = new Uint8Array(dataSize + paritySize);
|
|
12
|
+
shards.set(new Uint8Array(dataBuf), 0);
|
|
13
|
+
reedSolomon.encode(shards, k, m);
|
|
14
|
+
const res = [];
|
|
15
|
+
for (let i = 0; i < k; i++) {
|
|
16
|
+
res.push(
|
|
17
|
+
Buffer.from(shards.slice(i * shardSize, i * shardSize + shardSize))
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
for (let j = 0; j < m; j++) {
|
|
21
|
+
res.push(
|
|
22
|
+
Buffer.from(
|
|
23
|
+
shards.slice((k + j) * shardSize, (k + j) * shardSize + shardSize)
|
|
24
|
+
)
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
return new Promise((resolve) => resolve(res));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
erasureEncode
|
|
32
|
+
};
|
|
File without changes
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ShelbyBlobClient
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-B3CB2YEO.mjs";
|
|
4
4
|
import {
|
|
5
5
|
ShelbyRPCClient
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-IAHEBEM6.mjs";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
} from "./chunk-
|
|
8
|
+
generateCommitments
|
|
9
|
+
} from "./chunk-G263DBCY.mjs";
|
|
10
|
+
import {
|
|
11
|
+
DEFAULT_SHELBY_BASE_URL
|
|
12
|
+
} from "./chunk-D2FERD4A.mjs";
|
|
10
13
|
|
|
11
|
-
// src/
|
|
12
|
-
|
|
14
|
+
// src/core/clients/ShelbyClient.ts
|
|
15
|
+
import {
|
|
16
|
+
Aptos
|
|
17
|
+
} from "@aptos-labs/ts-sdk";
|
|
18
|
+
var ShelbyClient = class {
|
|
13
19
|
/**
|
|
14
20
|
* The coordination client is used to interact with the Aptos blockchain which handles the commitments
|
|
15
21
|
* and metadata for blobs.
|
|
@@ -21,26 +27,31 @@ var ShelbyNodeClient = class extends ShelbyClient {
|
|
|
21
27
|
*/
|
|
22
28
|
rpc;
|
|
23
29
|
/**
|
|
24
|
-
* The
|
|
30
|
+
* The configuration for the Shelby client.
|
|
31
|
+
*/
|
|
32
|
+
config;
|
|
33
|
+
/**
|
|
34
|
+
* The Aptos client.
|
|
35
|
+
*/
|
|
36
|
+
aptos;
|
|
37
|
+
/**
|
|
38
|
+
* The base class for Shelby clients
|
|
25
39
|
*
|
|
26
40
|
* @param config.aptos.config - The Aptos config.
|
|
27
41
|
* @param config.shelby.baseUrl - The base URL of the Shelby RPC node. If not provided, the default base URL will be used.
|
|
28
|
-
* @param config.shelby.deployer - The deployer account address of the Shelby contract. If not provided, the default deployer address will be used.
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```typescript
|
|
32
|
-
* const aptos = new Aptos(new AptosConfig({ network: Network.DEVNET }));
|
|
33
|
-
* const client = new ShelbyNodeClient({ aptos, shelby: { baseUrl: "https://api.shelby.dev" } });
|
|
34
|
-
* ```
|
|
35
42
|
*/
|
|
36
43
|
constructor(config) {
|
|
37
|
-
|
|
38
|
-
this.
|
|
39
|
-
|
|
40
|
-
shelbyDeployer: config.shelby?.deployer
|
|
41
|
-
});
|
|
44
|
+
this.config = config;
|
|
45
|
+
this.aptos = new Aptos(this.config.aptos.config);
|
|
46
|
+
this.coordination = new ShelbyBlobClient(config);
|
|
42
47
|
this.rpc = new ShelbyRPCClient(config);
|
|
43
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* The base URL for the Shelby RPC node.
|
|
51
|
+
*/
|
|
52
|
+
get baseUrl() {
|
|
53
|
+
return this.config.shelby?.baseUrl ?? DEFAULT_SHELBY_BASE_URL;
|
|
54
|
+
}
|
|
44
55
|
/**
|
|
45
56
|
* Uploads a blob to the Shelby network.
|
|
46
57
|
*
|
|
@@ -53,7 +64,15 @@ var ShelbyNodeClient = class extends ShelbyClient {
|
|
|
53
64
|
* @returns The transaction and generated blob commitments.
|
|
54
65
|
*/
|
|
55
66
|
async upload(params) {
|
|
56
|
-
const
|
|
67
|
+
const generatedBlobCommitments = await generateCommitments(
|
|
68
|
+
params.blobData,
|
|
69
|
+
void 0,
|
|
70
|
+
params.options?.encoding
|
|
71
|
+
);
|
|
72
|
+
const { transaction, blobCommitments } = await this.coordination.writeBlobCommitments({
|
|
73
|
+
...params,
|
|
74
|
+
blobCommitments: generatedBlobCommitments
|
|
75
|
+
});
|
|
57
76
|
const confirmedTransaction = await this.aptos.waitForTransaction({
|
|
58
77
|
transactionHash: transaction.hash
|
|
59
78
|
});
|
|
@@ -86,5 +105,5 @@ var ShelbyNodeClient = class extends ShelbyClient {
|
|
|
86
105
|
};
|
|
87
106
|
|
|
88
107
|
export {
|
|
89
|
-
|
|
108
|
+
ShelbyClient
|
|
90
109
|
};
|