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

Add signature verification + additional validation in xcm-core-buyer #559

Merged
merged 8 commits into from
May 30, 2024

Conversation

ParthDesai
Copy link
Contributor

@ParthDesai ParthDesai commented May 24, 2024

Description

This PR adds signature verification in the xcm-core-buyer. So that only collator can purchase the core. Apart from that the pallet now only allows collator to buy core if it is inline with the slot frequency.

Changes are as follows:

  1. xcm-core-buyer now takes into account slot frequency.
  2. couple of hooks added in xcm-core-buyer to get current slot and latest author info from other pallets.
  3. xcm-core-buyer now do signature verification in validate_unsigned for buy_core
  4. two runtime api exposed: 1. Get slot frequency 2. Check whether a client is allowed to buy core or not which can be used by client to decide whether it should buy core or not.

Remaining:

  • Benchmarks
  • Tests

{
let block_number = <frame_system::Pallet<T>>::block_number();

let current_nonce = CollatorSignatureNonce::<T>::get();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need a nonce? Can't we use the block number as the nonce for example?

Copy link
Contributor Author

@ParthDesai ParthDesai May 24, 2024

Choose a reason for hiding this comment

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

Hmm. Yeah. We can use block number as nonce. But problem is that it is not guaranteed at which block this tx will be included and any tx signed with earlier block number can become invalid.

So, the idea is to have nonce just like a substrate account.

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 like that it's an extra storage map. But block number won't work, because the tx may not be included in the next block, you're right. Container chain block number (from author-noting pallet) also won't work, because in case of failure we won't be able to retry... There must be something that we can use though.

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 is not extra storage map. It's just one storage value at the moment.

I think it is nice trade off between amount of space and the uncertainity.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, really? Sorry, I haven't look into the code yet, but what will happen if two collators try to buy a core in the same block? Will it work or will it fail?

Copy link
Contributor Author

@ParthDesai ParthDesai May 24, 2024

Choose a reason for hiding this comment

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

One of them would succeed and other one would fail. That is sort of drawback. This is the reason why I wanted it originally as storage map.

On second thought, let me modify it as storage map first and then we can arrive at equivalent solution later on.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah I agree, let's work with a storage map now, write some tests to make sure everything works, and then we can think about how to remove this storage map.

@ParthDesai ParthDesai force-pushed the add-parathread-support-part-2 branch from f1734ea to 17e822d Compare May 24, 2024 11:07
Copy link
Contributor

github-actions bot commented May 24, 2024

Coverage Report

(master)

@@                        Coverage Diff                        @@
##           master   add-parathread-support-part-2      +/-   ##
=================================================================
+ Coverage   69.19%                          69.31%   +0.12%     
+ Files         221                             223       +2     
+ Lines       39049                           39193     +144     
=================================================================
+ Hits        27017                           27165     +148     
- Misses      12032                           12028       -4     
Files Changed Coverage
/client/consensus/src/lib.rs 28.68% (-0.23%) 🔽
/pallets/author-noting/src/lib.rs 86.57% (+0.19%) 🔼
/pallets/xcm-core-buyer/src/lib.rs 91.08% (+10.16%) 🔼
/pallets/xcm-core-buyer/src/weights.rs 6.34% (-0.92%) 🔽
/primitives/traits/src/lib.rs 58.14% (+11.71%) 🔼
/runtime/dancebox/src/lib.rs 89.30% (-0.09%) 🔽
/runtime/dancebox/src/weights/pallet_xcm_core_buyer.rs 49.30% (+7.36%) 🔼
/runtime/dancebox/src/xcm_config.rs 83.67% (+2.90%) 🔼

Coverage generated Thu May 30 11:45:02 UTC 2024

@ParthDesai ParthDesai added B7-runtimenoteworthy Changes should be noted in any runtime-upgrade release notes breaking Needs to be mentioned in breaking changes D5-nicetohaveaudit⚠️ PR contains trivial changes to logic that should be properly reviewed. labels May 27, 2024
@ParthDesai ParthDesai force-pushed the add-parathread-support-part-2 branch 5 times, most recently from 3392279 to 0c0cbf2 Compare May 27, 2024 10:09
Comment on lines 322 to 325
#[cfg(test)]
pub fn set_signature(&mut self, signature: PublicKey::Signature) {
self.signature = signature;
}
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 make the fields public instead of having setters

Copy link
Contributor Author

@ParthDesai ParthDesai May 27, 2024

Choose a reason for hiding this comment

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

I only want to make the fields publicly accessible for testing. Can I do that?

Reason being is that if you mutate this struct, it will become invalid as either public key or signature changes.

Copy link
Contributor

Choose a reason for hiding this comment

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

For types that can be deserialized from bytes, such as this one that implements Decode, you must assume they can be in an invalid state anyway, so I don't see much benefit from having private fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh. I did not meant it for validation. Verify function will return false in that case anyway.

My idea was to indicate anybody who is using this structure in non-test environment to be able to just call new and get valid instance which they cannot modify as any change there can render the struct invalid and call to fail. So, basically reduce the error surface for anybody working with the struct.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tmpolaczyk Now, the fields are public. :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Cool, thank you

let current_slot = T::SlotBeacon::slot();
if !parathread_params.slot_frequency.should_parathread_buy_core(
Slot::from(current_slot as u64),
Slot::from(2u64),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
Slot::from(2u64),
Slot::from(2u64),

this should be a config parameter probably no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes. I have added to-do for that.

@girazoki
Copy link
Collaborator

girazoki commented May 27, 2024

I general I like the approach taken but I am missing a bunch of integration tests (with the xcm-emulator, if possible). Any other tests we can run @tmpolaczyk? I feel like any dev-test wont work so at most we can do the zombienet one you have already.

To adapt the zombienet test we are going to need to:

  • register the parathread as a parathread in the relay (not as a parachain, as we are doing now)
  • fund the account in the relay with tokens
  • check the block is more or less being produced at a consistent rate.

Also I have not seen the client-change related to the change of the runtime-api (I think instead of slot_frequency it's called some other thing now), so we should probably modify that too

@tmpolaczyk
Copy link
Contributor

I general I like the approach taken but I am missing a bunch of integration tests (with the xcm-emulator, if possible). Any other tests we can run @tmpolaczyk? I feel like any dev-test wont work so at most we can do the zombienet one you have already.

We don't have any zombienet tests? I see the one in test/suites/dev-tanssi/xcm-core-buyer/test_xcm_core_buyer.ts, which is a dev test, and we can only use it to test that the xcm message has been sent, (because dev test = no relay chain), unless we mock the response somehow.

@girazoki girazoki added D9-needsaudit👮 PR contains changes to fund-managing logic that should be properly reviewed and externally audited and removed D5-nicetohaveaudit⚠️ PR contains trivial changes to logic that should be properly reviewed. labels May 27, 2024
@ParthDesai ParthDesai force-pushed the add-parathread-support-part-2 branch 3 times, most recently from a77eb4d to a932640 Compare May 29, 2024 12:04
@ParthDesai ParthDesai force-pushed the add-parathread-support-part-2 branch from a932640 to 6319a74 Compare May 29, 2024 15:12
@ParthDesai ParthDesai marked this pull request as ready for review May 29, 2024 17:02
Copy link
Collaborator

@girazoki girazoki 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 it looks great now, great job! I have a few questions though:

  • We have in our xcm-emulator tests tests that use force_buy_core. How difficult would it be to implement one that uses buy_core? I am not sure which collators do we set there but if they are collators that are backed by a private key (e.g., Alice) we could do this right?

  • The zombienet parathread test version can be changed once the node changes are implemented

@ParthDesai
Copy link
Contributor Author

ParthDesai commented May 30, 2024

I think it looks great now, great job! I have a few questions though:

  • We have in our xcm-emulator tests tests that use force_buy_core. How difficult would it be to implement one that uses buy_core? I am not sure which collators do we set there but if they are collators that are backed by a private key (e.g., Alice) we could do this right?

It is not much of effort to replace force_buy_core with buy_core. But there is no point as buy_core is equivalent to force_buy_core with extra validation for sender but has no effect on xcm execution.

  • The zombienet parathread test version can be changed once the node changes are implemented

Sure.

primitives/traits/src/lib.rs Outdated Show resolved Hide resolved
proof,
} = call
{
let block_number = <frame_system::Pallet<T>>::block_number();
Copy link
Contributor

Choose a reason for hiding this comment

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

I added the block number to be able to do

.and_provides((block_number, para_id))

because without that, only a single unsigned transaction would ever be included by the block builder. Now that we have the nonce we probably don't need it. But I don't know a good alternative, (para_id, nonce) won't work because the nonce can be the same for different collators... So probably it's better to just leave it like it is. And unfortunately this is going to be very hard to test...

@ParthDesai ParthDesai merged commit 302abde into master May 30, 2024
32 checks passed
@ParthDesai ParthDesai deleted the add-parathread-support-part-2 branch May 30, 2024 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B7-runtimenoteworthy Changes should be noted in any runtime-upgrade release notes breaking Needs to be mentioned in breaking changes D9-needsaudit👮 PR contains changes to fund-managing logic that should be properly reviewed and externally audited
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants