fix chunking in gma + add chunk util function (#14)

* fix chunking in gma + add chunk util function

* rename resp variable and re-order arg options

---------

Co-authored-by: solpkr <solpkr1@gmail.com>
This commit is contained in:
solpkr 2023-02-15 16:31:45 +00:00 committed by GitHub
parent 881cbf7cb0
commit cd5e13c19c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 57 deletions

View File

@ -13,7 +13,7 @@ import {
BlockhashWithExpiryBlockHeight,
TransactionInstruction,
} from '@solana/web3.js';
import { getMultipleAccounts, sleep } from '../utils/utils';
import { getMultipleAccounts, sleep, chunk } from '../utils/utils';
import BN from 'bn.js';
import {
decodeEventQueue,
@ -243,11 +243,7 @@ async function run() {
if(crankInstructionsQueue.length > 0){
//chunk the instructions to ensure transactions are not too large
let chunkedCrankInstructions: any[] = [];
let chunkSize = maxTxInstructions;
for (let i = 0; i < crankInstructionsQueue.length; i += chunkSize) {
chunkedCrankInstructions.push(crankInstructionsQueue.slice(i, i + chunkSize));
}
let chunkedCrankInstructions = chunk(crankInstructionsQueue, maxTxInstructions);
chunkedCrankInstructions.forEach(function (transactionInstructions){

View File

@ -11,66 +11,59 @@ export async function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export function chunk(array, size) {
return Array.apply(0, new Array(Math.ceil(array.length / size))).map((_, index) => array.slice(index * size, (index + 1) * size));
}
export async function getMultipleAccounts(
connection: Connection,
publicKeys: PublicKey[],
commitment?: Commitment,
minContextSlot?: number,
): Promise<
{
publicKey: PublicKey;
context: { slot: number };
accountInfo: AccountInfo<Buffer>;
}[]
> {
const len = publicKeys.length;
if (len === 0) {
return [];
): Promise<{
publicKey: PublicKey;
context: { slot: number };
accountInfo: AccountInfo<Buffer>;
}[]> {
if (!publicKeys.length) {
throw new Error('no Public Keys provided to getMultipleAccounts');
}
if (len > 100) {
const mid = Math.floor(publicKeys.length / 2);
return Promise.all([
getMultipleAccounts(connection, publicKeys.slice(0, mid), commitment),
getMultipleAccounts(connection, publicKeys.slice(mid, len), commitment),
]).then((a) => a[0].concat(a[1]));
}
const publicKeyStrs = publicKeys.map((pk) => pk.toBase58());
// load connection commitment as a default
commitment ||= connection.commitment;
//set the maximum number of accounts per call
let chunkedPks = chunk(publicKeys, 100);
// set no minimum context slot by default
minContextSlot ||= 0;
//asynchronously fetch each chunk of accounts and combine the results
return (await Promise.all(chunkedPks.map(async function (pkChunk) {
//use zstd to compress large responses
let encoding = 'base64+zstd';
// load connection commitment as a default
commitment ||= connection.commitment;
//use zstd to compress large responses
let encoding = 'base64+zstd';
// set no minimum context slot by default
minContextSlot ||= 0;
const args = [publicKeyStrs, {commitment,encoding,minContextSlot}];
const args = [pkChunk, {commitment, encoding, minContextSlot}];
// @ts-ignore
const gmaResult = await connection._rpcRequest('getMultipleAccounts', args);
if (gmaResult.error) {
throw new Error(gmaResult.error.message);
}
return gmaResult.result.value.map(
({data, executable, lamports, owner}, i) => ({
publicKey: pkChunk[i],
context: gmaResult.result.context,
accountInfo: {
data: Buffer.from(fzstd.decompress(Buffer.from(data[0], 'base64'))),
executable,
owner: new PublicKey(owner),
lamports,
},
}),
);
}))).flat();
// @ts-ignore
const resp = await connection._rpcRequest('getMultipleAccounts', args);
if (resp.error) {
throw new Error(resp.error.message);
}
if (resp.result) {
const nullResults = resp.result.value.filter((r) => r?.account === null);
if (nullResults.length > 0)
throw new Error(
`gma returned ${
nullResults.length
} null results. ex: ${nullResults[0]?.pubkey.toString()}`,
);
}
return resp.result.value.map(
({ data, executable, lamports, owner }, i: number) => ({
publicKey: publicKeys[i],
context: resp.result.context,
accountInfo: {
data: Buffer.from(fzstd.decompress(Buffer.from(data[0], 'base64'))),
executable,
owner: new PublicKey(owner),
lamports,
},
}),
);
}