Skip to content

Refactoring script generating functions into a single place#387

Merged
apoelstra merged 3 commits intorust-bitcoin:masterfrom
pandoracore:builder-p2wildcard
Sep 11, 2020
Merged

Refactoring script generating functions into a single place#387
apoelstra merged 3 commits intorust-bitcoin:masterfrom
pandoracore:builder-p2wildcard

Conversation

@dr-orlovsky
Copy link
Copy Markdown
Collaborator

@dr-orlovsky dr-orlovsky commented Jan 10, 2020

I know that we do plan to utilize miniscript as much as possible, but as an intermediate step I propose to sort out some code duplication issues. Right now, we had script generation logic in address::Payload, which was a duplication of the same code in Script class. With this PR I have:

  • moved all logic to Builder, which seemed to be a more appropriate location
  • added P2PK generation logic
  • added test cases
    * sorted out unnecessary usage of HashEngine where hash function of the new hash types can be used instead

@dr-orlovsky dr-orlovsky changed the title p2* generators moved to Builder Builder functions to generate standard p2* scriptPubkey's Jan 10, 2020
@dr-orlovsky dr-orlovsky force-pushed the builder-p2wildcard branch 2 times, most recently from 95f3325 to 92aedb0 Compare January 12, 2020 12:59
@codecov-io
Copy link
Copy Markdown

Codecov Report

Merging #387 into master will decrease coverage by 0.57%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #387      +/-   ##
==========================================
- Coverage   85.55%   84.97%   -0.58%     
==========================================
  Files          40       40              
  Lines        8660     7315    -1345     
==========================================
- Hits         7409     6216    -1193     
+ Misses       1251     1099     -152
Impacted Files Coverage Δ
src/util/address.rs 85.98% <100%> (-0.24%) ⬇️
src/blockdata/script.rs 80.29% <100%> (+0.52%) ⬆️
src/network/message_blockdata.rs 89.23% <0%> (-3.7%) ⬇️
src/blockdata/block.rs 78.83% <0%> (-1.59%) ⬇️
src/util/contracthash.rs 78.5% <0%> (-1.29%) ⬇️
src/blockdata/transaction.rs 93.92% <0%> (-0.94%) ⬇️
src/util/hash.rs 93.75% <0%> (-0.85%) ⬇️
src/util/bip32.rs 87.14% <0%> (-0.83%) ⬇️
src/consensus/encode.rs 85.15% <0%> (-0.44%) ⬇️
... and 7 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7587c4b...92aedb0. Read the comment docs.

Copy link
Copy Markdown
Collaborator

@stevenroose stevenroose left a comment

Choose a reason for hiding this comment

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

2 major concerns:

  • Try to avoid allocations for generating hashes. The HashTrait::hash method is useful if the slice to be hashed already exists. Like for a Script. If the data to be hashed still needs to be created (i.e. serialized), then you can avoid allocating data by writing directly into the hash engine. Efficiency is more important than readability in for these cases.

  • Exactly what code was duplicated? I see that here you move the p2* creation from address.rs to script.rs, but where did this code exist a second time?

I'm a bit double as to where this code belongs. The notion of p2* scripts has to exist in address.rs, but doesn't necessarily have to exist in script.rs. So that suggests it should stay in address.rs. The only exception is p2pk for which there isn't an address.

Argh, perhaps I can agree with templating code being in Builder; it kinda makes sense. First of all please remove all unnecessary allocations.

@dr-orlovsky dr-orlovsky force-pushed the builder-p2wildcard branch 2 times, most recently from 5e205ac to 3266c6f Compare January 23, 2020 03:54
@dr-orlovsky
Copy link
Copy Markdown
Collaborator Author

@stevenroose I have reverted to hash engine procedure everywhere; so pls reconsider this version for the merge

Copy link
Copy Markdown
Collaborator

@stevenroose stevenroose left a comment

Choose a reason for hiding this comment

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

Now you changed some of the simpler hash functions into an engine without there being a reason for that..

Also, perhaps since the Builder::gen_* methods already construct a new builder so they can't be used on an existing builder, they should just also return a Script directly. That way they are just some kind of factory pattern. I think it's extremely uncommon to gen a template script and then add stuff to it. And it would make our code a lot more readable without all the into_scripts.

@dr-orlovsky
Copy link
Copy Markdown
Collaborator Author

dr-orlovsky commented Jul 21, 2020

Sorry for doing this such late; @stevenroose everything is fixed according to your comments + rebased onto master

@dr-orlovsky dr-orlovsky force-pushed the builder-p2wildcard branch 2 times, most recently from df952d4 to 305a252 Compare July 21, 2020 18:51
@stevenroose
Copy link
Copy Markdown
Collaborator

You seem to have a Rust v1.22 compilation error. I'm thinking if it actually makes sense to have the gen_xxx methods return a Builder instead of a Script directly. In the latter case, it would be a factory pattern, which might be fine for this kind of stuff. I can't see a situation where it'd be useful to have the raw builder and do something with it.

@sgeisler
Copy link
Copy Markdown
Contributor

sgeisler commented Aug 9, 2020

I'm not sure if these methods belong into the Builder at all. They produce complete scripts, there is no use case for appending opcodes after generating them and I'm not sure what would be the result of doing so (just a longer script or unwanted side effects). Imo these functions would be wonderful Script constructors, not Builder constructors.

@dr-orlovsky dr-orlovsky force-pushed the builder-p2wildcard branch 3 times, most recently from 07c4976 to 4221aa6 Compare September 3, 2020 21:55
@dr-orlovsky
Copy link
Copy Markdown
Collaborator Author

dr-orlovsky commented Sep 3, 2020

@sgeisler, @stevenroose I have moved all methods to Script and prefixed them with with_* (instead of gen_) according to Rust https://doc.rust-lang.org/1.0.0/style/style/naming/README.html#general-conventions-[rfc-#430].

It seems to me that @apoelstra comment from other PR #388 (comment) was actually addressing this PR (and not that one). I tend to agree that this generators are natural part of miniscript; however this code was anyway inside rust-bitcoin, so I have not written it but just refactored from scattered places across the library into a single set of functions. This may be a first step for moving this functions out/into miniscript.

This PR also increases test coverage of the original rust bitcoin code

@dr-orlovsky dr-orlovsky changed the title Builder functions to generate standard p2* scriptPubkey's Refactoring script generating functions into a single place Sep 3, 2020
}

/// Generates OP_RETURN-type of scriptPubkey for a given data
pub fn with_op_return(data: &Vec<u8>) -> Self {
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.

Please take a &[u8] rather than an &Vec<u8>.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

fixed with the new commit, as well as the rest of your points

pub fn with_op_return(data: &Vec<u8>) -> Self {
Builder::new()
.push_opcode(opcodes::all::OP_RETURN)
.push_slice(&data)
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.

This & is unnecessary

pub fn new() -> Script { Script(vec![].into_boxed_slice()) }

/// Generates P2PK-type of scriptPubkey
pub fn with_pk(pubkey: &PublicKey) -> Script {
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.

This should be named p2pk or something similar to indicate that you are making a pay-to-pubkey scriptpubkey. The with_ naming is confusing here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Right. I've taken with_ prefix after Rust naming guidelines https://rust-lang.github.io/api-guidelines/naming.html suggesting to name constructors as new or with_ prefix. But I agree that this is confusing and guidelines are not a law.

Renamed all methods to corresponding descriptor names with new_ prefix to signify that we are not converting existing script object into a scriptPubkey but constructing a new one from arguments.

}

/// Generates P2PKH-type of scriptPubkey
pub fn with_pkh(pubkey_hash: &PubkeyHash) -> Script {
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.

Ditto here, the name should indicate that this is a pay-to-pubkeyhash scriptpubkey

}

/// Generates P2WSH-type of scriptPubkey with a given hash of the redeem script
pub fn with_witness_program(ver: ::bech32::u5, program: &Vec<u8>) -> Script {
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.

Don't take a &Vec<u8>

@apoelstra
Copy link
Copy Markdown
Member

concept ACK. I like having these methods in Script; the current API makes you go through Address which is super annoying.

Copy link
Copy Markdown
Member

@elichai elichai 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!
utACK

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

Labels

minor API Change This PR should get a minor version bump

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants