Skip to content
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

Implement Trusted Vector Preallocation #1920

Merged
merged 17 commits into from
Apr 5, 2021

Conversation

preston-evans98
Copy link
Contributor

Motivation

Resolve #1880.

Solution

Implement the SafePreallocate trait, setting sane limits on blind preallocation of vectors. Implement proptests (where applicable) and unit tests to verify that the limits set by SafePreallocate are loose enough that all structurally valid messages can be deserialized.

This implementation deviates from the specification in #1880 in order to remove the use of min_specialization. Instead, we tighten the trait bound from impl<T> zcash_deserialize for Vec<T>, to impl<T: SafePreallocate> zcash_deserialize for Vec<T>, and implement SafePreallocate for all necessary types. If we need to deserialize a Vector type which can't be safely PreAllocated in future, we'll just have to write a manual impl for it.

Also note that the bounds in this implementation differ slightly from those in #1880 in order to remove special cases. For example, we don't set the max_allocation() for MetaAddr to 1000 as described in the Bitcoin specification. Instead, we set the limit based on the MAX_PROTOCOL_MESSAGE_SIZE and the serialized length of a MetaAddr. This mitigates the risk of that future changes to the Zcash protocol will render the bounds in SafePreallocate obsolete, potentially causing Zebra to fall out of consensus.

The code in this pull request has:

  • Documentation Comments
  • Unit Tests and Property Tests

Review

This is low priority. @teor2345

Related Issues

#1880, #1917

Follow Up Work

Improve the efficiency of the proptests for SafePreallocate.

@teor2345 teor2345 self-requested a review March 19, 2021 00:47
@teor2345 teor2345 added A-rust Area: Updates to Rust code C-bug Category: This is a bug C-design Category: Software design work C-security Category: Security issues I-invalid-data Zebra relies on invalid or untrusted data, or sends invalid data I-heavy Problems with excessive memory, disk, or CPU usage P-High labels Mar 19, 2021
@teor2345 teor2345 added this to the 2021 Sprint 5 milestone Mar 19, 2021
Copy link
Contributor

@teor2345 teor2345 left a comment

Choose a reason for hiding this comment

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

Thanks for doing all this work, it looks great.

I'd like some tests to make sure that the maximum preallocation is within the maximum block or message size. Otherwise, the code is really good.

I also have a bunch of suggestions and nitpicks around documentation.

While reviewing this PR, I discovered that Zebra preallocates a few other types. So after the fix in #1925 merges, this PR will need a SafePreallocate impl for JoinSplitData, String, and Script.

@teor2345 teor2345 mentioned this pull request Mar 19, 2021
3 tasks
Copy link
Contributor

@teor2345 teor2345 left a comment

Choose a reason for hiding this comment

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

I also discovered String and Script preallocations, which I fixed in #1925.

Note that equihash::Solution and transparent::Input::Coinbase also do manual allocations, but their checks are very strict.

Comments which did not include replacement code will be addressed in a follow-up commit.

Co-authored-by: teor <teor@riseup.net>
@teor2345 teor2345 changed the title Implement Safe Vector Preallocation Implement Trusted Vector Preallocation Mar 22, 2021
@mpguerra mpguerra removed this from the 2021 Sprint 5 milestone Mar 22, 2021
preston-evans98 and others added 5 commits March 22, 2021 19:36
Add tests to show that the largest allowed vec under TrustedPreallocate
is small enough to fit in a Zcash block/message (depending on type).
Add doc comments to all TrustedPreallocate test cases.
Tighten bounds on max_trusted_alloc for some types.

Note - this commit does NOT include TrustedPreallocate
impls for JoinSplitData, String, and Script.
These impls will be added in a follow up commit
Comments which did not include replacement code will be addressed in a follow-up commit.

Co-authored-by: teor <teor@riseup.net>
Add tests to show that the largest allowed vec under TrustedPreallocate
is small enough to fit in a Zcash block/message (depending on type).
Add doc comments to all TrustedPreallocate test cases.
Tighten bounds on max_trusted_alloc for some types.

Note - this commit does NOT include TrustedPreallocate
impls for JoinSplitData, String, and Script.
These impls will be added in a follow up commit
@teor2345 teor2345 added this to the 2021 Sprint 6 milestone Mar 26, 2021
@teor2345
Copy link
Contributor

Looks like you're ready for another review here.

I should get to it next week, but we're prioritising the Orchard network upgrade right now, so it might slip to early the week after.

@teor2345
Copy link
Contributor

teor2345 commented Apr 3, 2021

Looks good so far, see preston-evans98#1 for a fix to the merge conflict with #1946.

We'll probably want to move the tests to their own modules inside each test submodule. But we can do that in a follow-up PR.

I'm just doing some testing now, then I'll do a detailed review early next week.

Resolve merge conflict and implement TrustedPreallocate for Spend<SharedAnchor>
@teor2345
Copy link
Contributor

teor2345 commented Apr 5, 2021

The Google Cloud Build error is a network failure downloading the Rust docker image.

#[test]
/// Confirm that each MetaAddr takes exactly META_ADDR_SIZE bytes when serialized.
/// This verifies that our calculated `TrustedPreallocate::max_allocation()` is indeed an upper bound.
fn meta_addr_size_is_correct() {
Copy link
Contributor

Choose a reason for hiding this comment

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

The MetaAddr tests should be proptests, but I can make that change in a follow-up PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

(In case we add more address types in future, for example, Tor onion addresses.)

#[test]
/// Confirm that each InventoryHash takes exactly INV_HASH_SIZE bytes when serialized.
/// This verifies that our calculated `TrustedPreallocate::max_allocation()` is indeed an upper bound.
fn inv_hash_size_is_correct() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly, the inv tests should be proptests, in case we add more variants in future.

Copy link
Contributor

@teor2345 teor2345 left a comment

Choose a reason for hiding this comment

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

Looks good!

Let's merge this now, then I'll submit 2 small cleanup PRs.

@teor2345 teor2345 merged commit 0daaf58 into ZcashFoundation:main Apr 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-rust Area: Updates to Rust code C-bug Category: This is a bug C-design Category: Software design work C-security Category: Security issues I-heavy Problems with excessive memory, disk, or CPU usage I-invalid-data Zebra relies on invalid or untrusted data, or sends invalid data
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Safe Preallocation for (most) Vec<T>
3 participants