We are making a design decision now and we need your voice.
Since we are introducing contract factories we need to agree on the new syntax on the Sophia side of the new features. The time is up as the opcodes are already in the testing phase.
Just to remind: we are introducing 3 new primitives:
-
BYTECODE_HASH
– takes a contract and returns the hash of its bytecode. Fairly simple. -
CREATE
– takes a contract bytecode (new thing), deploys it and returns contract as a callable value. -
CLONE
– just like create but takes an existing contract and clones it. It shall have a separate state and balance that are set up from scratch (no state cloning). It is more efficient thanCREATE
since we can share code references and therefore the gas price is significantly lower.
Code introspection
Here the situation seems to be obvious. There will be a new function Chain.bytecode_hash : contract => option(hash)
that takes a contract and returns hash of it. Will fallback to None
on failure.
One of the ideas brought by @cytadela8 is if we should charge gas for the introspected bytecode size as one could deploy a big contract and spam this operation (making the execution costly). On the other hand the VM could just cache the results of it.
Contract cloning
For CLONE
my idea is to add a new function Chain.clone
with a named argument contract
/clonee
(to be discussed), optional protection annotation and all the arguments that its init
is going to take. It returns a thing of the same type as the cloned contract. Example:
contract Clonee =
type state = int
entrypoint init : int => state
contract Main =
entrypoint duplicate(c : Clonee) : Clonee =
Chain.clone(contract = c, protected = false, 2137)
I was thinking about the OOP syntax c.clone(21237)
, but this would collide with a potential clone
entrypoint of c
. Another possibility is to introduce new
keyword for this: new c(2137)
, but not sure how intuitive would it be.
Question to you: the current remote calls support limitation of gas for the execution. Do you want to have this option for cloning as well? Case is that hypothetically init
can take a lot of resources. This is an important thing to agree on if we want to have this, because this affects the behavior of the VM and the arities of FATE opcodes.
Arbitrary contract creation
This will have the biggest impact on the syntax and interface. At the current state Sophia allows only one contract definition and multiple contract declarations (for the purpose of remote calls). Moreover there is an assumption that the latest toplevel entity is the main contract. While it was quite obvious back then which contract was the “main” one, as it had to be also the only one that contains entrypoints’ definitions not only type declarations, now there would be some ambiguity if we do it in the most naive way:
contract FungusToken =
entrypoint init() = ...
contract FungibleToken =
entrypoint init() = ...
contract FunnyToken =
entrypoint init() = ...
…which one of these three is the main one and which are the deployable side contracts? The answer is known to devs with some insight – the last one as stated – but this is very misleading and I believe could be used to tricky frauds.
My proposal is to get rid of that “last contract” assertion and change the syntax to the following:
// Main contract
contract Main = ...
// Contract declaration for remote calls and cloning
contract type RemoteContract = ...
// Contract definition for deployment,
// but also remote calls and cloning
contract schema DeployableContract = ...
Note that the position of the main contract is now arbitrary and there are syntactic changes:
- new
schema
keyword that is used to indicate a independent contract definition that is used only as a type declaration and a base for the new “create” feature - requirement to add
type
betweencontract
keyword and contract’s name in contract type declaration
While I am pretty convinced to the type
keyword, I have doubts about schema
. How would you describe it? I decided not to change the main contract definition as it would break a lot of existing contracts. Now only those using remote calls are affected to a little extent.
Next thing is the syntax for contract deploy. Some ideas for that:
let c = Chain.create(SomeContract, arg1, arg2)
let c = SomeContract.create(arg1, arg2)
let c = SomeContract(arg1, arg2)
let c = new SomeContract(arg1, arg2)
-
let c : SomeContract = Chain.create(arg1, arg2)
// thanks Ulf!
The create
word is also a matter of discussion – what would you say for deploy
?
Personally I like the new
keyword, despite Java PTSD.
Gas
Proposed gas prices:
-
CREATE
– 10000 -
CLONE
– 1000 -
BYTECODE_HASH
– 100
btw
Btw, CLONE
and CREATE
have optional value
named argument just like remote calls.
Related PRs
- Add CREATE, CLONE and BYTECODE_HASH opcodes. Add bytecode typerep and datatype by radrow · Pull Request #94 · aeternity/aebytecode · GitHub
- https://github.com/aeternity/aeternity/pull/3544
- Factories sophia – tests by radrow · Pull Request #3590 · aeternity/aeternity · GitHub
- Contract factories and bytecode introspection by radrow · Pull Request #305 · aeternity/aesophia · GitHub
Summary
I need your opinions on the following dillemas:
- Do we want optional gas limitation on
CREATE
andCLONE
? - How do you see the syntax for contract cloning?
- How do you see the syntax for contract creation?
- What do you think about the proposed syntax for contract declarations? Asking especially about the
schema
keyword. - Do we want to have some special gas treatment for
BYTECODE_HASH
?
Stay safe and well typed!
CC @contributor