2018-03-25 16:21:00 +00:00
# NEO-GO smart contract compiler
2018-02-19 09:24:28 +00:00
The neo-go compiler compiles Go programs to bytecode that the NEO virtual machine can understand.
## Currently supported
2018-02-24 09:06:48 +00:00
### Go internals
2018-03-25 16:21:00 +00:00
- type checking
- multiple assignments
2018-02-25 12:26:56 +00:00
- global variables
- types int, string, byte and booleans
2018-02-19 09:24:28 +00:00
- struct types + method receives
- functions
2018-02-27 09:04:24 +00:00
- composite literals `[]int, []string, []byte`
2018-02-19 09:24:28 +00:00
- basic if statements
2018-03-25 16:21:00 +00:00
- binary expressions
2018-02-19 09:24:28 +00:00
- return statements
2018-04-04 19:41:19 +00:00
- for loops
2018-02-24 09:06:48 +00:00
- imports
2018-03-25 16:21:00 +00:00
### Go builtins
- len
2018-04-04 19:41:19 +00:00
- append
2018-03-25 16:21:00 +00:00
2018-02-24 09:06:48 +00:00
### VM API (interop layer)
2019-09-17 16:09:02 +00:00
Compiler translates interop function calls into NEO VM syscalls or (for custom
functions) into NEO VM instructions. [Refer to GoDoc ](https://godoc.org/github.com/nspcc-dev/neo-go/pkg/interop ) for full API documentation.
#### Standard NEO Smart Contract API
- account
- asset
- attribute
2018-08-19 18:47:10 +00:00
- block
2019-09-17 16:09:02 +00:00
- blockchain
- contract
- engine
2018-08-19 18:47:10 +00:00
- header
2019-09-17 16:09:02 +00:00
- input
- iterator
- output
- runtime
- storage
2018-08-19 18:47:10 +00:00
- transaction
2018-07-02 13:02:00 +00:00
2019-09-17 16:09:02 +00:00
#### Custom VM utility helper functions
- crypto:
- `SHA1`
- `SHA256`
- `Hash256`
- `Hash160`
- enumerator
- util:
- `Equals` (to emit `EQUALS` opcode, not needed usually)
- `FromAddress(address string) []byte`
2018-02-19 09:24:28 +00:00
## Not supported
Due to the limitations of the NEO virtual machine, features listed below will not be supported.
- channels
- goroutines
2019-09-17 16:09:02 +00:00
- returning multiple values from functions
2018-02-19 09:24:28 +00:00
2018-03-25 16:21:00 +00:00
## Quick start
### Compile a smart contract
```
./bin/neo-go contract compile -i mycontract.go
```
By default the filename will be the name of your .go file with the .avm extension, the file will be located in the same directory where your Go contract is. If you want another location for your compiled contract:
```
./bin/neo-go contract compile -i mycontract.go --out /Users/foo/bar/contract.avm
```
### Debugging your smart contract
You can dump the opcodes generated by the compiler with the following command:
```
2019-08-15 16:53:21 +00:00
./bin/neo-go contract inspect -i mycontract.go
2018-03-25 16:21:00 +00:00
```
This will result in something like this:
```
INDEX OPCODE DESC
2019-08-15 16:53:21 +00:00
0 0x54 PUSH4
1 0xc5 NEWARRAY
2 0x6b TOALTSTACK
3 0x1 PUSHBYTES1
3 0x2a *
5 0x6a DUPFROMALTSTACK
6 0x0 PUSH0
7 0x52 PUSH2
8 0x7a ROLL
9 0xc4 SETITEM
10 0x6a DUPFROMALTSTACK
11 0x0 PUSH0
12 0xc3 PICKITEM
13 0x5a PUSH10
14 0xa2 GTE
15 0x64 JMPIFNOT
16 0x7 7
16 0x0 0
18 0x51 PUSH1
19 0x6c FROMALTSTACK
20 0x75 DROP
21 0x66 RET
22 0x0 PUSH0
23 0x6c FROMALTSTACK
24 0x75 DROP
25 0x66 RET
2018-03-25 16:21:00 +00:00
```
### Test invoke a compiled contract
You can simulate a test invocation of your compiled contract by the VM, to know the total gas cost for example, with the following command:
```
./bin/neo-go contract testinvoke -i mycompiledcontract.avm
```
Will output something like:
```
{
"state": "HALT, BREAK",
"gas_consumed": "0.006",
"Stack": [
{
"type": "Integer",
"value": "9"
}
]
}
```
2019-09-17 16:09:02 +00:00
At the moment this is implemented via RPC call to the remote server.
2018-02-27 09:04:24 +00:00
## Smart contract examples
2020-04-09 16:45:46 +00:00
Some examples are provided in the [examples directory ](examples ).
2019-09-17 16:09:02 +00:00
2018-02-27 09:04:24 +00:00
### Check if the invoker of the contract is the owning address
```Golang
package mycontract
2018-07-02 13:02:00 +00:00
import (
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/interop/util"
2018-07-02 13:02:00 +00:00
)
2018-02-27 09:04:24 +00:00
2018-07-02 13:02:00 +00:00
var owner = util.FromAddress("AJX1jGfj3qPBbpAKjY527nPbnrnvSx9nCg")
2018-02-27 09:04:24 +00:00
func Main() bool {
isOwner := runtime.CheckWitness(owner)
if isOwner {
runtime.Log("invoker is the owner")
return true
}
return false
}
```
### Simple token
```Golang
package mytoken
import (
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
2018-02-27 09:04:24 +00:00
)
2018-07-02 13:02:00 +00:00
var owner = util.FromAddress("AJX1jGfj3qPBbpAKjY527nPbnrnvSx9nCg")
2018-02-27 09:04:24 +00:00
type Token struct {
Name string
Symbol string
TotalSupply int
Owner []byte
}
func (t Token) AddToCirculation(amount int) bool {
2018-04-10 09:45:31 +00:00
ctx := storage.Context()
2018-08-19 18:47:10 +00:00
inCirc := storage.Get(ctx, "in_circ").(int)
2018-02-27 09:04:24 +00:00
inCirc += amount
storage.Put(ctx, "in_circ", inCirc)
return true
}
func newToken() Token {
return Token{
Name: "your awesome NEO token",
Symbol: "YANT",
TotalSupply: 1000,
Owner: owner,
}
}
func Main(operation string, args []interface{}) bool {
token := newToken()
trigger := runtime.GetTrigger()
if trigger == runtime.Verification() {
isOwner := runtime.CheckWitness(token.Owner)
if isOwner {
return true
}
return false
}
if trigger == runtime.Application() {
if operation == "mintTokens" {
token.AddToCirculation(100)
}
}
return true
}
```
2018-02-24 09:06:48 +00:00
## How to report compiler bugs
2018-02-19 09:24:28 +00:00
1. Make a proper testcase (example testcases can be found in the tests folder)
2. Create an issue on Github
3. Make a PR with a reference to the created issue, containing the testcase that proves the bug
4. Either you fix the bug yourself or wait for patch that solves the problem