Skip to content

Add version-aware transaction size limits#1499

Open
mcintyre94 wants to merge 1 commit intotx-planner-constraintsfrom
v1-tx-size-limit
Open

Add version-aware transaction size limits#1499
mcintyre94 wants to merge 1 commit intotx-planner-constraintsfrom
v1-tx-size-limit

Conversation

@mcintyre94
Copy link
Copy Markdown
Member

@mcintyre94 mcintyre94 commented Mar 26, 2026

Problem

Currently we hardcode the transaction size limit to 1232 bytes. For v1 transactions this should be 4096 bytes.

Summary of Changes

Replace using constant transaction size limits with a function to get the size limit for a given Transaction or TransactionMessage. For TransactionMessage this just reads the version field.

For Transaction we use the fact that v1 transactions encode the version byte first, and the v1 value 0x81 is not a valid number of signatures for legacy/v0. Unlike the codec, we just need to know if it's v1 or not here to determine the answer, so we don't look at anything else. This will need to be extended for future versions, but assuming they put the version byte first it'll be trivial.

Fixes: #1221

Increases the size limit to 4096 bytes for v1 transactions, while keeping the existing 1232-byte limit for legacy and v0. V1 is the first version to place the version byte first in the message bytes — earlier versions put signatures before the message, making the signature count the first byte. For compiled `Transaction` objects, version detection reads the first byte of `messageBytes` (the version byte in v1); for `TransactionMessage` objects it checks `message.version === 1`. Exports a new `getTransactionMessageSizeLimit` helper and `V1_TRANSACTION_SIZE_LIMIT` constant from `@solana/transactions`.

Closes #1221.
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 26, 2026

🦋 Changeset detected

Latest commit: bc02a3f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 46 packages
Name Type
@solana/instruction-plans Minor
@solana/transactions Minor
@solana/kit Minor
@solana/plugin-interfaces Minor
@solana/program-client-core Minor
@solana/compat Minor
@solana/react Minor
@solana/rpc-api Minor
@solana/rpc-graphql Minor
@solana/rpc-subscriptions-api Minor
@solana/signers Minor
@solana/transaction-confirmation Minor
@solana/wallet-account-signer Minor
@solana/rpc Minor
@solana/sysvars Minor
@solana/rpc-subscriptions Minor
@solana/accounts Minor
@solana/addresses Minor
@solana/assertions Minor
@solana/codecs-core Minor
@solana/codecs-data-structures Minor
@solana/codecs-numbers Minor
@solana/codecs-strings Minor
@solana/codecs Minor
@solana/errors Minor
@solana/fast-stable-stringify Minor
@solana/functional Minor
@solana/instructions Minor
@solana/keys Minor
@solana/nominal-types Minor
@solana/offchain-messages Minor
@solana/options Minor
@solana/plugin-core Minor
@solana/programs Minor
@solana/promises Minor
@solana/rpc-parsed-types Minor
@solana/rpc-spec-types Minor
@solana/rpc-spec Minor
@solana/rpc-subscriptions-channel-websocket Minor
@solana/rpc-subscriptions-spec Minor
@solana/rpc-transformers Minor
@solana/rpc-transport-http Minor
@solana/rpc-types Minor
@solana/subscribable Minor
@solana/transaction-messages Minor
@solana/webcrypto-ed25519-polyfill Minor

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

Copy link
Copy Markdown
Member Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@mcintyre94 mcintyre94 changed the title Add version-aware transaction size limits for v1 transactions Increases the size limit to 4096 bytes for v1 transactions, while keeping the existing 1232-byte limit for legacy and v0. V1 is the first version to place the version byte first in the message Add version-aware transaction size limits Mar 26, 2026
@bundlemon
Copy link
Copy Markdown

bundlemon bot commented Mar 26, 2026

BundleMon

Files updated (16)
Status Path Size Limits
@solana/kit production bundle
kit/dist/index.production.min.js
46.06KB (+389B +0.83%) -
transaction-messages/dist/index.node.mjs
11.32KB (+247B +2.18%) -
transaction-messages/dist/index.browser.mjs
11.32KB (+246B +2.17%) -
transaction-messages/dist/index.native.mjs
11.32KB (+246B +2.17%) -
errors/dist/index.node.mjs
19.34KB (+170B +0.87%) -
errors/dist/index.browser.mjs
19.32KB (+169B +0.86%) -
errors/dist/index.native.mjs
19.32KB (+169B +0.86%) -
wallet-account-signer/dist/index.node.mjs
16.4KB (+145B +0.87%) -
wallet-account-signer/dist/index.browser.mjs
16.37KB (+134B +0.81%) -
wallet-account-signer/dist/index.native.mjs
16.37KB (+133B +0.8%) -
instruction-plans/dist/index.browser.mjs
6.58KB (+116B +1.75%) -
instruction-plans/dist/index.native.mjs
6.58KB (+116B +1.75%) -
instruction-plans/dist/index.node.mjs
6.58KB (+116B +1.75%) -
transactions/dist/index.browser.mjs
4.04KB (+109B +2.7%) -
transactions/dist/index.native.mjs
4.04KB (+109B +2.71%) -
transactions/dist/index.node.mjs
4.04KB (+109B +2.71%) -
Unchanged files (126)
Status Path Size Limits
rpc-graphql/dist/index.browser.mjs
18.82KB -
rpc-graphql/dist/index.native.mjs
18.81KB -
rpc-graphql/dist/index.node.mjs
18.81KB -
codecs-data-structures/dist/index.browser.mjs
5.04KB -
codecs-data-structures/dist/index.native.mjs
5.03KB -
codecs-data-structures/dist/index.node.mjs
5.03KB -
offchain-messages/dist/index.browser.mjs
4.89KB -
offchain-messages/dist/index.native.mjs
4.89KB -
offchain-messages/dist/index.node.mjs
4.89KB -
codecs-core/dist/index.browser.mjs
3.62KB -
codecs-core/dist/index.native.mjs
3.62KB -
codecs-core/dist/index.node.mjs
3.62KB -
webcrypto-ed25519-polyfill/dist/index.node.mj
s
3.61KB -
webcrypto-ed25519-polyfill/dist/index.browser
.mjs
3.59KB -
webcrypto-ed25519-polyfill/dist/index.native.
mjs
3.57KB -
rpc-subscriptions/dist/index.browser.mjs
3.37KB -
rpc-subscriptions/dist/index.node.mjs
3.34KB -
rpc-subscriptions/dist/index.native.mjs
3.31KB -
rpc-transformers/dist/index.browser.mjs
3.16KB -
rpc-transformers/dist/index.native.mjs
3.16KB -
rpc-transformers/dist/index.node.mjs
3.16KB -
signers/dist/index.browser.mjs
3.14KB -
signers/dist/index.native.mjs
3.14KB -
signers/dist/index.node.mjs
3.14KB -
react/dist/index.browser.mjs
3.09KB -
react/dist/index.native.mjs
3.09KB -
react/dist/index.node.mjs
3.09KB -
addresses/dist/index.browser.mjs
2.93KB -
addresses/dist/index.native.mjs
2.92KB -
addresses/dist/index.node.mjs
2.92KB -
kit/dist/index.browser.mjs
2.78KB -
kit/dist/index.native.mjs
2.78KB -
kit/dist/index.node.mjs
2.78KB -
codecs-strings/dist/index.browser.mjs
2.55KB -
codecs-strings/dist/index.node.mjs
2.51KB -
codecs-strings/dist/index.native.mjs
2.47KB -
transaction-confirmation/dist/index.node.mjs
2.41KB -
sysvars/dist/index.browser.mjs
2.37KB -
sysvars/dist/index.native.mjs
2.37KB -
sysvars/dist/index.node.mjs
2.37KB -
transaction-confirmation/dist/index.native.mj
s
2.36KB -
transaction-confirmation/dist/index.browser.m
js
2.35KB -
rpc-subscriptions-spec/dist/index.node.mjs
2.18KB -
rpc-subscriptions-spec/dist/index.native.mjs
2.13KB -
rpc-subscriptions-spec/dist/index.browser.mjs
2.13KB -
keys/dist/index.browser.mjs
2.1KB -
keys/dist/index.native.mjs
2.1KB -
keys/dist/index.node.mjs
2.1KB -
rpc/dist/index.node.mjs
1.95KB -
codecs-numbers/dist/index.browser.mjs
1.95KB -
codecs-numbers/dist/index.native.mjs
1.95KB -
codecs-numbers/dist/index.node.mjs
1.94KB -
rpc-transport-http/dist/index.browser.mjs
1.91KB -
rpc-transport-http/dist/index.native.mjs
1.9KB -
rpc/dist/index.native.mjs
1.81KB -
rpc/dist/index.browser.mjs
1.8KB -
subscribable/dist/index.node.mjs
1.8KB -
subscribable/dist/index.native.mjs
1.75KB -
subscribable/dist/index.browser.mjs
1.74KB -
rpc-transport-http/dist/index.node.mjs
1.72KB -
rpc-types/dist/index.browser.mjs
1.53KB -
rpc-types/dist/index.native.mjs
1.53KB -
rpc-types/dist/index.node.mjs
1.53KB -
rpc-subscriptions-channel-websocket/dist/inde
x.node.mjs
1.33KB -
rpc-subscriptions-channel-websocket/dist/inde
x.native.mjs
1.27KB -
rpc-subscriptions-channel-websocket/dist/inde
x.browser.mjs
1.26KB -
program-client-core/dist/index.browser.mjs
1.21KB -
program-client-core/dist/index.native.mjs
1.21KB -
program-client-core/dist/index.node.mjs
1.21KB -
options/dist/index.browser.mjs
1.18KB -
options/dist/index.native.mjs
1.18KB -
options/dist/index.node.mjs
1.17KB -
accounts/dist/index.browser.mjs
1.17KB -
accounts/dist/index.native.mjs
1.17KB -
accounts/dist/index.node.mjs
1.16KB -
rpc-api/dist/index.browser.mjs
976B -
rpc-api/dist/index.native.mjs
975B -
rpc-api/dist/index.node.mjs
973B -
compat/dist/index.browser.mjs
969B -
compat/dist/index.native.mjs
968B -
compat/dist/index.node.mjs
966B -
rpc-spec-types/dist/index.browser.mjs
962B -
rpc-spec-types/dist/index.native.mjs
961B -
rpc-spec-types/dist/index.node.mjs
959B -
rpc-subscriptions-api/dist/index.native.mjs
870B -
rpc-subscriptions-api/dist/index.node.mjs
869B -
rpc-subscriptions-api/dist/index.browser.mjs
868B -
rpc-spec/dist/index.browser.mjs
852B -
rpc-spec/dist/index.native.mjs
851B -
rpc-spec/dist/index.node.mjs
850B -
promises/dist/index.browser.mjs
799B -
promises/dist/index.native.mjs
798B -
promises/dist/index.node.mjs
797B -
assertions/dist/index.browser.mjs
783B -
instructions/dist/index.browser.mjs
771B -
instructions/dist/index.native.mjs
770B -
instructions/dist/index.node.mjs
768B -
fast-stable-stringify/dist/index.browser.mjs
726B -
fast-stable-stringify/dist/index.native.mjs
725B -
assertions/dist/index.native.mjs
724B -
fast-stable-stringify/dist/index.node.mjs
724B -
assertions/dist/index.node.mjs
723B -
plugin-core/dist/index.browser.mjs
473B -
plugin-core/dist/index.native.mjs
472B -
plugin-core/dist/index.node.mjs
470B -
programs/dist/index.browser.mjs
329B -
programs/dist/index.native.mjs
327B -
programs/dist/index.node.mjs
325B -
event-target-impl/dist/index.node.mjs
230B -
functional/dist/index.browser.mjs
154B -
functional/dist/index.native.mjs
152B -
text-encoding-impl/dist/index.native.mjs
152B -
functional/dist/index.node.mjs
151B -
codecs/dist/index.browser.mjs
137B -
codecs/dist/index.native.mjs
136B -
codecs/dist/index.node.mjs
134B -
event-target-impl/dist/index.browser.mjs
133B -
ws-impl/dist/index.node.mjs
131B -
text-encoding-impl/dist/index.browser.mjs
122B -
text-encoding-impl/dist/index.node.mjs
119B -
ws-impl/dist/index.browser.mjs
113B -
crypto-impl/dist/index.node.mjs
111B -
crypto-impl/dist/index.browser.mjs
109B -
rpc-parsed-types/dist/index.browser.mjs
66B -
rpc-parsed-types/dist/index.native.mjs
65B -
rpc-parsed-types/dist/index.node.mjs
63B -

Total files change +2.66KB +0.55%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

@mcintyre94 mcintyre94 marked this pull request as ready for review March 26, 2026 18:56
@mcintyre94 mcintyre94 requested a review from lorisleiva March 26, 2026 18:56
@github-actions
Copy link
Copy Markdown
Contributor

Documentation Preview: https://kit-docs-ueel5oxoh-anza-tech.vercel.app

Copy link
Copy Markdown
Member

@lorisleiva lorisleiva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I made a couple of comments.

Comment on lines 26 to +31
export const TRANSACTION_SIZE_LIMIT = TRANSACTION_PACKET_SIZE - TRANSACTION_PACKET_HEADER;

/**
* The maximum size of a version 1 transaction in bytes.
*/
export const V1_TRANSACTION_SIZE_LIMIT = 4096;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should deprecate TRANSACTION_SIZE_LIMIT instead and not expose these constants. That way we ensure people go through the more accurate getTransactionMessageSizeLimit helper instead. Wdyt?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. I actually renamed TRANSACTION_SIZE_LIMIT at one point and then realised it was exported so I reverted that. Makes sense to deprecate that rather than exporting the new one.

Comment on lines +106 to +112
if (transaction.messageBytes.length === 0) {
// If there are no message bytes, then the transaction is empty and thus within the size limit.
return;
}

const firstByte = transaction.messageBytes[0];
const sizeLimit = (firstByte & VERSION_FLAG_MASK) === 1 ? V1_TRANSACTION_SIZE_LIMIT : TRANSACTION_SIZE_LIMIT;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a big fan that we're having another location for computing the size limit for a transaction. I get that this is because the transaction message itself is compiled and encoded so we can't just defer to getTransactionMessageSizeLimit but maybe we should introduce a second getTransactionSizeLimit helper to make it clear that these two functions are the source of truth for that logic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants