@fizzyflow/endless-vector 0.0.3 → 0.0.4
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/EndlessVector.js +108 -21
- package/README.md +5 -8
- package/ids.js +4 -4
- package/package.json +2 -2
- package/test/base.test.js +54 -14
package/EndlessVector.js
CHANGED
|
@@ -8,6 +8,7 @@ import ids from './ids.js';
|
|
|
8
8
|
* @typedef {import('@mysten/sui/client').SuiClient} SuiClient
|
|
9
9
|
* @typedef {import('@mysten/sui/client').GetObjectParams} GetObjectParams
|
|
10
10
|
* @typedef {import('@mysten/sui/client').GetDynamicFieldsParams} GetDynamicFieldsParams
|
|
11
|
+
* @typedef {import('@mysten/sui/transactions').TransactionResult} TransactionResult
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -94,7 +95,7 @@ export default class EndlessVector {
|
|
|
94
95
|
* @param {SuiClient} params.suiClient - Sui client instance for blockchain interactions
|
|
95
96
|
* @param {string} params.packageId - ID of the Move package containing the EndlessVector module
|
|
96
97
|
* @param {CustomSignAndExecuteTransactionFunction} params.signAndExecuteTransaction - Function to sign and execute transactions
|
|
97
|
-
* @param {?
|
|
98
|
+
* @param {?Uint8Array} [params.array] - Optional Uint8Array to initialize the vector with as the first item to get with .at(0)
|
|
98
99
|
* @param {?Object} [params.gasCoin] - Optional gas coin object reference {objectId: string, digest: string, version: string} to use for transaction payment
|
|
99
100
|
* @param {?Object} [params.options] - Optional transaction parameters
|
|
100
101
|
* @param {?Number} [params.options.timeout] - Transaction confirmation timeout in ms, default 30000
|
|
@@ -103,7 +104,7 @@ export default class EndlessVector {
|
|
|
103
104
|
* @throws {Error} If the transaction fails or no EndlessVector object is created
|
|
104
105
|
*/
|
|
105
106
|
static async create(params) {
|
|
106
|
-
const { suiClient, packageId, signAndExecuteTransaction,
|
|
107
|
+
const { suiClient, packageId, signAndExecuteTransaction, array, gasCoin, options = {} } = params;
|
|
107
108
|
|
|
108
109
|
let normalizedPackageId = packageId;
|
|
109
110
|
if (normalizedPackageId == 'mainnet' || (!normalizedPackageId && suiClient?.network == 'mainnet')) {
|
|
@@ -129,10 +130,13 @@ export default class EndlessVector {
|
|
|
129
130
|
tx.setGasPayment([gasCoin]);
|
|
130
131
|
}
|
|
131
132
|
|
|
132
|
-
if (
|
|
133
|
+
if (array && array.length) {
|
|
134
|
+
const vectorInput = await EndlessVector.getCreateTransactionAndReturnVectorInput({
|
|
135
|
+
packageId: normalizedPackageId,
|
|
136
|
+
}, array, tx);
|
|
133
137
|
tx.moveCall({
|
|
134
|
-
target: `${normalizedPackageId}::endless_vector::
|
|
135
|
-
arguments: [
|
|
138
|
+
target: `${normalizedPackageId}::endless_vector::transfer_to_sender`,
|
|
139
|
+
arguments: [vectorInput],
|
|
136
140
|
});
|
|
137
141
|
} else {
|
|
138
142
|
tx.moveCall({
|
|
@@ -180,33 +184,92 @@ export default class EndlessVector {
|
|
|
180
184
|
});
|
|
181
185
|
}
|
|
182
186
|
|
|
183
|
-
get isWritable() {
|
|
184
|
-
return !!(this._packageId && this._signAndExecuteTransaction);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
187
|
/**
|
|
188
|
-
|
|
189
|
-
|
|
188
|
+
* Creates an empty EndlessVector and returns the vector input reference.
|
|
189
|
+
* Appends vector creation to existing transaction or makes new one.
|
|
190
|
+
*
|
|
191
|
+
* Returns the vector input reference for use in subsequent move calls as argument or to be transferred.
|
|
192
|
+
*
|
|
193
|
+
* @param {Object} params - Configuration parameters
|
|
194
|
+
* @param {string} params.packageId - The package ID ('mainnet', 'testnet', or explicit package ID)
|
|
195
|
+
* @param {Uint8Array|null} [arr=null] - Optional Uint8Array to push back to the new vector as the first item
|
|
196
|
+
* @param {Transaction|null} [txToAppendTo=null] - Optional existing transaction to append the move calls to
|
|
197
|
+
* @returns {Promise<TransactionResult>} Vector input reference for use in subsequent move calls
|
|
198
|
+
* @throws {Error} Throws if packageId is not provided or invalid
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* // Create an empty vector
|
|
202
|
+
* const vectorInput = await EndlessVector.getCreateTransactionAndReturnVectorInput({
|
|
203
|
+
* packageId: 'mainnet'
|
|
204
|
+
* });
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* // Create and populate a vector within an existing transaction
|
|
208
|
+
* const data = new Uint8Array([1, 2, 3, 4]);
|
|
209
|
+
* const tx = new Transaction();
|
|
210
|
+
* const vectorInput = await EndlessVector.getCreateTransactionAndReturnVectorInput({
|
|
211
|
+
* packageId: contract.id
|
|
212
|
+
* }, data, tx);
|
|
213
|
+
*/
|
|
214
|
+
static async getCreateTransactionAndReturnVectorInput(params, arr = null, txToAppendTo = null) {
|
|
215
|
+
const { packageId } = params;
|
|
216
|
+
let normalizedPackageId = packageId;
|
|
217
|
+
if (normalizedPackageId == 'mainnet') {
|
|
218
|
+
normalizedPackageId = ids['mainnet'].packageId;
|
|
219
|
+
} else if (normalizedPackageId == 'testnet') {
|
|
220
|
+
normalizedPackageId = ids['testnet'].packageId;
|
|
221
|
+
}
|
|
190
222
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
*/
|
|
194
|
-
getPushTransaction(arr, txToAppendTo = null) {
|
|
195
|
-
if (!this._packageId) {
|
|
196
|
-
throw new Error('packageId is required to compose push transaction');
|
|
223
|
+
if (!normalizedPackageId) {
|
|
224
|
+
throw new Error('packageId is required');
|
|
197
225
|
}
|
|
226
|
+
// Create transaction to call empty_entry
|
|
198
227
|
|
|
199
228
|
let tx = txToAppendTo;
|
|
200
229
|
if (!tx) {
|
|
201
230
|
tx = new Transaction();
|
|
202
231
|
}
|
|
203
232
|
|
|
233
|
+
const vectorInput = tx.moveCall({
|
|
234
|
+
target: `${normalizedPackageId}::endless_vector::empty`,
|
|
235
|
+
arguments: [],
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
if (arr && arr) {
|
|
239
|
+
EndlessVector.composePushTransaction(normalizedPackageId, vectorInput, arr, tx);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return vectorInput;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
get isWritable() {
|
|
246
|
+
return !!(this._packageId && this._signAndExecuteTransaction);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Attach move calls to transaction, to push item into endlessvector, handling large arrays by chunking them.
|
|
251
|
+
* This static method can be used to compose transactions for any existing EndlessVector instance:
|
|
252
|
+
* tx.object(vector.id)
|
|
253
|
+
* or newly created one, accepting TransactionResult as vectorInput, see: getCreateTransactionAndReturnVectorInput
|
|
254
|
+
*
|
|
255
|
+
* For arrays smaller than 12KB, it uses a single push_back call.
|
|
256
|
+
* For arrays between 12KB and 120KB, it splits the data into 10 chunks and uses compose_and_push_back.
|
|
257
|
+
*
|
|
258
|
+
* @static
|
|
259
|
+
* @param {string} packageId - The package ID of the Move module containing the endless_vector functions
|
|
260
|
+
* @param {TransactionObjectArgument} vectorInput - The transaction object argument representing the EndlessVector
|
|
261
|
+
* @param {Uint8Array} arr - The byte array to push to the vector
|
|
262
|
+
* @param {Transaction} tx - The transaction object to append the move calls to
|
|
263
|
+
* @returns {Transaction} The transaction object with the push operations added
|
|
264
|
+
* @throws {Error} If the array is larger than 120KB (10 * 12KB)
|
|
265
|
+
*/
|
|
266
|
+
static composePushTransaction(packageId, vectorInput, arr, tx) {
|
|
204
267
|
const maxArgLength = 12 * 1024;
|
|
205
268
|
if (arr.length < maxArgLength) {
|
|
206
269
|
tx.moveCall({
|
|
207
|
-
target: `${
|
|
270
|
+
target: `${packageId}::endless_vector::push_back`,
|
|
208
271
|
arguments: [
|
|
209
|
-
|
|
272
|
+
vectorInput,
|
|
210
273
|
tx.pure(bcs.vector(bcs.u8()).serialize(arr)),
|
|
211
274
|
],
|
|
212
275
|
});
|
|
@@ -223,17 +286,41 @@ export default class EndlessVector {
|
|
|
223
286
|
chunks.push(new Uint8Array()); // empty chunk
|
|
224
287
|
}
|
|
225
288
|
}
|
|
226
|
-
const args = [
|
|
289
|
+
const args = [vectorInput];
|
|
227
290
|
for (let i = 0; i < N; i++) {
|
|
228
291
|
args.push(tx.pure(bcs.vector(bcs.u8()).serialize(chunks[i])));
|
|
229
292
|
}
|
|
230
293
|
tx.moveCall({
|
|
231
|
-
target: `${
|
|
294
|
+
target: `${packageId}::endless_vector::compose_and_push_back`,
|
|
232
295
|
arguments: args,
|
|
233
296
|
});
|
|
234
297
|
} else {
|
|
235
298
|
throw new Error('Array too large, max '+(10*maxArgLength)+' bytes supported per single tx');
|
|
236
299
|
}
|
|
300
|
+
|
|
301
|
+
return tx;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Creates a transaction to push new byte arrays to the EndlessVector.
|
|
307
|
+
* Note: this method only creates the transaction, it does not sign or execute it.
|
|
308
|
+
|
|
309
|
+
* @param {Uint8Array} arr - Uint8Array to push
|
|
310
|
+
* @returns {Transaction} The transaction object to be signed and executed
|
|
311
|
+
*/
|
|
312
|
+
getPushTransaction(arr, txToAppendTo = null) {
|
|
313
|
+
if (!this._packageId) {
|
|
314
|
+
throw new Error('packageId is required to compose push transaction');
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
let tx = txToAppendTo;
|
|
318
|
+
if (!tx) {
|
|
319
|
+
tx = new Transaction();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
EndlessVector.composePushTransaction(this._packageId, tx.object(this.id), arr, tx);
|
|
323
|
+
|
|
237
324
|
return tx;
|
|
238
325
|
}
|
|
239
326
|
|
package/README.md
CHANGED
|
@@ -32,10 +32,7 @@ const vector = await EndlessVector.create({
|
|
|
32
32
|
const vectorWithData = await EndlessVector.create({
|
|
33
33
|
suiClient: client,
|
|
34
34
|
packageId: 'testnet', // or 'mainnet' or '0xYOUR_PACKAGE_ID'
|
|
35
|
-
|
|
36
|
-
new Uint8Array([1, 2, 3]),
|
|
37
|
-
new Uint8Array([4, 5, 6])
|
|
38
|
-
],
|
|
35
|
+
array: new Uint8Array([1, 2, 3]), // [0] to append to EndlessVector
|
|
39
36
|
signAndExecuteTransaction: async (tx) => {
|
|
40
37
|
const result = await wallet.signAndExecuteTransaction({ transaction: tx });
|
|
41
38
|
return result.digest;
|
|
@@ -57,7 +54,7 @@ console.log('Total items:', vector.length);
|
|
|
57
54
|
console.log('Total size:', vector.binaryLength, 'bytes');
|
|
58
55
|
|
|
59
56
|
// Read items
|
|
60
|
-
const firstItem = await vector.at(0);
|
|
57
|
+
const firstItem = await vector.at(0); // Uint8Array
|
|
61
58
|
```
|
|
62
59
|
|
|
63
60
|
## API Reference
|
|
@@ -72,7 +69,7 @@ Creates a new EndlessVector on the blockchain.
|
|
|
72
69
|
- `suiClient` (SuiClient) - Sui client instance for blockchain interactions
|
|
73
70
|
- `packageId` (string) - 'testnet', 'mainnet', or ID of the Move package containing the EndlessVector module
|
|
74
71
|
- `signAndExecuteTransaction` (function) - Function to sign and execute transactions
|
|
75
|
-
- `
|
|
72
|
+
- `array` (Uint8Array, optional) - Optional first vector<u8> to push back to the new vector
|
|
76
73
|
- `gasCoin` (Object, optional) - Gas coin object reference `{objectId: string, digest: string, version: string}` for transaction payment
|
|
77
74
|
- `options` (Object, optional) - Additional options:
|
|
78
75
|
- `timeout` (number) - Transaction confirmation timeout in ms (default: 30000)
|
|
@@ -85,7 +82,7 @@ Creates a new EndlessVector on the blockchain.
|
|
|
85
82
|
const vector = await EndlessVector.create({
|
|
86
83
|
suiClient: client,
|
|
87
84
|
packageId: 'testnet', // or 'mainnet' or '0xPACKAGE_ID'
|
|
88
|
-
|
|
85
|
+
array: new Uint8Array([1, 2, 3]),
|
|
89
86
|
gasCoin: {
|
|
90
87
|
objectId: '0xGAS_COIN_ID',
|
|
91
88
|
digest: 'DIGEST',
|
|
@@ -276,7 +273,7 @@ const vectors = await Promise.all(
|
|
|
276
273
|
EndlessVector.create({
|
|
277
274
|
suiClient: client,
|
|
278
275
|
packageId: 'testnet', // or 'mainnet' or '0xPACKAGE_ID'
|
|
279
|
-
|
|
276
|
+
array: items,
|
|
280
277
|
gasCoin: gasCoinRefs[i],
|
|
281
278
|
signAndExecuteTransaction: async (tx) => {
|
|
282
279
|
const result = await wallet.signAndExecuteTransaction({ transaction: tx });
|
package/ids.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
export default {
|
|
3
3
|
'testnet': {
|
|
4
|
-
packageId: '
|
|
5
|
-
originalPackageId: '
|
|
4
|
+
packageId: '0x30bf8e91f40774ed08234f767360b4154562232903928b5f2f8fe5b2d51655bc', // should be the same as in Move.lock
|
|
5
|
+
originalPackageId: '0x30bf8e91f40774ed08234f767360b4154562232903928b5f2f8fe5b2d51655bc',
|
|
6
6
|
},
|
|
7
7
|
'mainnet': {
|
|
8
|
-
packageId: '
|
|
9
|
-
originalPackageId: '
|
|
8
|
+
packageId: '0x94cf19d164f014cfe73dda1121f27b54b69f0dbfa89d8b6ed48ae8a9144f5d65', // should be the same as in Move.lock
|
|
9
|
+
originalPackageId: '0x94cf19d164f014cfe73dda1121f27b54b69f0dbfa89d8b6ed48ae8a9144f5d65',
|
|
10
10
|
},
|
|
11
11
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fizzyflow/endless-vector",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"author": "suidouble (https://github.com/suidouble)",
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"scripts": {
|
|
27
|
-
"test": "tap -j1 -
|
|
27
|
+
"test": "tap -j1 -t320 ./test/*.test.js"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"@mysten/sui": "^1.44.0"
|
package/test/base.test.js
CHANGED
|
@@ -71,6 +71,50 @@ test('attach a local package', async t => {
|
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
|
|
74
|
+
test('test raw create transaction', async t => {
|
|
75
|
+
const arr = randomBytesOfLength(120 * 1024); // 100KB
|
|
76
|
+
|
|
77
|
+
const tx = new suiMaster.Transaction();
|
|
78
|
+
const vectorTxInput = await EndlessVector.getCreateTransactionAndReturnVectorInput({
|
|
79
|
+
packageId: contract.id,
|
|
80
|
+
}, arr, tx);
|
|
81
|
+
tx.transferObjects([vectorTxInput], tx.pure.address(suiMaster.address));
|
|
82
|
+
|
|
83
|
+
t.ok(tx);
|
|
84
|
+
let digest = null;
|
|
85
|
+
try {
|
|
86
|
+
digest = await signAndExecuteTransaction(tx);
|
|
87
|
+
t.ok(digest);
|
|
88
|
+
} catch (e) {
|
|
89
|
+
console.error('Error preparing transaction:', e);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const transactionBlockResponse = await suiMaster.client.waitForTransaction({
|
|
93
|
+
digest: digest,
|
|
94
|
+
options: { showObjectChanges: true, },
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Find the created EndlessVector object
|
|
98
|
+
const objectChanges = transactionBlockResponse.objectChanges || [];
|
|
99
|
+
const createdVector = objectChanges.find(
|
|
100
|
+
change => change.type === 'created' &&
|
|
101
|
+
change.objectType &&
|
|
102
|
+
change.objectType.includes('endless_vector::EndlessVector')
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const createdVectorId = createdVector ? createdVector.objectId : null;
|
|
106
|
+
t.ok(createdVectorId, 'Created EndlessVector object should have an ID');
|
|
107
|
+
|
|
108
|
+
const loadBack = new EndlessVector({
|
|
109
|
+
suiClient: suiMaster.client,
|
|
110
|
+
id: createdVectorId,
|
|
111
|
+
});
|
|
112
|
+
await loadBack.initialize();
|
|
113
|
+
|
|
114
|
+
t.ok(loadBack.length === 1, `Loaded vector should have length 1, got ${loadBack.length}`);
|
|
115
|
+
const getBack = await loadBack.at(0);
|
|
116
|
+
t.ok(equalUint8Arrays(getBack, arr), 'Data retrieved from loaded vector should match original data');
|
|
117
|
+
});
|
|
74
118
|
|
|
75
119
|
|
|
76
120
|
test('make a test EndlessVector and push single Uint8Array to it', async t => {
|
|
@@ -358,7 +402,7 @@ test('test parallel creation, push, and append of 6 vectors', async t => {
|
|
|
358
402
|
// Prepare test data for each vector
|
|
359
403
|
const testData = [];
|
|
360
404
|
for (let i = 0; i < vectorCount; i++) {
|
|
361
|
-
testData.push(
|
|
405
|
+
testData.push(randomBytesOfLength(1024));
|
|
362
406
|
}
|
|
363
407
|
|
|
364
408
|
// Create N EndlessVectors in parallel using static create method
|
|
@@ -368,7 +412,7 @@ test('test parallel creation, push, and append of 6 vectors', async t => {
|
|
|
368
412
|
EndlessVector.create({
|
|
369
413
|
suiClient: suiMaster.client,
|
|
370
414
|
packageId: contract.id,
|
|
371
|
-
|
|
415
|
+
array: testData[i] ? testData[i] : null,
|
|
372
416
|
gasCoin: gasCoinInputs[i],
|
|
373
417
|
signAndExecuteTransaction: async (tx) => {
|
|
374
418
|
console.log(`Creating vector ${i}...`);
|
|
@@ -407,24 +451,20 @@ test('test parallel creation, push, and append of 6 vectors', async t => {
|
|
|
407
451
|
// Verify the data after concatenation
|
|
408
452
|
await mainVector.initialize();
|
|
409
453
|
|
|
410
|
-
|
|
411
|
-
const expectedLength = vectorCount * 2;
|
|
454
|
+
const expectedLength = vectorCount;
|
|
412
455
|
t.ok(mainVector.length === expectedLength, `mainVector should have ${expectedLength} items, got ${mainVector.length}`);
|
|
413
456
|
|
|
414
457
|
console.log(`Verifying ${expectedLength} items in concatenated vector...`);
|
|
415
458
|
|
|
416
459
|
// Verify each item matches the original testData
|
|
417
460
|
for (let vectorIdx = 0; vectorIdx < vectorCount; vectorIdx++) {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
`Item ${globalIdx} (vector ${vectorIdx}, item ${itemIdx}) should match`
|
|
426
|
-
);
|
|
427
|
-
}
|
|
461
|
+
const expected = testData[vectorIdx];
|
|
462
|
+
const retrieved = await mainVector.at(vectorIdx);
|
|
463
|
+
|
|
464
|
+
t.ok(
|
|
465
|
+
equalUint8Arrays(retrieved, expected),
|
|
466
|
+
`Item ${vectorIdx} (vector ${vectorIdx}, item ${vectorIdx}) should match`
|
|
467
|
+
);
|
|
428
468
|
}
|
|
429
469
|
});
|
|
430
470
|
|