8000 Added a newtype for script-pushable slice by Kixunil · Pull Request #1190 · rust-bitcoin/rust-bitcoin · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Added a newtype for script-pushable slice #1190

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

Merged
merged 4 commits into from
Feb 20, 2023

Conversation

Kixunil
Copy link
Collaborator
@Kixunil Kixunil commented Aug 12, 2022

The code previously contained undocumented panic when trying to push
slice. This is now solved by making a newtype that guarantees limited
length.

Closes #1186
Closes #1189

This is done on top of unsized script change. I only request light review of the design for now. I'd like to improve it to use a macro for all unsized types.

Copy link
Member
@tcharding tcharding left a comment

Choose a reason for hiding this comment

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

LGTM, since this is the second type of owned/borrow pair we are working on and there is a fair bit going on I'd like to write a thorough integration test. Both for my learning and because I think it would help to make sure we have all the boilerplate correct. Just checking that if I was to do that it is not treading on your toes @Kixunil?

Builder::new()
.push_opcode(opcodes::all::OP_DUP)
.push_opcode(opcodes::all::OP_HASH160)
// The `self` script is 0x00, 0x14, <pubkey_hash>
Copy link
Member

Choose a reason for hiding this comment

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

This is stale now, perhaps move it to the new method v0_p2wpkh. I realize my comment is too low level review for the current draft PR but mentioning it because what I wanted to say was I'm pretty sure I wrote this comment originally and now I can't remember why the first two bytes are 0 and 14 so if you do move the comment perhaps do a better job at explaining them than I did :)

Copy link
Contributor

Choose a reason for hiding this comment

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

0x00 is witness v0
0x14 is OP_PUSHDATA (20 bytes) which is pushing the <pubkey_hash>

The original did &self[2..] to skip the 0x00 and 0x14 of the p2wpkh and only push_slice the <pubkey_hash> part. (since it's the same hash as P2PKH).

P2WPKH requires the script code preimage to be a P2PKH script for some reason (which is what this function is creating)

@Kixunil
Copy link
Collaborator Author
Kixunil commented Aug 15, 2022

No problem! I don't enjoy writing tests too much. ;) Also I don't expect the API to change significantly except for adding stuff that's in std.

@Kixunil Kixunil added the Blocked Some other work is required to make this possible label Dec 6, 2022
@Kixunil
Copy link
Collaborator Author
Kixunil commented Dec 6, 2022

Blocked by #1155 #1438 #1189

@Kixunil Kixunil added this to the 0.30.0 milestone Dec 6, 2022
@Kixunil Kixunil force-pushed the push_bytes branch 2 times, most recently from 046dc0b to 3ba0d2b Compare February 10, 2023 22:03
@Kixunil Kixunil marked this pull request as ready for review February 10, 2023 22:03
@Kixunil
Copy link
Collaborator Author
Kixunil commented Feb 10, 2023

In principle, this is ready (uses the hex_lit crate). However:

  • This is a big change
  • The code and API would be a bit better after MSRV bump because of some traits being implemented for all arrays.

So feel free to skip if you think it's not suitable for 0.30.

@Kixunil Kixunil force-pushed the push_bytes branch 2 times, most recently from 5686a1c to a786315 Compare February 10, 2023 22:29
@apoelstra
Copy link
Member

concept ACK. I think the PR could be split up a bit to make review eaiser:

  • the introduction of hex_lit could be its own commit
  • the replacement of .as_bytes() with b"byte strings" could be its own commit (or part of the above)
  • the use of the One/Two/Four enum could be in its own commit
  • the SerializedSignature stuff could be its own commit (only the impl AsRef<PushBytes> for SerializedSignature needs the PushBytes stuff so this could even come before the "main" commit)

No matter what there'll be a huge commit that introduces the PushBytes types, but these all take up a lot of room in the diff, so I think we could get a big reduction.

I'm ambivalent about slipping to 0.31 or not.

@Kixunil
Copy link
Collaborator Author
Kixunil commented Feb 11, 2023

Yeah, it did occur to me I could split them, I just didn't have the energy to do it at midnight. :) I will look into it.

@tcharding
Copy link
Member

Ahh August 13th - @Kixunil I see why I couldn't remember what was going on with PushBytes now :)

@tcharding
Copy link
Member

All looks pretty sane to me.

@Kixunil
Copy link
Collaborator Author
Kixunil commented Feb 18, 2023

Force push just to (ab)use CI, going to address review.

So far we deserialized hex into `Vec<u8>` at run time. This was mainly
in tests where it had negligible performance cost. However moving the
computation to compile time has a few benefits: it allows proving the
length of the decoded bytes and identifies potential typos before the
code goes through LLVM and other compilation machinery which makes
feedback faster.

This change uses the `hex_lit` crate to move computation to compile
time. It is implemented as `const` declarative macro which doesn't blow
up compilation time.
Script parsing is composed of several functions which implicitly rely on
various properties. Adding a type that restricts the valid values makes
local review easier.
`Signature` only supported serialization into `Vec` which required a
heap allocation as well as prevented statically proving maximum length.

Adding a specialized type that holds a byte array and size solves this.
The solution is very similar to `secp256k1::ecdsa::SerializedSignature`.
The difference is that serialized signature in this crate contains
sighash bytes flag while in `secp256k1` it doesn't.
@Kixunil Kixunil removed the Blocked Some other work is required to make this possible label Feb 18, 2023
@Kixunil
Copy link
Collaborator Author
Kixunil commented Feb 18, 2023

Separated into multiple commits, I'd like to get this in since it looks like we have some time for it.

@apoelstra
Copy link
Member

Happy to review and get this in -- but heads up current version does not compile (it's not a CI network thing)

The code previously contained undocumented panic when trying to push
slice. This change solves it by adding a newtype that guarantees limited
length.
@Kixunil
Copy link
Collaborator Author
Kixunil commented Feb 18, 2023

Heh, looks like an artifact of my history editing. Should be resolved now.

Copy link
Member
@tcharding tcharding left a comment

Choose a reason for hiding this comment

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

ACK bcd95fa

}
}

macro_rules! delegate_index {
Copy link
Member
@apoelstra apoelstra Feb 19, 2023

Choose a reason for hiding this comment

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

In bcd95fa:

I think this macro can be replaced by a suitable generic impl Index<I> for PushBytes where [u8]: Index<I>, Vec: Index<I>::Output = [u8] or something.

Should be done in a followup, I don't want to have to re-review this thing and it's not a big deal anyay :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Then safe code could break our invariant:

strut Evil;

impl Index<Evil> for [u8] {
    type Output = [u8];

    fn index(&self, index: Evil) -> &Self::Output {
        static BIG_ARR: [u8; 4294967297] = [0; 4294967297];
        &BIG_ARR
    }
}

script.push(&PushBytes::empty()[Evil]);

Copy link
Member

Choose a reason for hiding this comment

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

Lol! Ok, that's fair.

Ok(())
}

#[cfg(not(any(target_pointer_width = "16", target_pointer_width = "32")))]
Copy link
Member

Choose a reason for hiding this comment

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

In bcd95fa:

Maybe a comment here saying "we have 64 bits in mind, but even for esoteric sizes, this code is correct, since it's the conservative one that checks for errors".

@apoelstra
Copy link
Member

I'm a little bit wary of how many generics this introduces and what the effect might be on complexity or compile time. But ACK for now and we can revisit later on once we have some better API-analysis tooling in place.

Copy link
Member
@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

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

ACK bcd95fa

@apoelstra apoelstra merged commit ad50fd7 into rust-bitcoin:master Feb 20, 2023
@Kixunil Kixunil deleted the push_bytes branch February 20, 2023 09:49
apoelstra added a commit that referenced this pull request Feb 20, 2023
d83739a Clarify the intention of strange condition (Martin Habovstiak)

Pull request description:

  It may not be obvious why the condition in `push_bytes` module checks for negation of 16 and 32 bit architectures rather than 64 bit. This adds a comment about it being conservative.

  Addresses #1190 (comment)

ACKs for top commit:
  apoelstra:
    ACK d83739a
  tcharding:
    ACK d83739a

Tree-SHA512: 8a674b9869c580a007c189b0d9b0a57023b26eff3afab25322d966e0ccaff767d19dd499243d438832972f351e1e7ea4b8e387a5e3c74569816814fea258b20b
@stevenroose
Copy link
Collaborator

@Kixunil Can you maybe find where that undocumented panic was? 4GB is so big, I feel like just documenting the panic would have been sufficient. The same code that would have triggered that panic, would have triggered an std-lib panic anyway on 32-bit architectures, right?

@Kixunil
Copy link
Collaborator Author
Kixunil commented Oct 28, 2023

In push_slice IIRC. This API gets rid of it completely and works out-of-the-box with all sufficiently small arrays, key types, signatures... If something is missing feel free to submit a PR.

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

Successfully merging this pull request may close these issues.

Use hex_literal crate (at least in tests) script::PushBytes type
5 participants
0