near / NEPs

The Near Enhancement Proposals repository
https://nomicon.io
215 stars 138 forks source link

[Proposal] The contract lifetime #90

Open lexfrl opened 4 years ago

lexfrl commented 4 years ago

as a follow-up to the protocol research group discussion 30.06.2020

At the moment Near runtime doesn't have a notion for a contract lifetime. Lack of a contract lifetime logic negatively affects the following areas:

From a DevX perspective, developer has to keep in mind to not forget to define the deployment procedure outside to the contract source code - there is no other choice but to define and maintain the deployment script separately. It's also not prefect for a bunch of reasons:

The list is not exhaustive.

The proposal

I suggest to upgrade runtime by introducing the explicit notion of a contract lifetime. This shouldn't require a lot of changes to the code, thought impact on the runtime semantics and DeX experience are significant.

Implementation steps

1) Reserve a function export symbol _init; 2) Extend the Deploy action to carry arguments (Vec<u8>); 3) Extend Runtime to call the _init function export with provided arguments as part of the Deploy action processing and update the contract state. 4) Restrict the direct (full) access to the account on the initial code deployment. Relax it back when account.code empty.

As a new default, we should take out the arbitrary ability of altering code from an external actor which is made with no respect to the logic of the deployed contract. From the moment of deployment till destruction, account is fully managed by the contract code- that should be an axiom. Not having this default is not safe since it opens a window for leaks to the contact invariants. I suggest the following: Deploy action should check if there is a code deployed and should restrict a FullAccess into the account, since otherwise that opens a direct external access to the internal account state which consistency is ought to be maintained by the contract. Having this rule may improve trustability of contracts due to a better semantic expressiveness of operation (and because the argument is valid and its premises are true, the argument is sound).

Note: fees are not covered in this proposal (CC @olonho)

CC @amgando @evgenykuzyakov @nearmax @willemneal @SkidanovAlex @ilblackdragon @frol @bowenwang1996

bowenwang1996 commented 4 years ago

How does destruction work?

lexfrl commented 4 years ago

The contract itself must define a self-destruction logic.

lexfrl commented 4 years ago

Interesting side-effect on testing experience: seems like this might be a significant improvement for unit-testing also, since it's unlocking testability of a contract initialization.

lexfrl commented 4 years ago

Updated the text a bit.

bowenwang1996 commented 4 years ago

The contract itself must define a self-destruction logic.

There needs to be something in the runtime that allows this. Otherwise you can only destroy data associated with the contract but not the contract itself.

lexfrl commented 4 years ago

Right. It must be allowed to call Deploy action if action was created by the contract code.

lexfrl commented 4 years ago

In short, we just restrict any "sender = receiver" calls if account.code is not empty. DeployAction can contain empty Vec<u8>.

lexfrl commented 4 years ago

But you're right, the problem is that it seems like we don't have action type witch just erases the contract state. AccountDelete does that (but it also deletes an account, which is unfortunate).

bowenwang1996 commented 4 years ago

Actually I don't think the self-destruction logic is necessary. We can just delete everything stored under ContractData prefix.

lexfrl commented 4 years ago

Actually I don't think the self-destruction logic is necessary.

It could be (maybe) useful if a contract has some (if any) obligations towards to other contracts/accounts.