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

Integration test: Generic runtime and environment #1583

Merged
merged 20 commits into from
Oct 12, 2023

Conversation

lemunozm
Copy link
Contributor

@lemunozm lemunozm commented Oct 6, 2023

Description

This PR adds a testing framework with the following features:

  • Tests are now parameterized by T: Runtime where T contains all expected types from a runtime as Config, Block, Events, Calls, Apis... (check env.rs file).
  • Tests are generic over an environment. The Env API abstracts between:
    • fudge (pending work for a future PR)
    • a more simple/low-level environment close to the runtime itself
  • No more macros in the test cases (easier to read/debug)

The framework and tests cases are under a generic folder. Check the example to get an introduction of this.

Pending extra changes for this PR:

  • Fix the fees calculation method.
  • Macro to run tests parameterized with the runtimes to test.

@lemunozm lemunozm added I4-tests Test needs fixing or improving. P2-nice-to-have Issue is worth doing. crcl-protocol Circle protocol related. labels Oct 6, 2023
@lemunozm lemunozm self-assigned this Oct 6, 2023
Copy link
Contributor Author

@lemunozm lemunozm left a comment

Choose a reason for hiding this comment

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

Pending things:

Comment on lines 103 to 106
match dispatch_info.pays_fee {
Pays::Yes => WeightToFee::weight_to_fee(&dispatch_info.weight),
Pays::No => 0,
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not exactly the fees the last executed extrinsic has consumed. Not sure why or what I'm missing.

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 have expected your solution to be correct. Have you compared the current result against the fee returned by transaction_payment::Event::<T>:TransactionFeePaid { actual_fee, tip } which should be the event before the last one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They're different, not sure why, but the way of calculating them comes from different paths. The difference is really subtle anyway:

  • From TransactionFeePaid:
    • 2004154679487179
  • From ExtrinsicSuccess:
    • 2003074679487179

Still investigating, thanks for addressing me to the TransactionFeePaid event!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure why the difference. But as far as I am concerned, using the value from TransactionFeePaid works so... I'll give this as solved.

Copy link
Contributor

@wischli wischli Oct 9, 2023

Choose a reason for hiding this comment

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

Maybe TransactionFeePaid includes another signature check which is not included in ExtrinsicSuccess. Just a guess, haven't looked into the code further.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe there's some extra fees for dispatching the transaction? That happens with xcm-related transactions, maybe there's a similar mechanism here involved?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, there must be some extra fees that do not depend on the weight of the call, so when I do WeightToFee::weight_to_fee(&dispatch_info.weight) I'm leaving some fees behind.

runtime/integration-tests/src/generic/cases/example.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@wischli wischli left a comment

Choose a reason for hiding this comment

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

Some comments. Really looking forward to getting hands on with this new approach! Thanks for your great work, as always. Super clean and a pleasure to read.

runtime/integration-tests/src/generic/environment.rs Outdated Show resolved Hide resolved
runtime/integration-tests/src/generic/environment.rs Outdated Show resolved Hide resolved
Comment on lines 103 to 106
match dispatch_info.pays_fee {
Pays::Yes => WeightToFee::weight_to_fee(&dispatch_info.weight),
Pays::No => 0,
}
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 have expected your solution to be correct. Have you compared the current result against the fee returned by transaction_payment::Event::<T>:TransactionFeePaid { actual_fee, tip } which should be the event before the last one?

runtime/integration-tests/src/generic/envs/runtime_env.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@NunoAlexandre NunoAlexandre left a comment

Choose a reason for hiding this comment

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

Overall this looks fantastic 👏 awesome work, Luis.

I am wondering how we plan on handling certain behaviour deviations between runtimes; for example, DOT and KSM have different decimals so when testing XCM transfers involving such a case, we need to take those differences in consideration. Or we might have certain restrictions on centrifuge that we don't have on development which would make it hard to build generic tests over the two.

Either way, this is a beautiful step further ❤️

@@ -0,0 +1 @@
// TODO: implement generic::env::Env for an environment using fudge
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we still want to do this in this 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.

No, this will be a future PR not to block this. That file is just a placeholder.

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 should create an issue for this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

runtime/integration-tests/src/generic/envs/runtime_env.rs Outdated Show resolved Hide resolved
@lemunozm lemunozm force-pushed the integration-test/generic-env-and-runtime branch from 05228ce to e8fedd5 Compare October 9, 2023 07:23
@lemunozm
Copy link
Contributor Author

lemunozm commented Oct 9, 2023

I am wondering how we plan on handling certain behaviour deviations between runtimes; for example, DOT and KSM have different decimals so when testing XCM transfers involving such a case, we need to take those differences in consideration. Or we might have certain restrictions on centrifuge that we don't have on development which would make it hard to build generic tests over the two.

For such things, the Runtime trait has a T::KIND where you can match and distinguish your behavior. i.e:

match T::KIND {
   KindRuntime::Development => //do X,
   KindRuntime::Altair => //do Y,
   KindRuntime::Centrifuge => //do Z
}

But I think most of the time, differentiations as decimals or other properties can be used under some T::property::get() without looking into what it really is.

@lemunozm
Copy link
Contributor Author

lemunozm commented Oct 9, 2023

Thanks for all your comments and feedback!

I think the PR is ready. The Cargo.toml from integration-tests can be simplify a lot (removing some features, runtime-benchmarks block which I think it's not needed, default-features = false parts, etc). But I think it's better to do this once @NunoAlexandre finalizes with the upgrade to avoid creating many conflicts.

@NunoAlexandre
Copy link
Contributor

Thanks for all your comments and feedback!

I think the PR is ready. The Cargo.toml from integration-tests can be simplify a lot (removing some features, runtime-benchmarks block which I think it's not needed, default-features = false parts, etc). But I think it's better to do this once @NunoAlexandre finalizes with the upgrade to avoid creating many conflicts.

I think it's better if you move ahead, it's no problem for me to deal with the conflicts. The world needs this PR merged asap 😄

@lemunozm
Copy link
Contributor Author

lemunozm commented Oct 9, 2023

There would be a lot of line changes. I think we can merge it without touching Cargo.toml, and in another PR after the upgrade, simplify the dependencies. WDYT?

@lemunozm
Copy link
Contributor Author

Ready for a final review/merge

@lemunozm
Copy link
Contributor Author

I consider this PR done, although some minor parts will be modified in a next PR #1588 to be able to support a FudgeEnv

Copy link
Contributor

@wischli wischli left a comment

Choose a reason for hiding this comment

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

Looks great! We should streamline the setup process by adding setter functions for common tasks such as setting the authorities, see comment below. Not a blocker for sure.

Comment on lines +83 to +85
.add(pallet_aura::GenesisConfig::<T> {
authorities: vec![AuraId::from(Keyring::Charlie.public())],
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a blocker: The authority pattern is and will be heavily used. IMO, we should add setter functions for commonly executed calls such as this one, i.e. with_authorities(vec![AuraId::from(Keyring::Charlie.public())].

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah! The idea is to add this kind of thing. By now, in #1588 such genesis are moved to the environment because it's mandatory needed to make aura works.

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 still need a lot of utilities for common stuff as creating assets, etc

@lemunozm lemunozm merged commit b8effb0 into main Oct 12, 2023
10 checks passed
Comment on lines +75 to +84
/// Retrieve the fees used in the last submit call
fn last_fee(&self) -> Balance {
self.find_event(|e| match e {
pallet_transaction_payment::Event::TransactionFeePaid { actual_fee, .. } => {
Some(actual_fee)
}
_ => None,
})
.expect("Expected transaction")
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This seems pretty detailed for the trait itself...

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, it is, and I've removed it in #1588

Now, submit_now() returns the fee it has cost. In order to later check in tests the exact balance required for some actions

Thanks for your post-morten review!

let cumulus_inherent = ParachainInherentData {
validation_data: PersistedValidationData {
parent_head: vec![].into(),
relay_parent_number: i,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: I think this might become problemativ once we rely on the relay chain block number in some code locations. But not the case right now. But we will probably switch to the relay-chain as a our clock sooner than later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

once we rely on the relay chain block number in some code locations.

Makes sense, taken into account!

Comment on lines +171 to +172
downward_messages: Default::default(),
horizontal_messages: Default::default(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

We could inject XCM messages here. That would be great.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@NunoAlexandre do you think we can get rid of the existing xcm-simulator like that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

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 like a standalone env - no relay nor other parachains being involved. So, even if we populate the horizontal_messages, there's no receiving end for it afaict.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could we mock the receiving end somehow?

Copy link
Contributor

Choose a reason for hiding this comment

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

The receiving end would have to be an actual parachain that's onboarded etc. Not sure if that's something that we want to add at this point.

I think that for the purpose of most integration tests, this setup is fine and we can leave it as it is. For other tests, such as XCM ones, we might need to use a fudge companion with multiple paras. So, I wouldn't mingle with this, for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok Cool!

BTW, I think for the FudgeEnv is quite easy to add new parachains, just adding it in the fudge::companion struct. Something to think about in the future, but I think it's feasible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
crcl-protocol Circle protocol related. I4-tests Test needs fixing or improving. P2-nice-to-have Issue is worth doing.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants