@helium/account-fetch-cache
Advanced tools
Comparing version 0.2.5 to 0.2.14-next.102
@@ -12,5 +12,6 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.AccountFetchCache = exports.DEFAULT_DELAY = exports.DEFAULT_CHUNK_SIZE = void 0; | ||
exports.AccountFetchCache = exports.getSingleton = exports.DEFAULT_DELAY = exports.DEFAULT_CHUNK_SIZE = void 0; | ||
const web3_js_1 = require("@solana/web3.js"); | ||
const eventEmitter_1 = require("./eventEmitter"); | ||
const getMultipleAccounts_1 = require("./getMultipleAccounts"); | ||
exports.DEFAULT_CHUNK_SIZE = 99; | ||
@@ -25,2 +26,20 @@ exports.DEFAULT_DELAY = 50; | ||
let id = 0; | ||
let singletons = {}; | ||
function getSingleton(conn) { | ||
const commitment = conn.commitment || "confirmed"; | ||
const endp = conn.rpcEndpoint; | ||
if (!singletons[endp + commitment]) { | ||
singletons[endp + commitment] = new AccountFetchCache({ | ||
connection: conn, | ||
commitment, | ||
}); | ||
} | ||
return singletons[endp + commitment]; | ||
} | ||
exports.getSingleton = getSingleton; | ||
function setSingleton(conn, cache) { | ||
const commitment = conn.commitment || "confirmed"; | ||
const endp = conn.rpcEndpoint; | ||
singletons[endp + commitment] = cache; | ||
} | ||
class AccountFetchCache { | ||
@@ -39,2 +58,3 @@ constructor({ connection, chunkSize = exports.DEFAULT_CHUNK_SIZE, delay = exports.DEFAULT_DELAY, commitment, missingRefetchDelay = 10000, extendConnection = false, }) { | ||
this.emitter = new eventEmitter_1.EventEmitter(); | ||
this.id = ++id; | ||
this.connection = connection; | ||
@@ -46,6 +66,8 @@ this.chunkSize = chunkSize; | ||
this.oldSendTransaction = connection.sendTransaction.bind(connection); | ||
this.oldSendRawTransaction = | ||
connection.sendRawTransaction.bind(connection); | ||
this.oldSendRawTransaction = connection.sendRawTransaction.bind(connection); | ||
const self = this; | ||
if (extendConnection) { | ||
// @ts-ignore | ||
if (extendConnection && !connection._accountFetchWrapped) { | ||
// @ts-ignore | ||
connection._accountFetchWrapped = true; | ||
this.oldGetAccountinfo = connection.getAccountInfo.bind(connection); | ||
@@ -90,2 +112,3 @@ connection.getAccountInfo = (publicKey, com) => __awaiter(this, void 0, void 0, function* () { | ||
}; | ||
setSingleton(connection, this); | ||
} | ||
@@ -131,3 +154,3 @@ requeryMissing(instructions) { | ||
const keys = Array.from(currentBatch); | ||
const array = yield this.connection.getMultipleAccountsInfo(keys.map(b => new web3_js_1.PublicKey(b)), this.commitment); | ||
const { array } = yield (0, getMultipleAccounts_1.getMultipleAccounts)(this.connection, keys, this.commitment); | ||
keys.forEach((key, index) => { | ||
@@ -148,2 +171,14 @@ const callback = this.pendingCallbacks.get(key); | ||
} | ||
addToBatchIgnoreResult(id) { | ||
const idStr = id.toBase58(); | ||
this.currentBatch.add(idStr); | ||
this.timeout != null && clearTimeout(this.timeout); | ||
if (this.currentBatch.size > exports.DEFAULT_CHUNK_SIZE) { | ||
return this.fetchBatch(); | ||
} | ||
else { | ||
this.timeout = setTimeout(() => this.fetchBatch(), this.delay); | ||
} | ||
return undefined; | ||
} | ||
addToBatch(id) { | ||
@@ -249,2 +284,4 @@ return __awaiter(this, void 0, void 0, function* () { | ||
// Rely on searchAndWatch to set the generic cache for everything else. | ||
// Never update the cache with an account that isn't being watched. This could cause | ||
// stale data to be returned. | ||
if (isStatic && result && result.info) { | ||
@@ -259,2 +296,62 @@ this.updateCache(address, result); | ||
} | ||
searchMultiple(pubKeys, parser, isStatic = false, // optimization, set if the data will never change | ||
forceRequery = false) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Store results of batch fetches in this map. If isStatic is false, genericCache will have none of the | ||
// results of our searches in the batch. So need to accumulate them here | ||
const result = {}; | ||
const searched = new Set(pubKeys.map((p) => p.toBase58())); | ||
for (const key of pubKeys) { | ||
this.registerParser(key, parser); | ||
const address = key.toBase58(); | ||
if (isStatic) { | ||
this.statics.add(address); | ||
} | ||
else if (this.statics.has(address)) { | ||
this.statics.delete(address); // If trying to use this as not static, need to rm it from the statics list. | ||
} | ||
if (forceRequery || !this.genericCache.has(address)) { | ||
const { keys, array } = (yield this.addToBatchIgnoreResult(key)) || { | ||
keys: [], | ||
array: [], | ||
}; | ||
keys.forEach((key, index) => { | ||
this.statics.add(key); | ||
if (searched.has(key)) { | ||
const item = array[index]; | ||
if (item) { | ||
const parsed = this.getParsed(key, item, parser) || null; | ||
// Cache these results if they aren't going to change | ||
if (isStatic) { | ||
this.genericCache.set(key, parsed); | ||
} | ||
if (parsed) { | ||
result[key] = parsed; | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
// Force a batch fetch to resolve all accounts | ||
const { keys, array } = yield this.fetchBatch(); | ||
keys.forEach((key, index) => { | ||
this.statics.add(key); | ||
if (searched.has(key)) { | ||
const item = array[index]; | ||
if (item) { | ||
const parsed = this.getParsed(key, item, parser) || null; | ||
// Cache these results if they aren't going to change | ||
if (isStatic) { | ||
this.genericCache.set(key, parsed); | ||
} | ||
if (parsed) { | ||
result[key] = parsed; | ||
} | ||
} | ||
} | ||
}); | ||
return pubKeys.map((key) => result[key.toBase58()] || this.genericCache.get(key.toBase58())); | ||
}); | ||
} | ||
onAccountChange(key, parser, account) { | ||
@@ -264,3 +361,2 @@ try { | ||
const address = key.toBase58(); | ||
console.log("accountFetchCache", `Received account change ${key}`, parsed); | ||
this.updateCache(address, parsed || null); | ||
@@ -267,0 +363,0 @@ } |
@@ -1,3 +0,4 @@ | ||
import { Connection, PublicKey, Transaction } from "@solana/web3.js"; | ||
import { Connection, PublicKey, Transaction, } from "@solana/web3.js"; | ||
import { EventEmitter } from "./eventEmitter"; | ||
import { getMultipleAccounts } from "./getMultipleAccounts"; | ||
export const DEFAULT_CHUNK_SIZE = 99; | ||
@@ -12,2 +13,19 @@ export const DEFAULT_DELAY = 50; | ||
let id = 0; | ||
let singletons = {}; | ||
export function getSingleton(conn) { | ||
const commitment = conn.commitment || "confirmed"; | ||
const endp = conn.rpcEndpoint; | ||
if (!singletons[endp + commitment]) { | ||
singletons[endp + commitment] = new AccountFetchCache({ | ||
connection: conn, | ||
commitment, | ||
}); | ||
} | ||
return singletons[endp + commitment]; | ||
} | ||
function setSingleton(conn, cache) { | ||
const commitment = conn.commitment || "confirmed"; | ||
const endp = conn.rpcEndpoint; | ||
singletons[endp + commitment] = cache; | ||
} | ||
export class AccountFetchCache { | ||
@@ -29,2 +47,3 @@ connection; | ||
emitter = new EventEmitter(); | ||
id; // For debugging, to see which cache is being used | ||
oldGetAccountinfo; | ||
@@ -35,2 +54,3 @@ oldSendTransaction; | ||
constructor({ connection, chunkSize = DEFAULT_CHUNK_SIZE, delay = DEFAULT_DELAY, commitment, missingRefetchDelay = 10000, extendConnection = false, }) { | ||
this.id = ++id; | ||
this.connection = connection; | ||
@@ -42,6 +62,8 @@ this.chunkSize = chunkSize; | ||
this.oldSendTransaction = connection.sendTransaction.bind(connection); | ||
this.oldSendRawTransaction = | ||
connection.sendRawTransaction.bind(connection); | ||
this.oldSendRawTransaction = connection.sendRawTransaction.bind(connection); | ||
const self = this; | ||
if (extendConnection) { | ||
// @ts-ignore | ||
if (extendConnection && !connection._accountFetchWrapped) { | ||
// @ts-ignore | ||
connection._accountFetchWrapped = true; | ||
this.oldGetAccountinfo = connection.getAccountInfo.bind(connection); | ||
@@ -82,2 +104,3 @@ connection.getAccountInfo = async (publicKey, com) => { | ||
}; | ||
setSingleton(connection, this); | ||
} | ||
@@ -118,3 +141,3 @@ async requeryMissing(instructions) { | ||
const keys = Array.from(currentBatch); | ||
const array = await this.connection.getMultipleAccountsInfo(keys.map(b => new PublicKey(b)), this.commitment); | ||
const { array } = await getMultipleAccounts(this.connection, keys, this.commitment); | ||
keys.forEach((key, index) => { | ||
@@ -134,2 +157,14 @@ const callback = this.pendingCallbacks.get(key); | ||
} | ||
addToBatchIgnoreResult(id) { | ||
const idStr = id.toBase58(); | ||
this.currentBatch.add(idStr); | ||
this.timeout != null && clearTimeout(this.timeout); | ||
if (this.currentBatch.size > DEFAULT_CHUNK_SIZE) { | ||
return this.fetchBatch(); | ||
} | ||
else { | ||
this.timeout = setTimeout(() => this.fetchBatch(), this.delay); | ||
} | ||
return undefined; | ||
} | ||
async addToBatch(id) { | ||
@@ -230,2 +265,4 @@ const idStr = id.toBase58(); | ||
// Rely on searchAndWatch to set the generic cache for everything else. | ||
// Never update the cache with an account that isn't being watched. This could cause | ||
// stale data to be returned. | ||
if (isStatic && result && result.info) { | ||
@@ -239,2 +276,60 @@ this.updateCache(address, result); | ||
} | ||
async searchMultiple(pubKeys, parser, isStatic = false, // optimization, set if the data will never change | ||
forceRequery = false) { | ||
// Store results of batch fetches in this map. If isStatic is false, genericCache will have none of the | ||
// results of our searches in the batch. So need to accumulate them here | ||
const result = {}; | ||
const searched = new Set(pubKeys.map((p) => p.toBase58())); | ||
for (const key of pubKeys) { | ||
this.registerParser(key, parser); | ||
const address = key.toBase58(); | ||
if (isStatic) { | ||
this.statics.add(address); | ||
} | ||
else if (this.statics.has(address)) { | ||
this.statics.delete(address); // If trying to use this as not static, need to rm it from the statics list. | ||
} | ||
if (forceRequery || !this.genericCache.has(address)) { | ||
const { keys, array } = (await this.addToBatchIgnoreResult(key)) || { | ||
keys: [], | ||
array: [], | ||
}; | ||
keys.forEach((key, index) => { | ||
this.statics.add(key); | ||
if (searched.has(key)) { | ||
const item = array[index]; | ||
if (item) { | ||
const parsed = this.getParsed(key, item, parser) || null; | ||
// Cache these results if they aren't going to change | ||
if (isStatic) { | ||
this.genericCache.set(key, parsed); | ||
} | ||
if (parsed) { | ||
result[key] = parsed; | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
// Force a batch fetch to resolve all accounts | ||
const { keys, array } = await this.fetchBatch(); | ||
keys.forEach((key, index) => { | ||
this.statics.add(key); | ||
if (searched.has(key)) { | ||
const item = array[index]; | ||
if (item) { | ||
const parsed = this.getParsed(key, item, parser) || null; | ||
// Cache these results if they aren't going to change | ||
if (isStatic) { | ||
this.genericCache.set(key, parsed); | ||
} | ||
if (parsed) { | ||
result[key] = parsed; | ||
} | ||
} | ||
} | ||
}); | ||
return pubKeys.map((key) => result[key.toBase58()] || this.genericCache.get(key.toBase58())); | ||
} | ||
onAccountChange(key, parser, account) { | ||
@@ -244,3 +339,2 @@ try { | ||
const address = key.toBase58(); | ||
console.log("accountFetchCache", `Received account change ${key}`, parsed); | ||
this.updateCache(address, parsed || null); | ||
@@ -247,0 +341,0 @@ } |
@@ -14,2 +14,3 @@ /// <reference types="node" /> | ||
export type AccountParser<T> = (pubkey: PublicKey, data: AccountInfo<Buffer>) => ParsedAccountBase<T> | undefined; | ||
export declare function getSingleton(conn: Connection): AccountFetchCache; | ||
export declare class AccountFetchCache { | ||
@@ -23,5 +24,5 @@ connection: Connection; | ||
statics: Set<string>; | ||
missingAccounts: Map<string, AccountParser<unknown>>; | ||
genericCache: Map<string, ParsedAccountBase<unknown>>; | ||
keyToAccountParser: Map<string, AccountParser<unknown>>; | ||
missingAccounts: Map<string, AccountParser<unknown> | undefined>; | ||
genericCache: Map<string, ParsedAccountBase<unknown> | null>; | ||
keyToAccountParser: Map<string, AccountParser<unknown> | undefined>; | ||
timeout: NodeJS.Timeout | null; | ||
@@ -32,2 +33,3 @@ currentBatch: Set<string>; | ||
emitter: EventEmitter; | ||
id: number; | ||
oldGetAccountinfo?: (publicKey: PublicKey, com?: Commitment) => Promise<AccountInfo<Buffer> | null>; | ||
@@ -53,2 +55,6 @@ oldSendTransaction: (...args: any[]) => Promise<string>; | ||
}>; | ||
addToBatchIgnoreResult(id: PublicKey): Promise<{ | ||
keys: string[]; | ||
array: AccountInfo<Buffer>[]; | ||
}> | undefined; | ||
addToBatch(id: PublicKey): Promise<AccountInfo<Buffer>>; | ||
@@ -62,2 +68,4 @@ flush(): Promise<void>; | ||
forceRequery?: boolean): Promise<ParsedAccountBase<T> | undefined>; | ||
searchMultiple<T>(pubKeys: PublicKey[], parser?: AccountParser<T> | undefined, isStatic?: Boolean, // optimization, set if the data will never change | ||
forceRequery?: boolean): Promise<(ParsedAccountBase<T> | undefined)[]>; | ||
onAccountChange<T>(key: PublicKey, parser: AccountParser<T> | undefined, account: AccountInfo<Buffer>): void; | ||
@@ -67,3 +75,3 @@ watch<T>(id: PublicKey, parser?: AccountParser<T> | undefined, exists?: Boolean): () => void; | ||
getParsed<T>(id: PublicKey | string, obj: AccountInfo<Buffer>, parser?: AccountParser<T>): ParsedAccountBase<T> | undefined; | ||
get(pubKey: string | PublicKey): ParsedAccountBase<unknown>; | ||
get(pubKey: string | PublicKey): ParsedAccountBase<unknown> | null | undefined; | ||
delete(pubKey: string | PublicKey): boolean; | ||
@@ -70,0 +78,0 @@ byParser<T>(parser: AccountParser<T>): string[]; |
{ | ||
"name": "@helium/account-fetch-cache", | ||
"version": "0.2.5", | ||
"version": "0.2.14-next.102+29959a97", | ||
"description": "Solana account fetch cache to eliminate reduntant fetching, and batch fetches", | ||
@@ -34,3 +34,3 @@ "publishConfig": { | ||
"dependencies": { | ||
"@solana/web3.js": "^1.43.4" | ||
"@solana/web3.js": "^1.78.4" | ||
}, | ||
@@ -40,6 +40,6 @@ "devDependencies": { | ||
"ts-loader": "^9.2.3", | ||
"typescript": "^4.3.4", | ||
"typescript": "^4.8.4", | ||
"yarn": "^1.22.18" | ||
}, | ||
"gitHead": "d391d5f039aef3f222ebfa5ca69bcc403fff86a7" | ||
"gitHead": "29959a976df5e40c25f66f9f8ff7fb0c6ace125f" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
145653
1266
1
Updated@solana/web3.js@^1.78.4