Remove duplicate connection to halve websockets, then only make websocket connections for things we mostly expect to care about. Come back later for further whittling.

This commit is contained in:
Jordan Prince 2021-06-17 17:26:18 -05:00
parent 434e1c5a11
commit 6847ae8975
4 changed files with 53 additions and 41 deletions

View File

@ -13,10 +13,8 @@ import { TokenAccount } from '../models';
import { chunks } from '../utils/utils';
import { EventEmitter } from '../utils/eventEmitter';
import { useUserAccounts } from '../hooks/useUserAccounts';
import {
WRAPPED_SOL_MINT,
programIds,
} from '../utils/ids';
import { WRAPPED_SOL_MINT, programIds } from '../utils/ids';
import { AuctionParser } from '../actions';
const AccountsContext = React.createContext<any>(null);
@ -106,6 +104,8 @@ export const keyToAccountParser = new Map<string, AccountParser>();
export const cache = {
emitter: new EventEmitter(),
totalSubs: 0,
totalObjects: 0,
query: async (
connection: Connection,
pubKey: string | PublicKey,
@ -146,6 +146,7 @@ export const cache = {
id: PublicKey | string,
obj: AccountInfo<Buffer>,
parser?: AccountParser,
isEligibleForSub?: boolean | undefined | ((parsed: any) => boolean),
) => {
if (obj.data.length === 0) {
return;
@ -166,10 +167,19 @@ export const cache = {
return;
}
if (isEligibleForSub == undefined) isEligibleForSub = true;
else if (isEligibleForSub instanceof Function)
isEligibleForSub = isEligibleForSub(account);
const isNew = !genericCache.has(address);
genericCache.set(address, account);
cache.emitter.raiseCacheUpdated(address, isNew, deserialize);
cache.emitter.raiseCacheUpdated(
address,
isNew,
deserialize,
isEligibleForSub,
);
return account;
},
get: (pubKey: string | PublicKey) => {
@ -320,7 +330,7 @@ const UseNativeAccount = () => {
const id = wallet.publicKey?.toBase58();
cache.registerParser(id, TokenAccountParser);
genericCache.set(id, wrapped as TokenAccount);
cache.emitter.raiseCacheUpdated(id, false, TokenAccountParser);
cache.emitter.raiseCacheUpdated(id, false, TokenAccountParser, true);
}
}
},
@ -341,7 +351,7 @@ const UseNativeAccount = () => {
return;
}
const account = await connection.getAccountInfo(wallet.publicKey)
const account = await connection.getAccountInfo(wallet.publicKey);
updateAccount(account);
subId = connection.onAccountChange(wallet.publicKey, updateAccount);
@ -351,7 +361,7 @@ const UseNativeAccount = () => {
if (subId) {
connection.removeAccountChangeListener(subId);
}
}
};
}, [setNativeAccount, wallet, wallet?.publicKey, connection, updateCache]);
return { nativeAccount };
@ -405,7 +415,10 @@ export function AccountsProvider({ children = null as any }) {
useEffect(() => {
const subs: number[] = [];
cache.emitter.onCache(args => {
if (args.isNew) {
cache.totalObjects += 1;
if (args.isNew && args.isEligibleForSub) {
cache.totalSubs += 1;
let id = args.id;
let deserialize = args.parser;
connection.onAccountChange(new PublicKey(id), info => {
@ -435,7 +448,7 @@ export function AccountsProvider({ children = null as any }) {
programIds().token,
info => {
// TODO: fix type in web3.js
const id = (info.accountId as unknown) as string;
const id = info.accountId as unknown as string;
// TODO: do we need a better way to identify layout (maybe a enum identifing type?)
if (info.accountInfo.data.length === AccountLayout.span) {
const data = deserializeAccount(info.accountInfo.data);

View File

@ -63,7 +63,6 @@ const DEFAULT = ENDPOINTS[0].endpoint;
interface ConnectionConfig {
connection: Connection;
sendConnection: Connection;
endpoint: string;
env: ENV;
setEndpoint: (val: string) => void;
@ -75,7 +74,6 @@ const ConnectionContext = React.createContext<ConnectionConfig>({
endpoint: DEFAULT,
setEndpoint: () => {},
connection: new Connection(DEFAULT, 'recent'),
sendConnection: new Connection(DEFAULT, 'recent'),
env: ENDPOINTS[0].name,
tokens: [],
tokenMap: new Map<string, TokenInfo>(),
@ -91,10 +89,6 @@ export function ConnectionProvider({ children = undefined as any }) {
() => new Connection(endpoint, 'recent'),
[endpoint],
);
const sendConnection = useMemo(
() => new Connection(endpoint, 'recent'),
[endpoint],
);
const env =
ENDPOINTS.find(end => end.endpoint === endpoint)?.name || ENDPOINTS[0].name;
@ -144,30 +138,12 @@ export function ConnectionProvider({ children = undefined as any }) {
};
}, [connection]);
useEffect(() => {
const id = sendConnection.onAccountChange(
Keypair.generate().publicKey,
() => {},
);
return () => {
sendConnection.removeAccountChangeListener(id);
};
}, [sendConnection]);
useEffect(() => {
const id = sendConnection.onSlotChange(() => null);
return () => {
sendConnection.removeSlotChangeListener(id);
};
}, [sendConnection]);
return (
<ConnectionContext.Provider
value={{
endpoint,
setEndpoint,
connection,
sendConnection,
tokens,
tokenMap,
env,
@ -182,10 +158,6 @@ export function useConnection() {
return useContext(ConnectionContext).connection as Connection;
}
export function useSendConnection() {
return useContext(ConnectionContext)?.sendConnection;
}
export function useConnectionConfig() {
const context = useContext(ConnectionContext);
return {

View File

@ -5,10 +5,17 @@ export class CacheUpdateEvent {
id: string;
parser: any;
isNew: boolean;
constructor(id: string, isNew: boolean, parser: any) {
isEligibleForSub: boolean;
constructor(
id: string,
isNew: boolean,
parser: any,
isEligibleForSub: boolean,
) {
this.id = id;
this.parser = parser;
this.isNew = isNew;
this.isEligibleForSub = isEligibleForSub;
}
}
@ -47,10 +54,15 @@ export class EventEmitter {
this.emitter.emit(MarketUpdateEvent.type, new MarketUpdateEvent(ids));
}
raiseCacheUpdated(id: string, isNew: boolean, parser: any) {
raiseCacheUpdated(
id: string,
isNew: boolean,
parser: any,
isEligibleForSub: boolean,
) {
this.emitter.emit(
CacheUpdateEvent.type,
new CacheUpdateEvent(id, isNew, parser),
new CacheUpdateEvent(id, isNew, parser, isEligibleForSub),
);
}

View File

@ -27,6 +27,9 @@ import {
Vault,
setProgramIds,
useConnectionConfig,
useWallet,
walletAdapters,
AuctionState,
} from '@oyster/common';
import { MintInfo } from '@solana/spl-token';
import { Connection, PublicKey, PublicKeyAndAccount } from '@solana/web3.js';
@ -112,6 +115,7 @@ const MetaContext = React.createContext<MetaContextState>({
export function MetaProvider({ children = null as any }) {
const connection = useConnection();
const { wallet } = useWallet();
const { env } = useConnectionConfig();
const [metadata, setMetadata] = useState<ParsedAccount<Metadata>[]>([]);
@ -226,6 +230,7 @@ export function MetaProvider({ children = null as any }) {
processAuctions(
accounts[i],
wallet,
(cb: any) => (tempCache.auctions = cb(tempCache.auctions)),
(cb: any) =>
(tempCache.bidderMetadataByAuctionAndBidder = cb(
@ -327,6 +332,7 @@ export function MetaProvider({ children = null as any }) {
setWhitelistedCreatorsByCreator,
updateMints,
env,
wallet,
]);
useEffect(() => {
@ -408,6 +414,7 @@ export function MetaProvider({ children = null as any }) {
pubkey,
account: info.accountInfo,
},
wallet,
setAuctions,
setBidderMetadataByAuctionAndBidder,
setBidderPotsByAuctionAndBidder,
@ -537,6 +544,7 @@ const queryExtendedMetadata = async (
key,
mintAccount,
MintParser,
false,
) as ParsedAccount<MintInfo>;
if (mint.info.supply.gt(new BN(1)) || mint.info.decimals !== 0) {
// naive not NFT check
@ -576,6 +584,7 @@ function isValidHttpUrl(text: string) {
const processAuctions = (
a: PublicKeyAndAccount<Buffer>,
wallet: any,
setAuctions: any,
setBidderMetadataByAuctionAndBidder: any,
setBidderPotsByAuctionAndBidder: any,
@ -587,6 +596,7 @@ const processAuctions = (
a.pubkey,
a.account,
AuctionParser,
(auction: ParsedAccount<AuctionData>) => !auction.info.ended(),
) as ParsedAccount<AuctionData>;
setAuctions((e: any) => ({
@ -603,6 +613,8 @@ const processAuctions = (
a.pubkey,
a.account,
BidderMetadataParser,
(parsed: ParsedAccount<BidderMetadata>) =>
parsed.info.bidderPubkey.toBase58() == wallet.publicKey.toBase58(),
) as ParsedAccount<BidderMetadata>;
setBidderMetadataByAuctionAndBidder((e: any) => ({
...e,
@ -621,6 +633,8 @@ const processAuctions = (
a.pubkey,
a.account,
BidderPotParser,
(parsed: ParsedAccount<BidderPot>) =>
parsed.info.bidderAct.toBase58() == wallet.publicKey.toBase58(),
) as ParsedAccount<BidderPot>;
setBidderPotsByAuctionAndBidder((e: any) => ({
@ -714,6 +728,7 @@ const processMetaplexAccounts = async (
a.pubkey,
a.account,
WhitelistedCreatorParser,
true,
) as ParsedAccount<WhitelistedCreator>;
const nameInfo = (names as any)[account.info.address.toBase58()];