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

Extend the BLSCache to add in a rust Pybinding for validate_clvm_and_signature for use in the mempool #637

Open
wants to merge 25 commits into
base: main
Choose a base branch
from

Conversation

matt-o-how
Copy link
Contributor

No description provided.

Copy link

coveralls-official bot commented Jul 31, 2024

Pull Request Test Coverage Report for Build 10267356686

Details

  • 411 of 443 (92.78%) changed or added relevant lines in 4 files are covered.
  • 288 unchanged lines in 11 files lost coverage.
  • Overall coverage decreased (-1.6%) to 81.361%

Changes Missing Coverage Covered Lines Changed/Added Lines %
crates/chia-consensus/src/gen/condition_tools.rs 73 74 98.65%
crates/chia-consensus/src/spendbundle_validation.rs 322 323 99.69%
crates/chia-bls/src/bls_cache.rs 15 23 65.22%
wheel/src/api.rs 1 23 4.35%
Files with Coverage Reduction New Missed Lines %
crates/chia-protocol/src/classgroup.rs 1 0.0%
crates/chia-bls/src/error.rs 4 0.0%
crates/chia-bls/src/parse_hex.rs 6 70.0%
crates/chia-traits/src/streamable.rs 9 92.54%
crates/chia-bls/src/secret_key.rs 11 88.22%
crates/chia-bls/src/signature.rs 19 93.94%
crates/chia-bls/src/public_key.rs 19 89.9%
wheel/src/api.rs 44 60.37%
crates/chia-bls/src/gtelement.rs 46 25.93%
crates/chia-bls/src/bls_cache.rs 46 71.88%
Totals Coverage Status
Change from base Build 10265410447: -1.6%
Covered Lines: 11908
Relevant Lines: 14636

💛 - Coveralls

@matt-o-how matt-o-how requested a review from arvidn August 1, 2024 14:33
@@ -122,9 +129,9 @@ impl BlsCache {
let msgs = msgs
.iter()?
.map(|item| item?.extract())
.collect::<PyResult<Vec<PyBackedBytes>>>()?;
Copy link
Contributor

Choose a reason for hiding this comment

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

what's the rationale for making this change?

Copy link
Contributor Author

@matt-o-how matt-o-how Aug 2, 2024

Choose a reason for hiding this comment

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

I've reverted it back now.

PyBytes::new_bound(py, key),
PyBytes::new_bound(py, &value.to_bytes()),
))?;
ret.append((PyBytes::new_bound(py, key), value.clone().into_py(py)))?;
Copy link
Contributor

Choose a reason for hiding this comment

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

we talked about going back to using plan bytes here, since GTElement doesn't support pickle. (maybe it should in the future, but let's make that a separate PR)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

@@ -64,7 +71,7 @@ impl BlsCache {

// Otherwise, we need to calculate the pairing and add it to the cache.
let mut aug_msg = pk.borrow().to_bytes().to_vec();
aug_msg.extend_from_slice(msg.as_ref());
Copy link
Contributor

Choose a reason for hiding this comment

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

I would expect extend_from_slice() to be more efficient. Is there a good reason to make this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

max_cost: int,
constants: ConsensusConstants,
peak_height: int,
cache: Option[BLSCache],
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 you should pass in the cache here. If we want to make that change, I think it should be considered independently of porting this to rust

Comment on lines 316 to 321
def get_name_puzzle_conditions(
spend_bundle: SpendBundle,
max_cost: int,
constants: ConsensusConstants,
height: int,
) -> SpendBundleConditions: ...
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't look like this function is defined in this PR. Did you mean get_conditions_from_spendbundle()?
It would be good to understand why this wasn't caught by CI as well. Perhaps there's no python test for this function, or we don't run mypy

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed the immediate problem, but I agree the testing for the pyi file is lacking

Copy link
Contributor

Choose a reason for hiding this comment

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

Manually generating this file is I hope only a temporary solution

Pyo3 is working on automatic type stub generation (though I don't know how we'll do our custom integer types)

Copy link
Contributor

Choose a reason for hiding this comment

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

we do run mypy, so I would have expected this to be caught if there was a test attempting to use this function (under either this name or the true name)

max_cost: u64,
constants: &ConsensusConstants,
height: u32,
cache: &Arc<Mutex<BlsCache>>,
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 you should pass in the cache here

for key, value in cached_bls.items():
assert isinstance(key, bytes)
assert isinstance(value, bytes)
assert isinstance(value, GTElement)
Copy link
Contributor

Choose a reason for hiding this comment

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

we agreed to these as bytes, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

use std::sync::Arc;

#[test]
fn test_validate_no_pks() {
Copy link
Contributor

Choose a reason for hiding this comment

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

there seems to be a lot of repetitions across these tests. did you try to factor something out or make it a parameterized test?

wheel/src/api.rs Outdated Show resolved Hide resolved
result
}

pub fn u64_to_bytes(val: u64) -> Bytes {
Copy link
Contributor

Choose a reason for hiding this comment

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

this seems to be an internal function that probably shouldn't be public/exported

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 used in spendbundle_validation.rs's tests and I suspect will be useful in more places as the Rust ports continue

Copy link
Contributor

Choose a reason for hiding this comment

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

it should probably be pub(crate) then

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@matt-o-how matt-o-how force-pushed the validate_clvm_and_sigs branch 2 times, most recently from ef93e62 to ba7da79 Compare August 5, 2024 14:28
Copy link
Contributor

@arvidn arvidn left a comment

Choose a reason for hiding this comment

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

I think you should revert crates/chia-bls/src/bls_cache.rs, crates/chia-bls/benches/cache.rs, crates/chia-bls/src/lib.rs.

You can define PairingInfo in wheel/src/api.rs if you like a name for it.

if !result {
return Err(ErrorCode::BadAggregateSignature);
}
Ok((npcresult, added, start_time.elapsed()))
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Ok((npcresult, added, start_time.elapsed()))
Ok((npcresult, cache.items(), start_time.elapsed()))

This change requires you to add the items() function to the cache (which currently only exists in the python binding). Alternatively (but maybe a bigger change) would be to replace the call to aggregate_verify() with just a loop over computing the pairings, and return those. There's already an aggregate_verify_gt() for the signature validation

Comment on lines 115 to 116
#[case] parent_id: Vec<u8>,
#[case] puzzle_hash: Vec<u8>,
Copy link
Contributor

Choose a reason for hiding this comment

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

every test case uses the same values for parent_id and puzzle_hash. I don't think you need to make these parameters to the test.

I think you could make msg a constant in the tests as well, since you don't need to test different values of it (I think).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

result
}

pub(crate) fn u64_to_bytes(val: u64) -> Bytes {
Copy link
Contributor

Choose a reason for hiding this comment

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

we already have two copies of this exact function (with this name) in the repository. The other copies are only available to tests however. So I still think it would make sense to make this private (not public) and use one of the existing copies for the test.

#645

Comment on lines +134 to +179
match opcode {
AGG_SIG_PARENT => {
expected_result.extend(parent_id.as_slice());
expected_result.extend(TEST_CONSTANTS.agg_sig_parent_additional_data.as_slice());
}
AGG_SIG_PUZZLE => {
expected_result.extend(puzzle_hash.as_slice());
expected_result.extend(TEST_CONSTANTS.agg_sig_puzzle_additional_data.as_slice());
}
AGG_SIG_AMOUNT => {
expected_result.extend(u64_to_bytes(coin_amount).as_slice());
expected_result.extend(TEST_CONSTANTS.agg_sig_amount_additional_data.as_slice());
}
AGG_SIG_PUZZLE_AMOUNT => {
expected_result.extend(puzzle_hash.as_slice());
expected_result.extend(u64_to_bytes(coin_amount).as_slice());
expected_result.extend(
TEST_CONSTANTS
.agg_sig_puzzle_amount_additional_data
.as_slice(),
);
}
AGG_SIG_PARENT_AMOUNT => {
expected_result.extend(parent_id.as_slice());
expected_result.extend(u64_to_bytes(coin_amount).as_slice());
expected_result.extend(
TEST_CONSTANTS
.agg_sig_parent_amount_additional_data
.as_slice(),
);
}
AGG_SIG_PARENT_PUZZLE => {
expected_result.extend(parent_id.as_slice());
expected_result.extend(puzzle_hash.as_slice());
expected_result.extend(
TEST_CONSTANTS
.agg_sig_parent_puzzle_additional_data
.as_slice(),
);
}
AGG_SIG_ME => {
expected_result.extend(coin.coin_id().as_slice());
expected_result.extend(TEST_CONSTANTS.agg_sig_me_additional_data.as_slice());
}
_ => {}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

rather than computing the expected value programatically, I think it would be easier to read this test (and be confident it's correct) if the expected output was a parameter instead. Since these are binary strings, it could be simplified by either altering the test constants to make the additional data ascii, or to change the messages to be hex and then specify the expected output as hex. Given that the amount will be binary either way, that might be the better option

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.

3 participants