-
Notifications
You must be signed in to change notification settings - Fork 916
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(experimental): use DrainOuterGeneric helper on codec type mappings #2322
Conversation
🦋 Changeset detectedLatest commit: d309da8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 35 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This stack of pull requests is managed by Graphite. Learn more about stacking. Join @lorisleiva and the rest of your teammates on Graphite |
a8fbba0
to
2206d24
Compare
@lithdew Would you have any recommendation on how I could reproduce your performance issues? I copy/pasted the code you shared in the original issue for the benchmark above but it didn't make any difference. |
Would you be able to try a trace with this? import {
getDataEnumCodec,
getStructCodec,
getStringCodec,
getU64Codec,
getU16Codec,
getNullableCodec,
getArrayCodec,
getUnitCodec,
getBase58Codec,
getBooleanCodec,
getScalarEnumCodec,
getU8Codec,
type Codec,
} from "@solana/web3.js";
export enum Currency {
sol = "sol",
like = "like",
usdc = "usdc",
}
export const CURRENCY_CODEC = getScalarEnumCodec(Currency);
export const PUBLIC_KEY = getStringCodec({
size: 32,
encoding: getBase58Codec(),
});
export const CREATOR = getStructCodec([
["address", PUBLIC_KEY],
["verified", getBooleanCodec()],
["share", getU8Codec()],
]);
export const SPLIT = getStructCodec([
["address", PUBLIC_KEY],
["share", getU8Codec()],
]);
export const PASS_INSTRUCTION_DATA = getDataEnumCodec([
[
"create_pass",
getStructCodec([
["name", getStringCodec()],
["symbol", getStringCodec()],
["uri", getStringCodec()],
["price", getU64Codec()],
["token", CURRENCY_CODEC],
["supply", getU64Codec()],
["sellerFeeBasisPoints", getU16Codec()],
["creators", getNullableCodec(getArrayCodec(CREATOR))],
["firstSaleSplit", getArrayCodec(SPLIT)],
]),
],
[
"update_pass",
getStructCodec([
["name", getNullableCodec(getStringCodec())],
["symbol", getNullableCodec(getStringCodec())],
["uri", getNullableCodec(getStringCodec())],
["price", getNullableCodec(getU64Codec())],
["token", getNullableCodec(CURRENCY_CODEC)],
["supply", getNullableCodec(getU64Codec())],
["sellerFeeBasisPoints", getNullableCodec(getU16Codec())],
["creators", getNullableCodec(getNullableCodec(getArrayCodec(CREATOR)))],
["firstSaleSplit", getNullableCodec(getArrayCodec(SPLIT))],
]),
],
["mint_pass", getUnitCodec()],
]);
export type CodecInput<T> = T extends Codec<infer TFrom, any> ? TFrom : never;
export type CodecOutput<T> = T extends Codec<any, infer TTo> ? TTo : never;
export type PassInstructionDataInput = CodecInput<typeof PASS_INSTRUCTION_DATA>;
export type PassInstructionDataOutput = CodecOutput<
typeof PASS_INSTRUCTION_DATA
>; |
2206d24
to
08b075b
Compare
@lithdew Almost identical traces on my side. I don't know if the results are biased by my machine's specs though. I also tried running this snippet on a code-sandbox and the TypeScript autocompletion was almost instant. Are you able to compare the two branches on your side and tell me if you see a difference? |
Would you have the code sandbox available? I can try paste in parts of my project into it. Having a hard time linking to @solana/web3.js@master. |
Sure it's here but the codesandbox only checks the current version. You'd need to check the branch locally to test the changes of this PR. |
Before:
After:
There is a noticeable improvement of 642518 -> 400640 instantiations processed. Wonder if there are other places this trick could be used too. |
Oh nice thanks! Would you mind sharing your process so I can check on my side and learn from you? |
Sure - I cloned the @solana/web3.js repository,
import {
type Codec,
getArrayCodec,
getBase58Codec,
getBooleanCodec,
getDataEnumCodec,
getNullableCodec,
getScalarEnumCodec,
getStringCodec,
getStructCodec,
getU8Codec,
getU16Codec,
getU64Codec,
getUnitCodec,
} from '@solana/codecs';
export enum Currency {
sol = 'sol',
like = 'like',
usdc = 'usdc',
}
export const CURRENCY_CODEC = getScalarEnumCodec(Currency);
export const PUBLIC_KEY = getStringCodec({
encoding: getBase58Codec(),
size: 32,
});
export const CREATOR = getStructCodec([
['address', PUBLIC_KEY],
['verified', getBooleanCodec()],
['share', getU8Codec()],
]);
export const SPLIT = getStructCodec([
['address', PUBLIC_KEY],
['share', getU8Codec()],
]);
export const PASS_INSTRUCTION_DATA = getDataEnumCodec([
[
'create_pass',
getStructCodec([
['name', getStringCodec()],
['symbol', getStringCodec()],
['uri', getStringCodec()],
['price', getU64Codec()],
['token', CURRENCY_CODEC],
['supply', getU64Codec()],
['sellerFeeBasisPoints', getU16Codec()],
['creators', getNullableCodec(getArrayCodec(CREATOR))],
['firstSaleSplit', getArrayCodec(SPLIT)],
]),
],
[
'update_pass',
getStructCodec([
['name', getNullableCodec(getStringCodec())],
['symbol', getNullableCodec(getStringCodec())],
['uri', getNullableCodec(getStringCodec())],
['price', getNullableCodec(getU64Codec())],
['token', getNullableCodec(CURRENCY_CODEC)],
['supply', getNullableCodec(getU64Codec())],
['sellerFeeBasisPoints', getNullableCodec(getU16Codec())],
['creators', getNullableCodec(getNullableCodec(getArrayCodec(CREATOR)))],
['firstSaleSplit', getNullableCodec(getArrayCodec(SPLIT))],
]),
],
['mint_pass', getUnitCodec()],
]);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type CodecInput<T> = T extends Codec<infer TFrom, any> ? TFrom : never;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type CodecOutput<T> = T extends Codec<any, infer TTo> ? TTo : never;
export type PassInstructionDataInput = CodecInput<typeof PASS_INSTRUCTION_DATA>;
export type PassInstructionDataOutput = CodecOutput<typeof PASS_INSTRUCTION_DATA>;
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@solana/codecs": "workspace:2.0.0-preview.1"
}
}
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "@solana/codecs",
"extends": "@solana/tsconfig/base.json",
"include": [
"src"
]
} I then ran I switched branches to this PR, deleted all |
Thank you for the detailed guide! I was able to reproduce the changes. Whilst on my machine I barely see a performance improvement measured in seconds, I can now see that the number of instantiations is almost reduced in half which is pretty amazing.
Yes I'm pretty confident it can. In fact, once I refactor the |
08b075b
to
b8caa96
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a bunch of comments to DrainOuterGeneric
?
- The original change that led us here. “Type instantiation is excessively deep and possibly infinite” but only in a large codebase microsoft/TypeScript#34933
- TypeScript is apparently tracking it? feat: increase fault tolerance to deep types error kysely-org/kysely#483
b8caa96
to
e6d76e0
Compare
e6d76e0
to
d309da8
Compare
Merge activity
|
🎉 This PR is included in version 1.91.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Because there has been no activity on this PR for 14 days since it was merged, it has been automatically locked. Please open a new issue if it requires a follow up. |
This PR aims to solve #2295 by wrapping codec type mappings with the suggested
DrainOuterGeneric
.The TypeScript diagnostics on a complex codec — using both data enums and structs — changes as follows. As you can see we get a significant reduction of instantiations.