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

[fastx types] Add gas coin type #97

Merged
merged 1 commit into from
Dec 31, 2021

Conversation

sblackshear
Copy link
Collaborator

@sblackshear sblackshear commented Dec 29, 2021

This bridges one useful object type from the Move world to the Rust one. Transfer orders now act over objects whose type is "gas coin".

  • Introduce new GAS module in Move + use it to instantiate the generic Coin type. The resulting type for a gas token is Coin::Coin<GAS>,
  • Introduce Rust wrappers for the Move Coin, Coin<GAS>, and ID types
  • Use Coin<GAS> as the type of all test objects constructed by Object::with_id_owner_for_testing. The value of each test coin is 0, but we can change that if desired.
  • Restrict Transfer orders so they only work on gas coins.

@sblackshear sblackshear requested a review from oxade December 29, 2021 00:40
@sblackshear sblackshear force-pushed the gas_token branch 2 times, most recently from 99110fb to 1d30833 Compare December 29, 2021 06:19
id::ID,
};

/// 0x7ABB80D444EB9F84F0CF64CC34CF8760
Copy link
Contributor

Choose a reason for hiding this comment

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

is this a special magic value from move?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is the ObjectID of the Coin module that gets published at genesis.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right now, the ID's for all the genesis modules get derived programmatically in the same way they do for ordinary objects (i.e., id = hash(tx_digest || N) for the Nth id created by the tx. But if we wanted to, we could hardcode special ID's for each genesis module (and there could be UX benefits for doing so).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Realized it is probably helpful for me to share how I knew to type this magic number (and how others in the future can figure it out if they need to add new Rust wrappers of Move types):

  • Write your wrapper type and use a dummy address (e.g., copy over COIN_ADDRESS)
  • Add a new conditional branch for your type along the lines of the code in 54--84 in genesis.rs that checks your dummy address
  • Run the tests, which will exercise your conditional branch and trip the assertion because your dummy address will not match the actual address of the type
  • Take the address printed by the test harness and add it to your type. Now, everything will work

This is a bit annoying, but it works for now. In the future, we can hopefully solve this via codegen of these Rust wrappers of Move types.

@lxfind
Copy link
Contributor

lxfind commented Dec 30, 2021

Why are we restricting transfers to gas object only?

@@ -54,7 +51,37 @@ fn create_genesis_module_objects() -> Result<Genesis> {
let self_id = m.self_id();
// check that modules the runtime needs to know about have the expected names and addresses
// if these assertions fail, it's likely because approrpiate constants need to be updated
if self_id.name() == TX_CONTEXT_MODULE_NAME {
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably cleaner using match instead of if elses? Or if you want to make it even simpler, define a map from name to address, and fold all these if/else into one.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not related to your change, but in line 44 (now 47), should it be assert_eq!(native.1.as_ident_str(), new_id.name()); instead? I don't expect module rewriter to change their names.

Copy link
Collaborator Author

@sblackshear sblackshear Dec 31, 2021

Choose a reason for hiding this comment

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

Probably cleaner using match instead of if elses? Or if you want to make it even simpler, define a map from name to address, and fold all these if/else into one.

I agree, but couldn't figure out how to match against a constant (not sure if Rust lets you do that?), but map idea is great--will make that fix.

Not related to your change, but in line 44 (now 47), should it be assert_eq!(native.1.as_ident_str(), new_id.name()); instead? I don't expect module rewriter to change their names.

Fair point. The rewriter can change the name if you ask it to (by providing a new name in the sub_map), but we don't use it that way here and shouldn't. Might as well make the assertion more precise to reflect that. Will make that change here if it's not too distracting.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not related to your change, but in line 44 (now 47), should it be assert_eq!(native.1.as_ident_str(), new_id.name()); instead? I don't expect module rewriter to change their names.

My bad--I mistakenly thought I understood this, but I don't think I do. Which assertion in the original code is this referring to?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think your previous understanding is correct. I was referring to this line:

native.1 = new_id.name().to_owned();

and suggest it to be assertion instead.

@sblackshear
Copy link
Collaborator Author

Why are we restricting transfers to gas object only?

Good question. User-defined objects can (and will want to) enforce restrictions on transfers, and we don't want to allow the native Transfer op to subvert those restrictions.

However, I don't think we'll want to restrict transfers to gas objects only--those are just the only type of objects we have right now. In the longer term, I think what probably makes sense is allowing native transfer for

  • Coin<T> for any T (and now that you mention it, we could implement that policy now)
  • Any of our standard libary types whose Move logic allows unconditional transfers (e.g., we will likely have mocks of ERC721 and ERC1155 that meet this condition)
  • [speculative] On the Move team, there has been some discussion adding custom attributes[1] to the bytecode language that are not interpreted by the VM or Move verifier, but can be given meaning by custom verifier passes. If this feature gets added, you could imagine supporting a transfer struct attribute for allowing unconditional transfers that allows the native transfer operation for your struct.

[1] See, e.g., diem/diem#10104, which is using the source attributes (which already exist) and mentions exposing them in the bytecode

This bridges one useful object type from the Move world to the Rust one. `Transfer` orders now act over objects whose type is "gas coin".

- Introduce new `GAS` module in Move + use it to instantiate the generic `Coin` type. The resulting type for a gas token is `Coin::Coin<GAS>`,
- Introduce Rust wrappers for the Move `Coin`, `Coin<GAS>`, and `ID` types
- Use `Coin<GAS>` as the type of all test objects constructed by `Object::with_id_owner_for_testing`. The value of each test coin is 0, but we can change that if desired.
- Restrict `Transfer` orders so they only work on gas coins.
@sblackshear sblackshear merged commit 7f37727 into MystenLabs:main Dec 31, 2021
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