Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

sdk: Add try_from_slice_unchecked for Borsh #16098

Merged
merged 4 commits into from
Mar 26, 2021

Conversation

joncinque
Copy link
Contributor

Problem

If we're using variable-sized structures on-chain, for example Vec<>, and we allocate 1000 bytes and don't immediately use all of them, Borsh fails deserialization because it doesn't read the entire slice.

Summary of Changes

Add a helper function. This is a copy of https://github.com/near/borsh-rs/blob/3223286bae05d29162eaf37512966b9fa7d9cfdb/borsh/src/de/mod.rs#L30 which just removes the is_empty() check.

Fixes #

@joncinque joncinque requested a review from mvines March 24, 2021 19:56
@joncinque joncinque added the v1.6 label Mar 24, 2021
@@ -54,3 +60,10 @@ pub fn get_packed_len<S: BorshSchema>() -> usize {
let schema_container = S::schema_container();
get_declaration_packed_len(&schema_container.declaration, &schema_container.definitions)
}

/// Deserializes without checking that the entire slice has been consumed
pub fn try_from_slice_unchecked<T: BorshDeserialize>(data: &[u8]) -> Result<T, Error> {
Copy link
Contributor

Choose a reason for hiding this comment

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

How about a little test for this guy?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Certainly

Copy link
Contributor

Choose a reason for hiding this comment

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

Unchecked sounds potentially dangerous, should folks be cautious using this function and if so what should they pay attention to?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm, that's a good point. The main difference is that this function eliminates a check that the slice has been totally read, so it lets you work with overallocated buffers. The normal try_from_slice returns an error if there's data left in the buffer after deserialization. How could we clarify that?

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a downside to always using the "unchecked" version?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The length check ensures that whatever you're expecting to deserialize uses up all of the bytes in the buffer, so you could potentially run into an issue if you always use unchecked. Any buffer that's big enough could work to deserialize your type, so if you pass the wrong buffer with unchecked, the error wouldn't get caught.

Copy link
Contributor

Choose a reason for hiding this comment

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

Any buffer greater than or equal to the expected size would work, correct? Maybe call it "unsized", "unchecked" is fine but should probably include something to effect of the description you have above as what the "unchecked" means practically to the developer

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correct -- I'll rename the function and add the description then

Copy link
Contributor

Choose a reason for hiding this comment

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

With the good description you have provided I think "unchecked" makes sense, I can go either way but "unchecked" is more consistent with rust norms

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's also consistent with the PR that I put in for Borsh JS :-D

mvines
mvines previously approved these changes Mar 25, 2021
Copy link
Contributor

@mvines mvines left a comment

Choose a reason for hiding this comment

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

lgtm!

@mergify mergify bot dismissed mvines’s stale review March 25, 2021 19:23

Pull request has been modified.

@codecov
Copy link

codecov bot commented Mar 26, 2021

Codecov Report

Merging #16098 (df55cba) into master (658ddd1) will increase coverage by 0.0%.
The diff coverage is 89.1%.

@@           Coverage Diff           @@
##           master   #16098   +/-   ##
=======================================
  Coverage    80.0%    80.1%           
=======================================
  Files         410      410           
  Lines      109161   109212   +51     
=======================================
+ Hits        87422    87508   +86     
+ Misses      21739    21704   -35     

@joncinque joncinque merged commit cffa851 into solana-labs:master Mar 26, 2021
@joncinque joncinque deleted the sdk-borsh branch March 26, 2021 22:37
mergify bot pushed a commit that referenced this pull request Mar 26, 2021
* sdk: Add try_from_slice_unchecked for Borsh

* Add tests

* Rename + clarify comment

* Rename back to unchecked

(cherry picked from commit cffa851)
mergify bot added a commit that referenced this pull request Mar 29, 2021
* sdk: Add try_from_slice_unchecked for Borsh

* Add tests

* Rename + clarify comment

* Rename back to unchecked

(cherry picked from commit cffa851)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
@brooksprumo brooksprumo mentioned this pull request Aug 23, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants