-
Notifications
You must be signed in to change notification settings - Fork 120
Add a function to create a decoder that checks the size of the input bytes #944
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
Conversation
🦋 Changeset detectedLatest commit: 7635876 The changes in this PR will be included in the next version bump. This PR includes changesets to release 41 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. |
BundleMonFiles updated (7)
Unchanged files (123)
Total files change +1.03KB +0.29% Final result: ✅ View report in BundleMon website ➡️ |
4bab6b3 to
9529670
Compare
|
Documentation Preview: https://kit-docs-by9igyds3-anza-tech.vercel.app |
steveluscher
left a comment
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.
| * decoder.decode(new Uint8Array([0, 0, 0, 0]), 1); // throws | ||
| * ``` | ||
| */ | ||
| export function createDecoderThatUsesExactByteArray<T>(decoder: Decoder<T>): Decoder<T> { |
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.
ConsumesEntire?
¯\_(°ペ)_/¯
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.
The reason I switched from Entire to Exact was because I started writing tests for things like "this decoder is going to read 4 bytes, and you give it 3 bytes, this gives you a useful error". So I was checking too long and too short, which Exact felt like a better fit for.
But I think this was the wrong approach because eg. our number codecs already error when the input bytes are too short, and I think it probably makes sense to leave that as the responsibility for the codec and just cover the case where the input bytes are too long here - which we don't want codecs to check by default.
I'll change this to just check for a byte array being too long, which I think your other suggestions fit better with too.
| bytesLength: bytes.length, | ||
| offsetAfterDecoding: newOffset, | ||
| offsetBeforeDecoding: offset, |
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.
This makes people do math. Just expectedBytes/actualBytes or just numExcessBytes?
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.
Yep agreed. Again this was because I wanted to cover the case where you provide too few bytes, and figured the offset before/after is the most helpful information there. But I can remove that case and provide a more helpful error that just considers the bytes being too long.
packages/errors/src/messages.ts
Outdated
| [SOLANA_ERROR__CODECS__UNION_VARIANT_OUT_OF_RANGE]: | ||
| 'Union variant out of range. Expected an index between $minRange and $maxRange, got $variant.', | ||
| [SOLANA_ERROR__CODECS__BYTES_LENGTH_DECODER_MISMATCH]: | ||
| 'Byte array of length `$bytesLength` was not decoded to the last byte by the provided decoder. End offset was `$offsetAfterDecoding`.', |
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.
Maybe something with a suggestion of what to do, more like:
This decoder expected a byte array of exactly
$expectedLengthbytes, but$numExcessBytesunexpected excess bytes remained after decoding. Are you sure that you have chosen the correct decoder for this data?
| * ``` | ||
| */ | ||
| export function createDecoderThatUsesExactByteArray<T>(decoder: Decoder<T>): Decoder<T> { | ||
| return transformDecoder(decoder, (value, bytes, offset, newOffset) => { |
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.
Since transformDecoder is just:
return createDecoder({
...decoder,
read: (bytes, offset) => {
// Some mapping.
},
});Could we not avoid the extra argument to transformDecoder and simply use createDecoder for this helper?
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.
That makes sense to me and should make this PR simpler, will refactor. Thanks for the pointer!
9529670 to
7635876
Compare
|
Thanks both for the review! I've made a bunch of changes:
|
lorisleiva
left a comment
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.
Very nice! 👌
steveluscher
left a comment
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.
|
🔎💬 Inkeep AI search and chat service is syncing content for source 'Solana Kit Docs' |
|
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. |



Problem
When an app has access to many codecs, for example when using generated clients, it is easy to write code that accidentally uses the wrong type of
Decoderfor a given byte array. This is difficult to debug as you will often be able to use the wrong decoder without any errors, but will be getting invalid data.Summary of Changes
This PR adds a new helper function
createDecoderThatUsesExactByteArraythat can wrap any decoder. The transformed decoder throws if the new offset after decoding a byte array, is not at the end of the input bytes.This means that if you pass a byte array that is longer or shorter than the wrapped decoder expects, the decode will fail.
As noted in the issue this is not a strong guarantee that you're using the correct decoder, many decoders are the same size or variable size. But it should catch a lot of difficult to debug cases in practice, such as decoding account data using the wrong decoder.
Note that to enable this, the signature of
transformDecoderis modified to additionally provide thenewOffsetto the callback. We use both the original offset and the new offset in the error context.Fixes #755