@fizzyflow/endless-vector 0.0.2 → 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 +118 -24
- 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,12 +104,19 @@ 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;
|
|
108
|
+
|
|
109
|
+
let normalizedPackageId = packageId;
|
|
110
|
+
if (normalizedPackageId == 'mainnet' || (!normalizedPackageId && suiClient?.network == 'mainnet')) {
|
|
111
|
+
normalizedPackageId = ids['mainnet'].packageId;
|
|
112
|
+
} else if (normalizedPackageId == 'testnet' || (!normalizedPackageId && suiClient?.network == 'testnet')) {
|
|
113
|
+
normalizedPackageId = ids['testnet'].packageId;
|
|
114
|
+
}
|
|
107
115
|
|
|
108
116
|
if (!suiClient) {
|
|
109
117
|
throw new Error('suiClient is required');
|
|
110
118
|
}
|
|
111
|
-
if (!
|
|
119
|
+
if (!normalizedPackageId) {
|
|
112
120
|
throw new Error('packageId is required');
|
|
113
121
|
}
|
|
114
122
|
if (!signAndExecuteTransaction) {
|
|
@@ -122,14 +130,17 @@ export default class EndlessVector {
|
|
|
122
130
|
tx.setGasPayment([gasCoin]);
|
|
123
131
|
}
|
|
124
132
|
|
|
125
|
-
if (
|
|
133
|
+
if (array && array.length) {
|
|
134
|
+
const vectorInput = await EndlessVector.getCreateTransactionAndReturnVectorInput({
|
|
135
|
+
packageId: normalizedPackageId,
|
|
136
|
+
}, array, tx);
|
|
126
137
|
tx.moveCall({
|
|
127
|
-
target: `${
|
|
128
|
-
arguments: [
|
|
138
|
+
target: `${normalizedPackageId}::endless_vector::transfer_to_sender`,
|
|
139
|
+
arguments: [vectorInput],
|
|
129
140
|
});
|
|
130
141
|
} else {
|
|
131
142
|
tx.moveCall({
|
|
132
|
-
target: `${
|
|
143
|
+
target: `${normalizedPackageId}::endless_vector::empty_entry`,
|
|
133
144
|
arguments: [],
|
|
134
145
|
});
|
|
135
146
|
}
|
|
@@ -168,38 +179,97 @@ export default class EndlessVector {
|
|
|
168
179
|
return new EndlessVector({
|
|
169
180
|
suiClient,
|
|
170
181
|
id: createdVector.objectId,
|
|
171
|
-
packageId,
|
|
182
|
+
packageId: normalizedPackageId,
|
|
172
183
|
signAndExecuteTransaction,
|
|
173
184
|
});
|
|
174
185
|
}
|
|
175
186
|
|
|
176
|
-
get isWritable() {
|
|
177
|
-
return !!(this._packageId && this._signAndExecuteTransaction);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
187
|
/**
|
|
181
|
-
|
|
182
|
-
|
|
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
|
+
}
|
|
183
222
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
*/
|
|
187
|
-
getPushTransaction(arr, txToAppendTo = null) {
|
|
188
|
-
if (!this._packageId) {
|
|
189
|
-
throw new Error('packageId is required to compose push transaction');
|
|
223
|
+
if (!normalizedPackageId) {
|
|
224
|
+
throw new Error('packageId is required');
|
|
190
225
|
}
|
|
226
|
+
// Create transaction to call empty_entry
|
|
191
227
|
|
|
192
228
|
let tx = txToAppendTo;
|
|
193
229
|
if (!tx) {
|
|
194
230
|
tx = new Transaction();
|
|
195
231
|
}
|
|
196
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) {
|
|
197
267
|
const maxArgLength = 12 * 1024;
|
|
198
268
|
if (arr.length < maxArgLength) {
|
|
199
269
|
tx.moveCall({
|
|
200
|
-
target: `${
|
|
270
|
+
target: `${packageId}::endless_vector::push_back`,
|
|
201
271
|
arguments: [
|
|
202
|
-
|
|
272
|
+
vectorInput,
|
|
203
273
|
tx.pure(bcs.vector(bcs.u8()).serialize(arr)),
|
|
204
274
|
],
|
|
205
275
|
});
|
|
@@ -216,17 +286,41 @@ export default class EndlessVector {
|
|
|
216
286
|
chunks.push(new Uint8Array()); // empty chunk
|
|
217
287
|
}
|
|
218
288
|
}
|
|
219
|
-
const args = [
|
|
289
|
+
const args = [vectorInput];
|
|
220
290
|
for (let i = 0; i < N; i++) {
|
|
221
291
|
args.push(tx.pure(bcs.vector(bcs.u8()).serialize(chunks[i])));
|
|
222
292
|
}
|
|
223
293
|
tx.moveCall({
|
|
224
|
-
target: `${
|
|
294
|
+
target: `${packageId}::endless_vector::compose_and_push_back`,
|
|
225
295
|
arguments: args,
|
|
226
296
|
});
|
|
227
297
|
} else {
|
|
228
298
|
throw new Error('Array too large, max '+(10*maxArgLength)+' bytes supported per single tx');
|
|
229
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
|
+
|
|
230
324
|
return tx;
|
|
231
325
|
}
|
|
232
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
|
|