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

Directive: Early binding of names to contracts #1078

Closed
lgalabru opened this issue Aug 2, 2019 · 11 comments
Closed

Directive: Early binding of names to contracts #1078

lgalabru opened this issue Aug 2, 2019 · 11 comments
Assignees

Comments

@lgalabru
Copy link
Member

lgalabru commented Aug 2, 2019

I’d like to improve the way we’re handling contract identification, deployment + dependency management.

#### Name being unique
I think I’m concerned by the scarcity of contract's names. Developers will rush their contracts for getting the right name, or worst, the common names will be squatted with dangerous contracts (“token”, “blockstack”, “admin”, etc).
I'm having a hard time seeing the upsides.

Developer experience at deployment

I’m also concerned by deployment flows, being error prone.
At this point, if my understanding of the flow is correct, when a developer wants to deploy a contract, he would have to specify the name of his contract at deploy time, from the CLI.
Let’s consider the following scenario: I have 2 contracts, rocket-factory and rocket-market, with the latter contract-call-ing the former.
My contracts are ready, tested, they’ve been audited, light is green for a deployment on main-net.
I’m trying to deploy rocket-market, but bummer, the name is already taken. I have to find another name + try again. If it worked, I'll have to manually edit rocket-factory, and update the name. Cherry on-top, my project is "git dirty", and the sha deployed won’t match with the sha audited.
I’m concerned by the fact that there’s some room for a human error, at deploy time (the most stressful step).

Lack of versioning

Deploying a fixed version of a flawed contract is part of the real life. I'm obviously not saying that we should update the contract, but we should provide traceability, and be able to say that a contract B is a newer version of contract A.
As a user interacting with a contract, I'd like to be able to look at the history of that contract, and if for some reason, I'm not interacting with the latest version, or if one of the contract being called is not pointing to the latest and greatest version, I'd like to get a huge warning from the wallet interface

Here is my suggestion:
We can require a manifest / header in the contract for:

  • Specifying a name (required)
  • Specifying a version (required)
  • Adding a description (optional?)

If your contract include a contract-call, then a define-dependency must be included, fully qualifying the contract you’d like to call: owner principal + name + version.
You would end up with something like this:

(define-contract 
    (name "rocket-factory")
    (version 1)
    (description "Lorem ipsum dolor sit amet."))

(define-dependency rocket-market ((name "rocket-market") (principal 'STX00000000000000000000000000001) (version 1)))
(define-dependency rocket-token  ((name "rocket-token")  (principal 'STX00000000000000000000000000001) (version 1)))
@jcnelson
Copy link
Member

jcnelson commented Aug 2, 2019

Name being unique
I think I’m concerned by the scarcity of contract's names. Developers will rush their contracts for getting the right name, or worst, the common names will be squatted with dangerous contracts (“token”, “blockstack”, “admin”, etc).
I'm having a hard time seeing the upsides.

Names are unique within the context of the principal that created the smart contract. If your address is SP11V9BF5TGNZFKB6WJHYKE2DEAW9SGQAJF4GGMEV, and my address is SP3RGBYWD8QPRA12K531CCZ9P5Q9V3F0NDWVVF75S, we can both create a contract named blockstack, because within the Clarity VM (and within contract-call!), the contract names are:

  • SP11V9BF5TGNZFKB6WJHYKE2DEAW9SGQAJF4GGMEV.blockstack
  • SP3RGBYWD8QPRA12K531CCZ9P5Q9V3F0NDWVVF75S.blockstack

At this point, if my understanding of the flow is correct, when a developer wants to deploy a contract, he would have to specify the name of his contract at deploy time, from the CLI.

In the near future, this will be done within a transaction. So, the developer will be supplying the contract name plus one or more private keys. The key(s), in turn, will be used to derive the address prefix above.

Within the contracts deployed by the same keys (e.g. within all contracts deployed by SP11V9BF5TGNZFKB6WJHYKE2DEAW9SGQAJF4GGMEV), you can use relative names. For example, if you deploy two contracts called rocket-market and rocket-factory, the code in rocket-market can contract-call! rocket-factory and the code in rocket-factory can contract-call! rocket-market without needing the address prefix.

If I deploy a separate contract astronaut under SP3RGBYWD8QPRA12K531CCZ9P5Q9V3F0NDWVVF75S, then I would need to supply your address to call into rocket-factory or rocket-market (e.g. contract-call! SP11V9BF5TGNZFKB6WJHYKE2DEAW9SGQAJF4GGMEV.rocket-market).

but we should provide traceability, and be able to say that a contract B is a newer version of contract A.

I agree that traceability is a legitimate concern. However, I don't currently believe that this is something Clarity needs to address (but am open to being convinced otherwise). I'll have to think more about this.

@jcnelson
Copy link
Member

jcnelson commented Aug 2, 2019

If your contract include a contract-call, then a define-dependency must be included, fully qualifying the contract you’d like to call: owner principal + name + version.
You would end up with something like this:

I don't think this is the right way to go about this. This information is already captured in the current naming scheme ${address}.${name}. If there are multiple versions of a contract, then the ${name} component will be different for each version already (as a consequence of needing to be unique within the context of the same ${address}). There is thus no need for define-dependency -- each instance of contract-call! will explicitly identify the particular contract and function it wants to call into.

Without gaining or losing safety, developers are free to adopt a convention for naming different versions of a contract or public function (or even data maps and variables). For example, I could have blockstack and blockstack_v2 as contracts.

@lgalabru
Copy link
Member Author

lgalabru commented Aug 2, 2019

Within the contracts deployed by the same keys (e.g. within all contracts deployed by SP11V9BF5TGNZFKB6WJHYKE2DEAW9SGQAJF4GGMEV), you can use relative names

Ok, I missed that part, thank you for clarifying.

@kantai
Copy link
Member

kantai commented Aug 2, 2019

Yep -- I think the proposed naming scheme of { pub-key-hash } . { chosen-name } takes care of most of this. As far as versioning goes, I think we should punt on that.

@lgalabru
Copy link
Member Author

lgalabru commented Aug 2, 2019

I still think that providing the name of the contract at deploy time is a fragile flow where there's a too much room for human errors (typos, contract name intertwining, etc).
The name of a contract should be included in the contract itself.

For example, I could have blockstack and blockstack_v2 as contracts.

Sure, but a wallet can't build a version history + traceability, which is something that would definitely be a game changer, compared to other smart contract languages.

@lgalabru lgalabru closed this as completed Aug 2, 2019
@jcnelson jcnelson reopened this Aug 2, 2019
@jcnelson
Copy link
Member

jcnelson commented Aug 2, 2019

I think we should think more about having an "early binding" on contract names. If we put them into the contract source itself, then the CLI tool can do an end-to-end check across a set of contracts to verify that all contract names are still available.

@kantai kantai changed the title Considering embedding a manifest in the contracts Proposal: Early binding of names to contracts Aug 2, 2019
@jcnelson
Copy link
Member

jcnelson commented Aug 8, 2019

  • Each contract context knows the address of the principal that created it.
  • The . is reserved -- it can't be in a contract name.

@kantai kantai changed the title Proposal: Early binding of names to contracts Directive: Early binding of names to contracts Aug 8, 2019
@kantai
Copy link
Member

kantai commented Aug 13, 2019

One thing that we should be sure to do:
When we make this change, we'll want to update any of our rust method signatures (in the interpreter or the checker passes) that expect a contract name as input to take a qualified contract name struct as input, rather than a string.

This struct will also be used to enforce any constraints on contract names (name length, etc.).

@lgalabru
Copy link
Member Author

The conclusion on how we're implementing this binding is unclear. Are we introducing something like:

(define-contract 
    (name "rocket-factory"))

cc @jcnelson @kantai

@jcnelson
Copy link
Member

No. The contract name is defined outside of the contract code body (i.e. the type variant that encodes a transaction that instantiates a smart contract has a separate "name" field that will include the developer-given name, sans address). The fully-qualified name is derived from both the standard principal that sent the transaction, and the name given in the transaction.

@lgalabru
Copy link
Member Author

Addressed with #1105

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

No branches or pull requests

4 participants