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 Async Script Verification RFC #961

Merged
merged 12 commits into from
Oct 14, 2020
Merged

Implement Async Script Verification RFC #961

merged 12 commits into from
Oct 14, 2020

Conversation

yaahc
Copy link
Contributor

@yaahc yaahc commented Aug 28, 2020

blocked on the implementation of RFC5

@yaahc yaahc marked this pull request as draft August 28, 2020 22:57
@yaahc yaahc linked an issue Sep 4, 2020 that may be closed by this pull request
@yaahc yaahc added the S-blocked Status: Blocked on other tasks label Sep 17, 2020
@yaahc yaahc removed the S-blocked Status: Blocked on other tasks label Oct 9, 2020
@yaahc yaahc marked this pull request as ready for review October 9, 2020 02:10
@yaahc yaahc requested a review from hdevalence October 9, 2020 02:10
@yaahc yaahc requested review from a team and hdevalence October 12, 2020 22:40
})
.flat_map(|inputs| inputs.into_iter());

assert!(inputs.any(|input| matches!(input, transparent::Input::PrevOut { .. })));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried writing a test but it ended up being perfectly, beautifully useless. This assert fails. Not really sure how to test this one...

Copy link
Contributor

Choose a reason for hiding this comment

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

The first block with a non-coinbase transaction is at least block 101, because of the coinbase maturity rule.

Should we focus on getting the sync acceptance tests working? (#1141)

If we only want to test finalized state, then we could add a sync test for the second checkpoint, which has 2000 blocks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that might be necessary, but even then I'm not sure we can test this code meaningfully via the acceptance test, given the restriction only being able to chain verify post sapling blocks.

.boxed()
}
transparent::Input::Coinbase { .. } => unimplemented!(
"how should we handle verifying coinbase transactions in the script::Verifier?"
Copy link
Contributor

Choose a reason for hiding this comment

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

The block height MUST be encoded as the first item in the coinbase transaction’s scriptSig, as specified in [BIP-34]. The format of the height is “serialized CScript” – the first byte is the number of bytes in the number, and the following bytes are the signed little-endian representation of the number.

https://zips.z.cash/protocol/canopy.pdf#blockheader

Copy link
Contributor

@teor2345 teor2345 Oct 13, 2020

Choose a reason for hiding this comment

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

I think the async script verifier should check the script part of this rule, and then the subsidy module should check the address:

Consensus rule: [Pre-Canopy] A coinbase transaction at height ∈ {1..FoundersRewardLastBlockHeight} MUST include at least one output that pays exactly FoundersReward(height) zatoshi with a standard P2SH script of the form OP_HASH160 FounderRedeemScriptHash(height) OP_EQUAL as its scriptPubKey.

https://zips.z.cash/protocol/canopy.pdf#foundersreward

Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly with transparent founders rewards:

Consensus rule: [Canopy onward] The coinbase transaction at block height height MUST contain at least one output per funding stream fs active at height, that pays fs.Value(height) zatoshi in the prescribed way to the stream’s recipient address represented by fs.AddressListfs.AddressIndex(height).
The “prescribed way” to pay a transparent P2SH address is to use a standard P2SH script of the form OP_HASH160 fs.RedeemScriptHash(height) OP_EQUAL as the scriptPubKey. Here fs.RedeemScriptHash(height) is the standard redeem script hash for the recipient address given by fs.AddressList[fs.AddressIndex(height)] in Base58Check form. The standard redeem script hash is specified in [Bitcoin-Multisig] for P2SH multisig addresses, or [Bitcoin-P2SH] for other P2SH addresses.

Copy link
Contributor

Choose a reason for hiding this comment

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

To be clear, I think we can merge this PR now, and open a ticket for coinbase script validation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sounds good, tysm for looking this up, I'll create the issue rn and vendor this information there.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think that this is the appropriate place to check this rule, because this rule isn't actually a rule scoped to a particular script input, but a rule scoped to a block: each block has exactly one transaction with coinbase inputs, of such and such form, etc.

So, I think that a better strategy that keeps the script verifier scoped to script verification would be to handle the special coinbase transaction specially, and reject coinbase inputs in the script verifier (which would then be scoped to ordinary transactions).

.zcash_serialize_to_vec()
.expect("zcash_serialize_to_vec has wrong return type");

// TODO: check highest entry of hash_by_height as in RFC
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 ticket or checklist item for this TODO?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no idea, the comment predates this PR

Copy link
Contributor

Choose a reason for hiding this comment

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

I wrote that comment when implementing the most basic version of the sled state that would unblock the sync work. It should be on the list of things to implement to complete the sled state, along with the other TODOs in the source code below.

Comment on lines 114 to 115
#[spandoc::spandoc]
async fn happy_path_test() -> Result<(), Report> {
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like this test is actually 3-4 separate tests in the same function.
Would it help to split them up?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

its two tests, tho the second one (the initial assert) was added because I realized the rest of the test was useless and I wanted to write a short gist of why this test was doomed to fail. I don't think splitting it up is useful, I still have to read the other comments, so there might be a suggestion for how to make this actually useful that I've missed but my expectation is that this entire test needs to get tossed in the trash.

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.

This looks like a good set of functionality.

I'd be keen to freeze the features in the PR, and focus on getting the tests working.

Let me know if you'd like to pair on testing.

hdevalence
hdevalence previously approved these changes Oct 14, 2020
Copy link
Contributor

@hdevalence hdevalence left a comment

Choose a reason for hiding this comment

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

This seems great to me, let's merge this and see if we can connect this to the sync machinery to pump block data through it.

@hdevalence hdevalence dismissed teor2345’s stale review October 14, 2020 21:02

The behavior we need to test here is the integration, not the verification, so we need to be able to integrate it before we can test it.

Copy link
Contributor

@hdevalence hdevalence left a comment

Choose a reason for hiding this comment

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

Same review as before

@yaahc yaahc merged commit e051033 into main Oct 14, 2020
@yaahc yaahc deleted the async-script branch October 14, 2020 21:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement async script verification RFC
3 participants