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

[RFC] Example-driven proposal for Move-based programmability #4

Merged
merged 1 commit into from
Nov 26, 2021

Conversation

sblackshear
Copy link
Collaborator

See included README

@sblackshear sblackshear force-pushed the programmability_rfc branch 3 times, most recently from 870cfb3 to a13ed34 Compare November 19, 2021 05:30
Copy link
Collaborator

@gdanezis gdanezis left a comment

Choose a reason for hiding this comment

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

Wow. Mind blowing stuff.

fastx_programmability/Move.toml Show resolved Hide resolved
fastx_programmability/README.md Outdated Show resolved Hide resolved
fastx_programmability/sources/Coin.move Show resolved Hide resolved
fastx_programmability/sources/Coin.move Outdated Show resolved Hide resolved
fastx_programmability/sources/Coin.move Show resolved Hide resolved
fastx_programmability/sources/Escrow.move Show resolved Hide resolved
// logic for their structs that cannot be subverted by other modules
public native fun transfer<T: key>(obj: T, recipient: Authenticator);

/// Transfer ownership of `obj` to another object `id`. Afterward, `obj`
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice one: also I think the constraint is a little stronger than it may be used only when another object is in the Tx. The 'owner' object smart contact needs to invoke the operation that uses the owned object?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think I understood this. Here's what I was thinking in more detail; let me know which part is too strong.

  • Every transaction has to be signed by one end-user Bob
  • A transaction can include objects directly owned by Bob (e.g., obj1.authenticator = Bob)
  • Under the George proposal, objects can own other objects, and a the transaction can also include objects transitively owned by Bob (e.g., ParentObj.authenticator = GranparentObj, ChildObj.Authenticator=ParentObj, GrandparentObj.authenticator = Bob)
  • If a transaction wants to use ChildObj, it must also include ParentObj and GrandparentObj + be signed by Bob. Otherwise, we can't verify which end-user's signature grants permission to include ChildObj.

Copy link
Contributor

@huitseeker huitseeker left a comment

Choose a reason for hiding this comment

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

Thanks for these examples, they're great!

In several cases, I've noticed portions of examples that angle towards ACLs: we have a list of subjects with special permissions:

  • const ADMIN in Hero.move,
  • const OWNER in TrustedCoin.move

I've indicated other "roles" that may arise, for instance on the EscrowSwap contract.

Sidenote:
Just so we're on the same page re: vocabulary in the context of this discussion:

  • we're dealing with resources (e.g. a boar, a sword, a TreasuryCap),
  • and we're dealing with subjects (e.g. the owner of the passed resources, the admin account, the coin OWNER account),

ACLs are what guarantees safety when you "classify" what can happen depending on the resource at hand (e.g. for the Hero contract, the normal callers have ambient permissions to slay, heal, ..., whereas the admin also has permissions to create_{potion, boar}). And, as you know, capabilities are what happen when you "sort" permissions on the subject at hand (e.g. Bob has a Sword, and a Boar, so he can create a Hero, and maybe slay, but not heal).

Overall, I would like some details on the management of the contract ACL list, if you will.

  • if it is, as demonstrated, limited to constants —requiring a full-fleged contract update to change— do we plan to manage those updates more loosely in FastX? If not, is this manageable? How do we address the proliferation of contracts who want a "fork" of the HeroesOfBC&Magic game?
  • Will we materialize explicit ACLs? What would that look like? Maybe a Permissions type, pointers from smart contracts to a specific handful of coarse Permissions instances, and a global namespace tying Permissions to users ?
  • How do we delegate and revoke permissions?

fastx_programmability/sources/Escrow.move Show resolved Hide resolved
fastx_programmability/examples/Hero.move Outdated Show resolved Hide resolved
fastx_programmability/examples/Hero.move Show resolved Hide resolved
sword: Sword,
}

/// The hero's trusty sword
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 the later. What I haven't seen is the Sword creation though.

) {
let v = read_field(to_read);
write_field(to_write, v + int_input);
transfer(to_consume, Authenticator::new(bytes_input));
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 the idea here I think is to represent object ownership (in the pecuniary sense) by object ownership (in the Rust capability sense).

Even If a &mut foo sufficed at runtime to transfer foo (by, say a —hypothetical— mutation of an owner field in foo), then any smart contract you'd give this &mut foo to could either give your foo a new sword, or transfer it away, at its discretion.

One language trick to reconcile your expectation of drop and your read of "taking a value" is to call it "consuming" a value.

fastx_programmability/examples/TrustedCoin.move Outdated Show resolved Hide resolved
fastx_programmability/sources/Coin.move Show resolved Hide resolved
Comment on lines +32 to +38
public fun create<T: key + store, ExchangeForT: key + store>(
recipient: Authenticator,
third_party: Authenticator,
exchange_for: IDBytes,
escrowed: T,
ctx: &mut TxContext
) {
Copy link
Contributor

@huitseeker huitseeker Nov 19, 2021

Choose a reason for hiding this comment

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

IIUC, nothing prevents e.g. me from escrowing the object to myself, and then scamming others into participating in an exchange with me.

Without a return_to_sender call automatically issued by a timekeeper I do not control (as discussed later), this allows me to block another person's object (as well as my own), trolling them, or alternatively, holding this as a perpetual American option.

In other terms, we need to make sure the 3d party is not only not the sender (symmetrically receiver), but also not otherwise controlled by the sender (resp. receiver).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah, interesting point. I don't think there's much we can do about this--at the very least, we can assert that sender and recipient are not the same as third_party. But of course in general, third_party can be recipient with a different authenticator, and there's no good way to prevent that.

I think this attack is a special case of "if the trusted third party is not trustworthy, your objects will get locked up", but makes the important point that the trusted third party might have more motivation to lock up your object than you might think (i.e., trolling is not rational, holding a free American option is...)

@sblackshear
Copy link
Collaborator Author

sblackshear commented Nov 20, 2021

Thanks for these examples, they're great!

In several cases, I've noticed portions of examples that angle towards ACLs: we have a list of subjects with special permissions:

  • const ADMIN in Hero.move,
  • const OWNER in TrustedCoin.move

I've indicated other "roles" that may arise, for instance on the EscrowSwap contract.

Sidenote:
Just so we're on the same page re: vocabulary in the context of this discussion:

  • we're dealing with resources (e.g. a boar, a sword, a TreasuryCap),
  • and we're dealing with subjects (e.g. the owner of the passed resources, the admin account, the coin OWNER account),

ACLs are what guarantees safety when you "classify" what can happen depending on the resource at hand (e.g. for the Hero contract, the normal callers have ambient permissions to slay, heal, ..., whereas the admin also has permissions to create_{potion, boar}). And, as you know, capabilities are what happen when you "sort" permissions on the subject at hand (e.g. Bob has a Sword, and a Boar, so he can create a Hero, and maybe slay, but not heal).

Overall, I would like some details on the management of the contract ACL list, if you will.

  • if it is, as demonstrated, limited to constants —requiring a full-fleged contract update to change— do we plan to manage those updates more loosely in FastX? If not, is this manageable? How do we address the proliferation of contracts who want a "fork" of the HeroesOfBC&Magic game?
  • Will we materialize explicit ACLs? What would that look like? Maybe a Permissions type, pointers from smart contracts to a specific handful of coarse Permissions instances, and a global namespace tying Permissions to users ?
  • How do we delegate and revoke permissions?

if it is, as demonstrated, limited to constants —requiring a full-fleged contract update to change— do we plan to manage those updates more loosely in FastX? If not, is this manageable?

How do we address the proliferation of contracts who want a "fork" of the HeroesOfBC&Magic game?

If you want to use objects defined by HeroesOfBC&Magic in a different game, that should be possible by simply defining a new module that adds new logic around those objects. However, if the user wants to mutate the objects in ways that aren't allowed by the original module, or change the game logic, they'll need to fork the contract. If it's well-engineered, HeroesOfBC&Magic will be split across multiple modules that isolate the more generic bits from the game-specific ones + allows lots of customization of the generic bits.

Will we materialize explicit ACLs? What would that look like? Maybe a Permissions type, pointers from smart contracts to a specific handful of coarse Permissions instances, and a global namespace tying Permissions to users ?

TBD. I think there are interesting decisions between simplicity (it doesn't get any easier than asserting that the sender authenticator is equal to a constant) and more complex, but possibly harder-to-use access control functionality. My inclination is to start with the simplest methods, then add more as there are needs/clear value props (using capabilities, which are more complex but enable delegation is a great example).

How do we delegate and revoke permissions?

See #4 (comment)

@sblackshear sblackshear force-pushed the programmability_rfc branch 4 times, most recently from ced417d to c0c0fa5 Compare November 22, 2021 18:08
@sblackshear sblackshear merged commit e170b6f into MystenLabs:main Nov 26, 2021
lxfind added a commit that referenced this pull request Feb 1, 2022
[Object Ownership #4] Prevent circular ownership
brson pushed a commit to brson/sui that referenced this pull request Apr 30, 2024
jordanjennings-mysten added a commit to jordanjennings-mysten/sui that referenced this pull request Oct 22, 2024
# This is the 1st commit message:

reword

# The commit message MystenLabs#2 will be skipped:

# fix

# The commit message MystenLabs#3 will be skipped:

# fix

# The commit message MystenLabs#4 will be skipped:

# fix
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