-
Notifications
You must be signed in to change notification settings - Fork 11.3k
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
Play Hero game in unit test #206
Conversation
Awesome! Will test. it out |
btw this PR is ready for review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now this is gameplay!! Thanks for doing this!
A thought for the future: my first reaction to this PR was "this is awesome". My second was "oh man, we shouldn't expect average devs to write tests that look like this". Ideally, you'd be able to concisely write a test scenario like this in pure Move with unit tests. Unfortunately, Transfer::transfer
makes that tricky--once you pass an object into transfer
, there's no way for the unit tests to get it back and continue running the scenario.
Not immediately sure what the best solution to this is. I wonder if there's a way for us to write a FastX-specific wrapper for the unit testing framework that understands transfer
+ enables us to write scenarios like this. I think it should probably be possible if we have a clear idea of what we want--we should think a bit and then ask Tim.
response.signed_effects.as_ref().unwrap().effects.status, | ||
ExecutionStatus::Success | ||
); | ||
let package_object = &response |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated: I think we need need some utility functions to make these sorts of lookups more ergonomic...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think some work needs to go in to making the OrderResponse more organized. For example, it should at least separate the gas object with the rest of the objects in the response.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Currently in client we have to retrieve the mutated objects and check to make sure the gas is indeed there.
I think it deserved it's own spot.
vec![], | ||
) | ||
.await; | ||
assert_eq!(effects.status, ExecutionStatus::Success); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Triumph!
@@ -99,7 +101,7 @@ module Examples::Hero { | |||
|
|||
/// Slay the `boar` with the `hero`'s sword, get experience. | |||
/// Aborts if the hero has 0 HP or is not strong enough to slay the boar | |||
public fun slay(hero: &mut Hero, boar: Boar) { | |||
public fun slay(hero: &mut Hero, boar: Boar, _ctx: &mut TxContext) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The need for a dummy TxContext
parameters to allow this as an entrypoint makes me a bit sad. We could easily relax the entrypoint signature rules to enforce that the last argument is optionally &mut TxContext
, which would make things a bit more ergonomic. But it will also implicitly make a lot of functions into entrypoints, which may be confusing to the programmer and/or to someone trying to understand the public API of a module by looking at its entrypoints... And there are probably already lots of functions that happen to satisfy the entrypoint signature rules, but aren't intended to be entrypoints. Hmm.
Am curious to hear your thoughts on this. I have a vague idea for a long-term solution:repurpose the public(script)
feature of Move bytecode to allow adapters to decide on the interpretation of script
with their own entrypoint signature constraints instead of harcoding one interpretation in the VM. This will decouple entrypoint. But I am less sure of what to do in the short/medium term.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in the short/medium term we should make the same enforcement that Diem does: only scripts functions are entry functions. So most module functions will not be callable. This will also encourage script writers to bundle things together instead of calling function one-by-one.
// Collect all module names from the current package to be published. | ||
// For each transistive dependent module, if they are not to be published, | ||
// they must have a non-zero address (meaning they are already published on-chain). | ||
// TODO: Shall we also check if they are really on-chain in the future? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this seems useful. We will need an impl StateView
from the caller to run the linker, which will check both that the deps are on-chain and that they match the imports in the package to be published.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few nits, and a peeve on the get_key_pair_from_bytes
.
&& m.self_id().address() == &AccountAddress::ZERO | ||
}) | ||
{ | ||
return Err(FastPayError::ModulePublishFailure { error: format!("Denpendent modules must have already been published on-chain with non-0 addresses. Violated by module {:?}", m.self_id()) }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return Err(FastPayError::ModulePublishFailure { error: format!("Denpendent modules must have already been published on-chain with non-0 addresses. Violated by module {:?}", m.self_id()) }); | |
return Err(FastPayError::ModulePublishFailure { error: format!("Dependent modules must have been published on-chain with non-0 addresses, unlike module {:?}", m.self_id()) }); |
@@ -189,6 +190,11 @@ pub fn get_key_pair() -> (FastPayAddress, KeyPair) { | |||
(PublicKeyBytes(keypair.public.to_bytes()), KeyPair(keypair)) | |||
} | |||
|
|||
pub fn get_key_pair_from_bytes(bytes: &[u8]) -> (FastPayAddress, KeyPair) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather make this return a KeyPair
, and equip KeyPair
with a public(&self) -> PublicKeyBytes
, and inline that call to let name = keypair.public()
wherever you need it.
It makes more sense w.r.t what a KeyPair
is, and It's more maintainable if we ever try to revisit the Address
- PublicKeyBytes
relationship.
Add a unit test that plays the hero game. It works!
In order to do so, this PR also fixed a few things: