neo-go
neo-go copied to clipboard
Create contract manifest during compilation
While some of the contract features cannot be determined from the contract source (e.g. IsPayable) most of them can. Method and Event descriptions should be generated automatically.
I think it is also worth supporting Permissions/Groups (via magic comments?), so that manifest can be completely generated from source.
Perhaps, we can define Permissions/Groups right into configuration .yaml file, like it was done before for contract author, email and etc. Usage of this file is required for .manifest.json generation, so why not to add some more configurable fields to it?
@roman-khimov ?
I support this. 👍 💯
@roman-khimov as we discussed in the other issue, I would keep generating the YAMLs. However, I would check if the YAML can be automagically generated somehow (as you suggested).
A short-term approach, in my opinion, would be:
- when the user compiles the
contract.gousing theneo-go contract compile, it reads comment's tags and not only generates the NEF, but also the YAML file - if the user wants to compile the contract without generating the YAML file again (for whatever reason), this behavior can be specified as a param to the
neo-go contract compile
The only disadvantage with this approach is that the neo-go would need to parse and validate comment, which can be ugly. But I believe you guys can re-use the tools used in swag.
The best (long-term) approach would be to automagically generate the YAML from analyzing the script. But this is a second step after generating from comments (as I mentioned above).
If we're to get all metadata from the source code we probably no longer need YAMLs then, compiler could just emit NEF and manifest. But
neo-go would need to parse and validate comment, which can be ugly
this still is a problem.
The best (long-term) approach would be to automagically generate the YAML from analyzing the script.
If we're to get back to the list of things specified there:
- name
Can't be derived from the code, it's either needs to be specified in the comment or some magic variable (like
var _contract_name = "Name"with_contract_namebeing a reserved identifier) - list of supported standards Also can't be derived directly.
- list of safe methods #1596
- events
Unfortunately, even this is problematic. We can analyze
runtime.Notify()argument types, but is the type we have there is the intended one? Do we want to emit "Tranfser" if that's what is written in the source code? How do we mapinterface{}into event type? What if event name is a variable? So some declaration is still needed even there.
Hello.
What if there is a method that returns the configuration object? It doesn't need annotations. The compiler could identify the method by the return type. For example, if it returns the NeoMetadataStruct, you know that this method will generate the configuration.
- There won't be conflicts with existing applications because this type doesn't exist yet.
Something like this (I'm not a go dev):
type NeoMetadata struct {
Name string
Source *string
SupportedStandards []string
Trusts []string
Permissions []map[string]interface{}
Groups []map[string]interface{}
Author *string
Email *string
Description *string
}
func ContractMetadata() *NeoMetadata {
return &NeoMetadata{
Name: "",
SupportedStandards: []string{},
Trusts: []string{},
Permissions: []map[string]interface{}{},
Groups: []map[string]interface{}{},
}
}
I'm not sure if this is what I was proposing in the other issue. It's not that I want it to be automatic, I just want it to use a single file instead
Magic variables were considered previously, they can help to some extent, but I'm not sure it'd be a big improvement if they just have the same data, it could be a magic
const __manifest = `
name: "NeoFS Object NFT"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: ["NEP-11"]
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "properties", "tokens"]
events:
- name: Transfer
parameters:
- name: from
type: Hash160
- name: to
type: Hash160
- name: amount
type: Integer
- name: tokenId
type: ByteArray
permissions:
- hash: fffdc93764dbaddd97c48f252a53ea4643faa3fd
methods: ["update", "destroy"]
- methods: ["onNEP11Payment"]
overloads:
balanceOfDivisible: balanceOf
transferDivisible: transfer
`
then. Is it better than a separate YAML?
At the same time we have some mechanism for event guessing now (implemented as a part of #3008), the hardest part other than that is likely method safeness (permissions can technically be guessed in a way similar to events). But we've also got overloads (https://github.com/nspcc-dev/neo-go/blob/master/docs/compiler.md#Overloads).
Magic variables were considered previously, they can help to some extent, but I'm not sure it'd be a big improvement if they just have the same data, it could be a magic
const __manifest = ` name: "NeoFS Object NFT" sourceurl: https://github.com/nspcc-dev/neo-go/ supportedstandards: ["NEP-11"] safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "properties", "tokens"] events: - name: Transfer parameters: - name: from type: Hash160 - name: to type: Hash160 - name: amount type: Integer - name: tokenId type: ByteArray permissions: - hash: fffdc93764dbaddd97c48f252a53ea4643faa3fd methods: ["update", "destroy"] - methods: ["onNEP11Payment"] overloads: balanceOfDivisible: balanceOf transferDivisible: transfer `then. Is it better than a separate YAML?
At the same time we have some mechanism for event guessing now (implemented as a part of #3008), the hardest part other than that is likely method safeness (permissions can technically be guessed in a way similar to events). But we've also got overloads (https://github.com/nspcc-dev/neo-go/blob/master/docs/compiler.md#Overloads).
For some use cases, it's better than a separate file. However, I can see that it may become an issue once it gets bigger. It would be better if it were typed 😅
Edit: This could be replaced with a type, like a "NEP11TransferEvent"
- name: Transfer parameters:
- name: from type: Hash160
- name: to type: Hash160
- name: amount type: Integer
- name: tokenId type: ByteArray
Edit 2:, if the user declares it NEP-11 or NEP-xx compliant, the safe methods and events can be 'guessed' (enforced?)
It could be like this:
const __manifest = ` name: "NeoFS Object NFT" sourceurl: https://github.com/nspcc-dev/neo-go/ supportedstandards: ["NEP-11"] // This line tells the compiler to find the methods and events permissions: - hash: fffdc93764dbaddd97c48f252a53ea4643faa3fd methods: ["update", "destroy"] - methods: ["onNEP11Payment"] // Maybe this one is not needed overloads: balanceOfDivisible: balanceOf transferDivisible: transfer `
this looks cool. Any progress on this @roman-khimov ? be nice to not have to have a seperate yaml file!
Not on the roadmap at the moment (https://github.com/nspcc-dev/neo-go/milestone/76). Patches are welcome. Can be done step by step, btw, starting with simple attributes (name/url/standards).