forked from TrueCloudLab/neoneo-go
Merge pull request #1702 from nspcc-dev/native/interop
Represent native contracts as interop packages
This commit is contained in:
commit
71494e6ae4
21 changed files with 1016 additions and 51 deletions
|
@ -275,6 +275,26 @@ func isSyscall(fun *funcScope) bool {
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const interopPrefix = "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
|
||||||
func isInteropPath(s string) bool {
|
func isInteropPath(s string) bool {
|
||||||
return strings.HasPrefix(s, "github.com/nspcc-dev/neo-go/pkg/interop")
|
return strings.HasPrefix(s, interopPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNativeHelpersPath(s string) bool {
|
||||||
|
return strings.HasPrefix(s, interopPrefix+"/native")
|
||||||
|
}
|
||||||
|
|
||||||
|
// canConvert returns true if type doesn't need to be converted on type assertion.
|
||||||
|
func canConvert(s string) bool {
|
||||||
|
if len(s) != 0 && s[0] == '*' {
|
||||||
|
s = s[1:]
|
||||||
|
}
|
||||||
|
if isInteropPath(s) {
|
||||||
|
s = s[len(interopPrefix):]
|
||||||
|
return s != "/iterator.Iterator" && s != "/storage.Context" &&
|
||||||
|
s != "/native/ledger.Block" && s != "/native/ledger.Transaction" &&
|
||||||
|
s != "/native/management.Contract"
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -821,13 +821,20 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
f, ok = c.funcs[name]
|
f, ok = c.funcs[name]
|
||||||
// @FIXME this could cause runtime errors.
|
if ok {
|
||||||
f.selector = fun.X.(*ast.Ident)
|
f.selector = fun.X.(*ast.Ident)
|
||||||
if !ok {
|
isBuiltin = isCustomBuiltin(f)
|
||||||
|
} else {
|
||||||
|
typ := c.typeOf(fun)
|
||||||
|
if _, ok := typ.(*types.Signature); ok {
|
||||||
c.prog.Err = fmt.Errorf("could not resolve function %s", fun.Sel.Name)
|
c.prog.Err = fmt.Errorf("could not resolve function %s", fun.Sel.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
isBuiltin = isCustomBuiltin(f)
|
|
||||||
|
ast.Walk(c, n.Args[0])
|
||||||
|
c.emitExplicitConvert(c.typeOf(n.Args[0]), typ)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
case *ast.ArrayType:
|
case *ast.ArrayType:
|
||||||
// For now we will assume that there are only byte slice conversions.
|
// For now we will assume that there are only byte slice conversions.
|
||||||
// E.g. []byte("foobar") or []byte(scriptHash).
|
// E.g. []byte("foobar") or []byte(scriptHash).
|
||||||
|
@ -1190,8 +1197,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
// not the assertion type.
|
// not the assertion type.
|
||||||
case *ast.TypeAssertExpr:
|
case *ast.TypeAssertExpr:
|
||||||
ast.Walk(c, n.X)
|
ast.Walk(c, n.X)
|
||||||
typ := toNeoType(c.typeOf(n.Type))
|
goTyp := c.typeOf(n.Type)
|
||||||
|
if canConvert(goTyp.String()) {
|
||||||
|
typ := toNeoType(goTyp)
|
||||||
emit.Instruction(c.prog.BinWriter, opcode.CONVERT, []byte{byte(typ)})
|
emit.Instruction(c.prog.BinWriter, opcode.CONVERT, []byte{byte(typ)})
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
|
@ -1242,6 +1252,24 @@ func (c *codegen) processDefers() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// emitExplicitConvert handles `someType(someValue)` conversions between string/[]byte.
|
||||||
|
// Rules for conversion:
|
||||||
|
// 1. interop.* types are converted to ByteArray if not already.
|
||||||
|
// 2. Otherwise convert between ByteArray/Buffer.
|
||||||
|
// 3. Rules for types which are not string/[]byte should already
|
||||||
|
// be enforced by go parser.
|
||||||
|
func (c *codegen) emitExplicitConvert(from, to types.Type) {
|
||||||
|
if isInteropPath(to.String()) {
|
||||||
|
if isByteSlice(from) && !isString(from) {
|
||||||
|
c.emitConvert(stackitem.ByteArrayT)
|
||||||
|
}
|
||||||
|
} else if isByteSlice(to) && !isByteSlice(from) {
|
||||||
|
c.emitConvert(stackitem.BufferT)
|
||||||
|
} else if isString(to) && !isString(from) {
|
||||||
|
c.emitConvert(stackitem.ByteArrayT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *codegen) rangeLoadKey() {
|
func (c *codegen) rangeLoadKey() {
|
||||||
emit.Int(c.prog.BinWriter, 2)
|
emit.Int(c.prog.BinWriter, 2)
|
||||||
emit.Opcodes(c.prog.BinWriter,
|
emit.Opcodes(c.prog.BinWriter,
|
||||||
|
@ -1890,7 +1918,8 @@ func (c *codegen) compile(info *buildInfo, pkg *loader.PackageInfo) error {
|
||||||
// Don't convert the function if it's not used. This will save a lot
|
// Don't convert the function if it's not used. This will save a lot
|
||||||
// of bytecode space.
|
// of bytecode space.
|
||||||
name := c.getFuncNameFromDecl(pkg.Path(), n)
|
name := c.getFuncNameFromDecl(pkg.Path(), n)
|
||||||
if !isInitFunc(n) && !isDeployFunc(n) && funUsage.funcUsed(name) && !isInteropPath(pkg.Path()) {
|
if !isInitFunc(n) && !isDeployFunc(n) && funUsage.funcUsed(name) &&
|
||||||
|
(!isInteropPath(pkg.Path()) || isNativeHelpersPath(pkg.Path())) {
|
||||||
c.convertFuncDecl(f, n, pkg)
|
c.convertFuncDecl(f, n, pkg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,37 @@ func TestTypeConversion(t *testing.T) {
|
||||||
eval(t, src, big.NewInt(42))
|
eval(t, src, big.NewInt(42))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSelectorTypeConversion(t *testing.T) {
|
||||||
|
src := `package foo
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/types"
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/util"
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
func Main() int {
|
||||||
|
var a int
|
||||||
|
if util.Equals(types.Buffer(nil), nil) {
|
||||||
|
a += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer != ByteArray
|
||||||
|
if util.Equals(types.Buffer("\x12"), "\x12") {
|
||||||
|
a += 10
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp := []byte{0x23}
|
||||||
|
if util.Equals(types.ByteString(tmp), "\x23") {
|
||||||
|
a += 100
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := "aaaaaaaaaaaaaaaaaaaa"
|
||||||
|
buf := []byte(addr)
|
||||||
|
if util.Equals(interop.Hash160(addr), interop.Hash160(buf)) {
|
||||||
|
a += 1000
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}`
|
||||||
|
eval(t, src, big.NewInt(1101))
|
||||||
|
}
|
||||||
|
|
||||||
func TestTypeConversionString(t *testing.T) {
|
func TestTypeConversionString(t *testing.T) {
|
||||||
src := `package foo
|
src := `package foo
|
||||||
type mystr string
|
type mystr string
|
||||||
|
|
|
@ -239,7 +239,7 @@ func scAndVMInteropTypeFromExpr(named *types.Named) (smartcontract.ParamType, st
|
||||||
name := named.Obj().Name()
|
name := named.Obj().Name()
|
||||||
pkg := named.Obj().Pkg().Name()
|
pkg := named.Obj().Pkg().Name()
|
||||||
switch pkg {
|
switch pkg {
|
||||||
case "runtime", "contract":
|
case "ledger", "contract":
|
||||||
return smartcontract.ArrayType, stackitem.ArrayT // Block, Transaction, Contract
|
return smartcontract.ArrayType, stackitem.ArrayT // Block, Transaction, Contract
|
||||||
case "interop":
|
case "interop":
|
||||||
if name != "Interface" {
|
if name != "Interface" {
|
||||||
|
|
|
@ -16,7 +16,7 @@ func TestCodeGen_DebugInfo(t *testing.T) {
|
||||||
src := `package foo
|
src := `package foo
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
import "github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
import "github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
|
||||||
func Main(op string) bool {
|
func Main(op string) bool {
|
||||||
var s string
|
var s string
|
||||||
_ = s
|
_ = s
|
||||||
|
@ -47,7 +47,7 @@ func unexportedMethod() int { return 1 }
|
||||||
func MethodParams(addr interop.Hash160, h interop.Hash256,
|
func MethodParams(addr interop.Hash160, h interop.Hash256,
|
||||||
sig interop.Signature, pub interop.PublicKey,
|
sig interop.Signature, pub interop.PublicKey,
|
||||||
inter interop.Interface,
|
inter interop.Interface,
|
||||||
ctx storage.Context, tx runtime.Transaction) bool {
|
ctx storage.Context, tx ledger.Transaction) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
type MyStruct struct {}
|
type MyStruct struct {}
|
||||||
|
|
271
pkg/compiler/native_test.go
Normal file
271
pkg/compiler/native_test.go
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
package compiler_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/gas"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/nameservice"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/neo"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/notary"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/oracle"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/policy"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/roles"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestContractHashes(t *testing.T) {
|
||||||
|
cs := native.NewContracts(true)
|
||||||
|
require.Equal(t, []byte(neo.Hash), cs.NEO.Hash.BytesBE())
|
||||||
|
require.Equal(t, []byte(gas.Hash), cs.GAS.Hash.BytesBE())
|
||||||
|
require.Equal(t, []byte(oracle.Hash), cs.Oracle.Hash.BytesBE())
|
||||||
|
require.Equal(t, []byte(roles.Hash), cs.Designate.Hash.BytesBE())
|
||||||
|
require.Equal(t, []byte(policy.Hash), cs.Policy.Hash.BytesBE())
|
||||||
|
require.Equal(t, []byte(nameservice.Hash), cs.NameService.Hash.BytesBE())
|
||||||
|
require.Equal(t, []byte(ledger.Hash), cs.Ledger.Hash.BytesBE())
|
||||||
|
require.Equal(t, []byte(management.Hash), cs.Management.Hash.BytesBE())
|
||||||
|
require.Equal(t, []byte(notary.Hash), cs.Notary.Hash.BytesBE())
|
||||||
|
}
|
||||||
|
|
||||||
|
// testPrintHash is a helper for updating contract hashes.
|
||||||
|
func testPrintHash(u util.Uint160) {
|
||||||
|
fmt.Print(`"`)
|
||||||
|
for _, b := range u.BytesBE() {
|
||||||
|
fmt.Printf("\\x%02x", b)
|
||||||
|
}
|
||||||
|
fmt.Println(`"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContractParameterTypes(t *testing.T) {
|
||||||
|
require.EqualValues(t, management.AnyType, smartcontract.AnyType)
|
||||||
|
require.EqualValues(t, management.BoolType, smartcontract.BoolType)
|
||||||
|
require.EqualValues(t, management.IntegerType, smartcontract.IntegerType)
|
||||||
|
require.EqualValues(t, management.ByteArrayType, smartcontract.ByteArrayType)
|
||||||
|
require.EqualValues(t, management.StringType, smartcontract.StringType)
|
||||||
|
require.EqualValues(t, management.Hash160Type, smartcontract.Hash160Type)
|
||||||
|
require.EqualValues(t, management.Hash256Type, smartcontract.Hash256Type)
|
||||||
|
require.EqualValues(t, management.PublicKeyType, smartcontract.PublicKeyType)
|
||||||
|
require.EqualValues(t, management.SignatureType, smartcontract.SignatureType)
|
||||||
|
require.EqualValues(t, management.ArrayType, smartcontract.ArrayType)
|
||||||
|
require.EqualValues(t, management.MapType, smartcontract.MapType)
|
||||||
|
require.EqualValues(t, management.InteropInterfaceType, smartcontract.InteropInterfaceType)
|
||||||
|
require.EqualValues(t, management.VoidType, smartcontract.VoidType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoleManagementRole(t *testing.T) {
|
||||||
|
require.EqualValues(t, native.RoleOracle, roles.Oracle)
|
||||||
|
require.EqualValues(t, native.RoleStateValidator, roles.StateValidator)
|
||||||
|
require.EqualValues(t, native.RoleP2PNotary, roles.P2PNotary)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNameServiceRecordType(t *testing.T) {
|
||||||
|
require.EqualValues(t, native.RecordTypeA, nameservice.TypeA)
|
||||||
|
require.EqualValues(t, native.RecordTypeCNAME, nameservice.TypeCNAME)
|
||||||
|
require.EqualValues(t, native.RecordTypeTXT, nameservice.TypeTXT)
|
||||||
|
require.EqualValues(t, native.RecordTypeAAAA, nameservice.TypeAAAA)
|
||||||
|
}
|
||||||
|
|
||||||
|
type nativeTestCase struct {
|
||||||
|
method string
|
||||||
|
params []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here we test that corresponding method does exist, is invoked and correct value is returned.
|
||||||
|
func TestNativeHelpersCompile(t *testing.T) {
|
||||||
|
cs := native.NewContracts(true)
|
||||||
|
u160 := `interop.Hash160("aaaaaaaaaaaaaaaaaaaa")`
|
||||||
|
u256 := `interop.Hash256("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")`
|
||||||
|
pub := `interop.PublicKey("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")`
|
||||||
|
nep17TestCases := []nativeTestCase{
|
||||||
|
{"balanceOf", []string{u160}},
|
||||||
|
{"decimals", nil},
|
||||||
|
{"symbol", nil},
|
||||||
|
{"totalSupply", nil},
|
||||||
|
{"transfer", []string{u160, u160, "123", "nil"}},
|
||||||
|
}
|
||||||
|
runNativeTestCases(t, cs.NEO.ContractMD, "neo", append([]nativeTestCase{
|
||||||
|
{"getCandidates", nil},
|
||||||
|
{"getCommittee", nil},
|
||||||
|
{"getGasPerBlock", nil},
|
||||||
|
{"getNextBlockValidators", nil},
|
||||||
|
{"registerCandidate", []string{pub}},
|
||||||
|
{"setGasPerBlock", []string{"1"}},
|
||||||
|
{"vote", []string{u160, pub}},
|
||||||
|
{"unclaimedGas", []string{u160, "123"}},
|
||||||
|
{"unregisterCandidate", []string{pub}},
|
||||||
|
}, nep17TestCases...))
|
||||||
|
runNativeTestCases(t, cs.GAS.ContractMD, "gas", nep17TestCases)
|
||||||
|
runNativeTestCases(t, cs.Oracle.ContractMD, "oracle", []nativeTestCase{
|
||||||
|
{"request", []string{`"url"`, "nil", `"callback"`, "nil", "123"}},
|
||||||
|
})
|
||||||
|
runNativeTestCases(t, cs.Designate.ContractMD, "roles", []nativeTestCase{
|
||||||
|
{"designateAsRole", []string{"1", "[]interop.PublicKey{}"}},
|
||||||
|
{"getDesignatedByRole", []string{"1", "1000"}},
|
||||||
|
})
|
||||||
|
runNativeTestCases(t, cs.Policy.ContractMD, "policy", []nativeTestCase{
|
||||||
|
{"blockAccount", []string{u160}},
|
||||||
|
{"getExecFeeFactor", nil},
|
||||||
|
{"getFeePerByte", nil},
|
||||||
|
{"getMaxBlockSize", nil},
|
||||||
|
{"getMaxBlockSystemFee", nil},
|
||||||
|
{"getMaxTransactionsPerBlock", nil},
|
||||||
|
{"getStoragePrice", nil},
|
||||||
|
{"isBlocked", []string{u160}},
|
||||||
|
{"setExecFeeFactor", []string{"42"}},
|
||||||
|
{"setFeePerByte", []string{"42"}},
|
||||||
|
{"setMaxBlockSize", []string{"42"}},
|
||||||
|
{"setMaxBlockSystemFee", []string{"42"}},
|
||||||
|
{"setMaxTransactionsPerBlock", []string{"42"}},
|
||||||
|
{"setStoragePrice", []string{"42"}},
|
||||||
|
{"unblockAccount", []string{u160}},
|
||||||
|
})
|
||||||
|
runNativeTestCases(t, cs.NameService.ContractMD, "nameservice", []nativeTestCase{
|
||||||
|
// nonfungible
|
||||||
|
{"symbol", nil},
|
||||||
|
{"decimals", nil},
|
||||||
|
{"totalSupply", nil},
|
||||||
|
{"ownerOf", []string{`"neo.com"`}},
|
||||||
|
{"balanceOf", []string{u160}},
|
||||||
|
{"properties", []string{`"neo.com"`}},
|
||||||
|
{"tokens", nil},
|
||||||
|
{"tokensOf", []string{u160}},
|
||||||
|
{"transfer", []string{u160, `"neo.com"`}},
|
||||||
|
|
||||||
|
// name service
|
||||||
|
{"addRoot", []string{`"com"`}},
|
||||||
|
{"deleteRecord", []string{`"neo.com"`, "nameservice.TypeA"}},
|
||||||
|
{"isAvailable", []string{`"neo.com"`}},
|
||||||
|
{"getPrice", nil},
|
||||||
|
{"getRecord", []string{`"neo.com"`, "nameservice.TypeA"}},
|
||||||
|
{"register", []string{`"neo.com"`, u160}},
|
||||||
|
{"renew", []string{`"neo.com"`}},
|
||||||
|
{"resolve", []string{`"neo.com"`, "nameservice.TypeA"}},
|
||||||
|
{"setPrice", []string{"42"}},
|
||||||
|
{"setAdmin", []string{`"neo.com"`, u160}},
|
||||||
|
{"setRecord", []string{`"neo.com"`, "nameservice.TypeA", `"1.1.1.1"`}},
|
||||||
|
})
|
||||||
|
runNativeTestCases(t, cs.Ledger.ContractMD, "ledger", []nativeTestCase{
|
||||||
|
{"currentHash", nil},
|
||||||
|
{"currentIndex", nil},
|
||||||
|
{"getBlock", []string{"1"}},
|
||||||
|
{"getTransaction", []string{u256}},
|
||||||
|
{"getTransactionFromBlock", []string{u256, "1"}},
|
||||||
|
{"getTransactionHeight", []string{u256}},
|
||||||
|
})
|
||||||
|
runNativeTestCases(t, cs.Notary.ContractMD, "notary", []nativeTestCase{
|
||||||
|
{"lockDepositUntil", []string{u160, "123"}},
|
||||||
|
{"withdraw", []string{u160, u160}},
|
||||||
|
{"balanceOf", []string{u160}},
|
||||||
|
{"expirationOf", []string{u160}},
|
||||||
|
{"getMaxNotValidBeforeDelta", nil},
|
||||||
|
{"setMaxNotValidBeforeDelta", []string{"42"}},
|
||||||
|
})
|
||||||
|
runNativeTestCases(t, cs.Management.ContractMD, "management", []nativeTestCase{
|
||||||
|
{"deploy", []string{"nil", "nil"}},
|
||||||
|
{"deployWithData", []string{"nil", "nil", "123"}},
|
||||||
|
{"destroy", nil},
|
||||||
|
{"getContract", []string{u160}},
|
||||||
|
{"getMinimumDeploymentFee", nil},
|
||||||
|
{"setMinimumDeploymentFee", []string{"42"}},
|
||||||
|
{"update", []string{"nil", "nil"}},
|
||||||
|
{"updateWithData", []string{"nil", "nil", "123"}},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func runNativeTestCases(t *testing.T, ctr interop.ContractMD, name string, testCases []nativeTestCase) {
|
||||||
|
t.Run(ctr.Name, func(t *testing.T) {
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.method, func(t *testing.T) {
|
||||||
|
runNativeTestCase(t, ctr, name, tc.method, tc.params...)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func runNativeTestCase(t *testing.T, ctr interop.ContractMD, name, method string, params ...string) {
|
||||||
|
md, ok := ctr.GetMethod(strings.TrimSuffix(method, "WithData"), len(params))
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
isVoid := md.MD.ReturnType == smartcontract.VoidType
|
||||||
|
srcTmpl := `package foo
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/native/%s"
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
var _ interop.Hash160
|
||||||
|
`
|
||||||
|
if isVoid {
|
||||||
|
srcTmpl += `func Main() { %s.%s(%s) }`
|
||||||
|
} else {
|
||||||
|
srcTmpl += `func Main() interface{} { return %s.%s(%s) }`
|
||||||
|
}
|
||||||
|
methodUpper := strings.ToUpper(method[:1]) + method[1:] // ASCII only
|
||||||
|
methodUpper = strings.ReplaceAll(methodUpper, "Gas", "GAS")
|
||||||
|
src := fmt.Sprintf(srcTmpl, name, name, methodUpper, strings.Join(params, ","))
|
||||||
|
|
||||||
|
v, s := vmAndCompileInterop(t, src)
|
||||||
|
id := interopnames.ToID([]byte(interopnames.SystemContractCall))
|
||||||
|
result := getTestStackItem(md.MD.ReturnType)
|
||||||
|
s.interops[id] = testContractCall(t, ctr.Hash, md, result)
|
||||||
|
require.NoError(t, v.Run())
|
||||||
|
if isVoid {
|
||||||
|
require.Equal(t, 0, v.Estack().Len())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.Equal(t, 1, v.Estack().Len(), "stack contains unexpected items")
|
||||||
|
require.Equal(t, result.Value(), v.Estack().Pop().Item().Value())
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestStackItem(typ smartcontract.ParamType) stackitem.Item {
|
||||||
|
switch typ {
|
||||||
|
case smartcontract.AnyType, smartcontract.VoidType:
|
||||||
|
return stackitem.Null{}
|
||||||
|
case smartcontract.BoolType:
|
||||||
|
return stackitem.NewBool(true)
|
||||||
|
case smartcontract.IntegerType:
|
||||||
|
return stackitem.NewBigInteger(big.NewInt(42))
|
||||||
|
case smartcontract.ByteArrayType, smartcontract.StringType, smartcontract.Hash160Type,
|
||||||
|
smartcontract.Hash256Type, smartcontract.PublicKeyType, smartcontract.SignatureType:
|
||||||
|
return stackitem.NewByteArray([]byte("result"))
|
||||||
|
case smartcontract.ArrayType:
|
||||||
|
return stackitem.NewArray([]stackitem.Item{stackitem.NewBool(true), stackitem.Null{}})
|
||||||
|
case smartcontract.MapType:
|
||||||
|
return stackitem.NewMapWithValue([]stackitem.MapElement{{
|
||||||
|
Key: stackitem.NewByteArray([]byte{1, 2, 3}),
|
||||||
|
Value: stackitem.NewByteArray([]byte{5, 6, 7}),
|
||||||
|
}})
|
||||||
|
case smartcontract.InteropInterfaceType:
|
||||||
|
return stackitem.NewInterop(42)
|
||||||
|
default:
|
||||||
|
panic("unexpected type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testContractCall(t *testing.T, hash util.Uint160, md interop.MethodAndPrice, result stackitem.Item) func(*vm.VM) error {
|
||||||
|
return func(v *vm.VM) error {
|
||||||
|
h := v.Estack().Pop().Bytes()
|
||||||
|
require.Equal(t, hash.BytesBE(), h)
|
||||||
|
|
||||||
|
method := v.Estack().Pop().String()
|
||||||
|
require.Equal(t, md.MD.Name, method)
|
||||||
|
|
||||||
|
fs := callflag.CallFlag(int32(v.Estack().Pop().BigInt().Int64()))
|
||||||
|
require.Equal(t, md.RequiredFlags, fs)
|
||||||
|
|
||||||
|
args := v.Estack().Pop().Array()
|
||||||
|
require.Equal(t, len(md.MD.Parameters), len(args))
|
||||||
|
|
||||||
|
v.Estack().PushVal(result)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
7
pkg/compiler/testdata/types/types.go
vendored
Normal file
7
pkg/compiler/testdata/types/types.go
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
// Buffer represents Buffer VM type.
|
||||||
|
type Buffer []byte
|
||||||
|
|
||||||
|
// ByteString represents ByteString VM type.
|
||||||
|
type ByteString string
|
|
@ -7,19 +7,6 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Compatibility test. hashes are taken directly from C# node.
|
|
||||||
func TestNativeHashes(t *testing.T) {
|
|
||||||
require.Equal(t, "a501d7d7d10983673b61b7a2d3a813b36f9f0e43", newManagement().Hash.StringLE())
|
|
||||||
require.Equal(t, "971d69c6dd10ce88e7dfffec1dc603c6125a8764", newLedger().Hash.StringLE())
|
|
||||||
require.Equal(t, "f61eebf573ea36593fd43aa150c055ad7906ab83", newNEO().Hash.StringLE())
|
|
||||||
require.Equal(t, "70e2301955bf1e74cbb31d18c2f96972abadb328", newGAS().Hash.StringLE())
|
|
||||||
require.Equal(t, "79bcd398505eb779df6e67e4be6c14cded08e2f2", newPolicy().Hash.StringLE())
|
|
||||||
require.Equal(t, "597b1471bbce497b7809e2c8f10db67050008b02", newDesignate(false).Hash.StringLE())
|
|
||||||
require.Equal(t, "8dc0e742cbdfdeda51ff8a8b78d46829144c80ee", newOracle().Hash.StringLE())
|
|
||||||
// Not yet a part of NEO.
|
|
||||||
//require.Equal(t, "", newNotary().Hash.StringLE()())
|
|
||||||
}
|
|
||||||
|
|
||||||
// "C" and "O" can easily be typed by accident.
|
// "C" and "O" can easily be typed by accident.
|
||||||
func TestNamesASCII(t *testing.T) {
|
func TestNamesASCII(t *testing.T) {
|
||||||
cs := NewContracts(true)
|
cs := NewContracts(true)
|
||||||
|
|
35
pkg/interop/native/gas/gas.go
Normal file
35
pkg/interop/native/gas/gas.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package gas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash represents GAS contract hash.
|
||||||
|
const Hash = "\x28\xb3\xad\xab\x72\x69\xf9\xc2\x18\x1d\xb3\xcb\x74\x1e\xbf\x55\x19\x30\xe2\x70"
|
||||||
|
|
||||||
|
// Symbol represents `symbol` method of GAS native contract.
|
||||||
|
func Symbol() string {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "symbol", contract.NoneFlag).(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decimals represents `decimals` method of GAS native contract.
|
||||||
|
func Decimals() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "decimals", contract.NoneFlag).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TotalSupply represents `totalSupply` method of GAS native contract.
|
||||||
|
func TotalSupply() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "totalSupply", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BalanceOf represents `balanceOf` method of GAS native contract.
|
||||||
|
func BalanceOf(addr interop.Hash160) int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "balanceOf", contract.ReadStates, addr).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer represents `transfer` method of GAS native contract.
|
||||||
|
func Transfer(from, to interop.Hash160, amount int, data interface{}) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "transfer",
|
||||||
|
contract.WriteStates|contract.AllowCall|contract.AllowNotify, from, to, amount, data).(bool)
|
||||||
|
}
|
29
pkg/interop/native/ledger/block.go
Normal file
29
pkg/interop/native/ledger/block.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package ledger
|
||||||
|
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
|
||||||
|
// Block represents a NEO block, it's a data structure that you can get
|
||||||
|
// block-related data from. It's similar to the Block class in the Neo .net
|
||||||
|
// framework. To use it you need to get it via GetBlock function call.
|
||||||
|
type Block struct {
|
||||||
|
// Hash represents the hash (256 bit BE value in a 32 byte slice) of the
|
||||||
|
// given block.
|
||||||
|
Hash interop.Hash256
|
||||||
|
// Version of the block.
|
||||||
|
Version int
|
||||||
|
// PrevHash represents the hash (256 bit BE value in a 32 byte slice) of the
|
||||||
|
// previous block.
|
||||||
|
PrevHash interop.Hash256
|
||||||
|
// MerkleRoot represents the root hash (256 bit BE value in a 32 byte slice)
|
||||||
|
// of a transaction list.
|
||||||
|
MerkleRoot interop.Hash256
|
||||||
|
// Timestamp represents millisecond-precision block timestamp.
|
||||||
|
Timestamp int
|
||||||
|
// Index represents the height of the block.
|
||||||
|
Index int
|
||||||
|
// NextConsensus represents contract address of the next miner (160 bit BE
|
||||||
|
// value in a 20 byte slice).
|
||||||
|
NextConsensus interop.Hash160
|
||||||
|
// TransactionsLength represents the length of block's transactions array.
|
||||||
|
TransactionsLength int
|
||||||
|
}
|
40
pkg/interop/native/ledger/ledger.go
Normal file
40
pkg/interop/native/ledger/ledger.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package ledger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash represents Ledger contract hash.
|
||||||
|
const Hash = "\x64\x87\x5a\x12\xc6\x03\xc6\x1d\xec\xff\xdf\xe7\x88\xce\x10\xdd\xc6\x69\x1d\x97"
|
||||||
|
|
||||||
|
// CurrentHash represents `currentHash` method of Ledger native contract.
|
||||||
|
func CurrentHash() interop.Hash256 {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "currentHash", contract.ReadStates).(interop.Hash256)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentIndex represents `currentIndex` method of Ledger native contract.
|
||||||
|
func CurrentIndex() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "currentIndex", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlock represents `getBlock` method of Ledger native contract.
|
||||||
|
func GetBlock(indexOrHash interface{}) *Block {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getBlock", contract.ReadStates, indexOrHash).(*Block)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransaction represents `getTransaction` method of Ledger native contract.
|
||||||
|
func GetTransaction(hash interop.Hash256) *Transaction {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getTransaction", contract.ReadStates, hash).(*Transaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransactionHeight represents `getTransactionHeight` method of Ledger native contract.
|
||||||
|
func GetTransactionHeight(hash interop.Hash256) int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getTransactionHeight", contract.ReadStates, hash).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransactionFromBlock represents `getTransactionFromBlock` method of Ledger native contract.
|
||||||
|
func GetTransactionFromBlock(indexOrHash interface{}, txIndex int) *Transaction {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getTransactionFromBlock", contract.ReadStates,
|
||||||
|
indexOrHash, txIndex).(*Transaction)
|
||||||
|
}
|
27
pkg/interop/native/ledger/transaction.go
Normal file
27
pkg/interop/native/ledger/transaction.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package ledger
|
||||||
|
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
|
||||||
|
// Transaction represents a NEO transaction. It's similar to Transaction class
|
||||||
|
// in Neo .net framework.
|
||||||
|
type Transaction struct {
|
||||||
|
// Hash represents the hash (256 bit BE value in a 32 byte slice) of the
|
||||||
|
// given transaction (which also is its ID).
|
||||||
|
Hash interop.Hash256
|
||||||
|
// Version represents the transaction version.
|
||||||
|
Version int
|
||||||
|
// Nonce is a random number to avoid hash collision.
|
||||||
|
Nonce int
|
||||||
|
// Sender represents the sender (160 bit BE value in a 20 byte slice) of the
|
||||||
|
// given Transaction.
|
||||||
|
Sender interop.Hash160
|
||||||
|
// SysFee represents fee to be burned.
|
||||||
|
SysFee int
|
||||||
|
// NetFee represents fee to be distributed to consensus nodes.
|
||||||
|
NetFee int
|
||||||
|
// ValidUntilBlock is the maximum blockchain height exceeding which
|
||||||
|
// transaction should fail verification.
|
||||||
|
ValidUntilBlock int
|
||||||
|
// Script represents code to run in NeoVM for this transaction.
|
||||||
|
Script []byte
|
||||||
|
}
|
82
pkg/interop/native/management/contract.go
Normal file
82
pkg/interop/native/management/contract.go
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
package management
|
||||||
|
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
|
||||||
|
// Contract represents deployed contract.
|
||||||
|
type Contract struct {
|
||||||
|
ID int
|
||||||
|
UpdateCounter int
|
||||||
|
Hash interop.Hash160
|
||||||
|
NEF []byte
|
||||||
|
Manifest Manifest
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParameterType represents smartcontract parameter type.
|
||||||
|
type ParameterType byte
|
||||||
|
|
||||||
|
// Various parameter types.
|
||||||
|
const (
|
||||||
|
AnyType ParameterType = 0x00
|
||||||
|
BoolType ParameterType = 0x10
|
||||||
|
IntegerType ParameterType = 0x11
|
||||||
|
ByteArrayType ParameterType = 0x12
|
||||||
|
StringType ParameterType = 0x13
|
||||||
|
Hash160Type ParameterType = 0x14
|
||||||
|
Hash256Type ParameterType = 0x15
|
||||||
|
PublicKeyType ParameterType = 0x16
|
||||||
|
SignatureType ParameterType = 0x17
|
||||||
|
ArrayType ParameterType = 0x20
|
||||||
|
MapType ParameterType = 0x22
|
||||||
|
InteropInterfaceType ParameterType = 0x30
|
||||||
|
VoidType ParameterType = 0xff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Manifest represents contract's manifest.
|
||||||
|
type Manifest struct {
|
||||||
|
Name string
|
||||||
|
Groups []Group
|
||||||
|
SupportedStandards []string
|
||||||
|
ABI ABI
|
||||||
|
Permissions []Permission
|
||||||
|
Trusts []interop.Hash160
|
||||||
|
Extra interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABI represents contract's ABI.
|
||||||
|
type ABI struct {
|
||||||
|
Methods []Method
|
||||||
|
Events []Event
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method represents contract method.
|
||||||
|
type Method struct {
|
||||||
|
Name string
|
||||||
|
Params []Parameter
|
||||||
|
ReturnType ParameterType
|
||||||
|
Offset int
|
||||||
|
Safe bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event represents contract event.
|
||||||
|
type Event struct {
|
||||||
|
Name string
|
||||||
|
Params []Parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parameter represents method parameter.
|
||||||
|
type Parameter struct {
|
||||||
|
Name string
|
||||||
|
Type ParameterType
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permission represents contract permission.
|
||||||
|
type Permission struct {
|
||||||
|
Contract interop.Hash160
|
||||||
|
Methods []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group represents manifest group.
|
||||||
|
type Group struct {
|
||||||
|
PublicKey interop.PublicKey
|
||||||
|
Signature interop.Signature
|
||||||
|
}
|
53
pkg/interop/native/management/management.go
Normal file
53
pkg/interop/native/management/management.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package management
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash represents Management contract hash.
|
||||||
|
const Hash = "\x43\x0e\x9f\x6f\xb3\x13\xa8\xd3\xa2\xb7\x61\x3b\x67\x83\x09\xd1\xd7\xd7\x01\xa5"
|
||||||
|
|
||||||
|
// Deploy represents `deploy` method of Management native contract.
|
||||||
|
func Deploy(script, manifest []byte) *Contract {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "deploy",
|
||||||
|
contract.WriteStates|contract.AllowNotify, script, manifest).(*Contract)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeployWithData represents `deploy` method of Management native contract.
|
||||||
|
func DeployWithData(script, manifest []byte, data interface{}) *Contract {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "deploy",
|
||||||
|
contract.WriteStates|contract.AllowNotify, script, manifest, data).(*Contract)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy represents `destroy` method of Management native contract.
|
||||||
|
func Destroy() {
|
||||||
|
contract.Call(interop.Hash160(Hash), "destroy", contract.WriteStates|contract.AllowNotify)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContract represents `getContract` method of Management native contract.
|
||||||
|
func GetContract(addr interop.Hash160) *Contract {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getContract", contract.ReadStates, addr).(*Contract)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMinimumDeploymentFee represents `getMinimumDeploymentFee` method of Management native contract.
|
||||||
|
func GetMinimumDeploymentFee() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getMinimumDeploymentFee", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMinimumDeploymentFee represents `setMinimumDeploymentFee` method of Management native contract.
|
||||||
|
func SetMinimumDeploymentFee(value int) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setMinimumDeploymentFee", contract.WriteStates, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update represents `update` method of Management native contract.
|
||||||
|
func Update(script, manifest []byte) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "update",
|
||||||
|
contract.WriteStates|contract.AllowNotify, script, manifest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateWithData represents `update` method of Management native contract.
|
||||||
|
func UpdateWithData(script, manifest []byte, data interface{}) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "update",
|
||||||
|
contract.WriteStates|contract.AllowNotify, script, manifest, data)
|
||||||
|
}
|
125
pkg/interop/native/nameservice/name_service.go
Normal file
125
pkg/interop/native/nameservice/name_service.go
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
package nameservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RecordType represents NameService record type.
|
||||||
|
type RecordType byte
|
||||||
|
|
||||||
|
// Various record type.
|
||||||
|
const (
|
||||||
|
TypeA RecordType = 1
|
||||||
|
TypeCNAME RecordType = 5
|
||||||
|
TypeTXT RecordType = 16
|
||||||
|
TypeAAAA RecordType = 28
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash represents NameService contract hash.
|
||||||
|
const Hash = "\x8c\x02\xb8\x43\x98\x6b\x3c\x44\x4f\xf8\x6a\xd5\xa9\x43\xfe\x8d\xb6\x24\xb5\xa2"
|
||||||
|
|
||||||
|
// Symbol represents `symbol` method of NameService native contract.
|
||||||
|
func Symbol() string {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "symbol", contract.NoneFlag).(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decimals represents `decimals` method of NameService native contract.
|
||||||
|
func Decimals() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "decimals", contract.NoneFlag).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TotalSupply represents `totalSupply` method of NameService native contract.
|
||||||
|
func TotalSupply() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "totalSupply", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OwnerOf represents `ownerOf` method of NameService native contract.
|
||||||
|
func OwnerOf(tokenID string) interop.Hash160 {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "ownerOf", contract.ReadStates, tokenID).(interop.Hash160)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BalanceOf represents `balanceOf` method of NameService native contract.
|
||||||
|
func BalanceOf(owner interop.Hash160) int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "balanceOf", contract.ReadStates, owner).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properties represents `properties` method of NameService native contract.
|
||||||
|
func Properties(tokenID string) map[string]interface{} {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "properties", contract.ReadStates, tokenID).(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tokens represents `tokens` method of NameService native contract.
|
||||||
|
func Tokens() iterator.Iterator {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "tokens",
|
||||||
|
contract.ReadStates).(iterator.Iterator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokensOf represents `tokensOf` method of NameService native contract.
|
||||||
|
func TokensOf(addr interop.Hash160) iterator.Iterator {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "tokensOf",
|
||||||
|
contract.ReadStates, addr).(iterator.Iterator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer represents `transfer` method of NameService native contract.
|
||||||
|
func Transfer(to interop.Hash160, tokenID string) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "transfer",
|
||||||
|
contract.WriteStates|contract.AllowNotify, to, tokenID).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRoot represents `addRoot` method of NameService native contract.
|
||||||
|
func AddRoot(root string) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "addRoot", contract.WriteStates, root)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPrice represents `setPrice` method of NameService native contract.
|
||||||
|
func SetPrice(price int) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setPrice", contract.WriteStates, price)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPrice represents `getPrice` method of NameService native contract.
|
||||||
|
func GetPrice() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getPrice", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAvailable represents `isAvailable` method of NameService native contract.
|
||||||
|
func IsAvailable(name string) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "isAvailable", contract.ReadStates, name).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register represents `register` method of NameService native contract.
|
||||||
|
func Register(name string, owner interop.Hash160) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "register", contract.WriteStates, name, owner).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renew represents `renew` method of NameService native contract.
|
||||||
|
func Renew(name string) int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "renew", contract.WriteStates, name).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAdmin represents `setAdmin` method of NameService native contract.
|
||||||
|
func SetAdmin(name string, admin interop.Hash160) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setAdmin", contract.WriteStates, name, admin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRecord represents `setRecord` method of NameService native contract.
|
||||||
|
func SetRecord(name string, recType RecordType, data string) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setRecord", contract.WriteStates, name, recType, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRecord represents `getRecord` method of NameService native contract.
|
||||||
|
// It returns `nil` if record is missing.
|
||||||
|
func GetRecord(name string, recType RecordType) []byte {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getRecord", contract.ReadStates, name, recType).([]byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRecord represents `deleteRecord` method of NameService native contract.
|
||||||
|
func DeleteRecord(name string, recType RecordType) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "deleteRecord", contract.WriteStates, name, recType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve represents `resolve` method of NameService native contract.
|
||||||
|
func Resolve(name string, recType RecordType) []byte {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "resolve", contract.ReadStates, name, recType).([]byte)
|
||||||
|
}
|
80
pkg/interop/native/neo/neo.go
Normal file
80
pkg/interop/native/neo/neo.go
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
package neo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash represents NEO contract hash.
|
||||||
|
const Hash = "\x83\xab\x06\x79\xad\x55\xc0\x50\xa1\x3a\xd4\x3f\x59\x36\xea\x73\xf5\xeb\x1e\xf6"
|
||||||
|
|
||||||
|
// Symbol represents `symbol` method of NEO native contract.
|
||||||
|
func Symbol() string {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "symbol", contract.NoneFlag).(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decimals represents `decimals` method of NEO native contract.
|
||||||
|
func Decimals() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "decimals", contract.NoneFlag).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TotalSupply represents `totalSupply` method of NEO native contract.
|
||||||
|
func TotalSupply() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "totalSupply", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BalanceOf represents `balanceOf` method of NEO native contract.
|
||||||
|
func BalanceOf(addr interop.Hash160) int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "balanceOf", contract.ReadStates, addr).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer represents `transfer` method of NEO native contract.
|
||||||
|
func Transfer(from, to interop.Hash160, amount int, data interface{}) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "transfer",
|
||||||
|
contract.WriteStates|contract.AllowCall|contract.AllowNotify, from, to, amount, data).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommittee represents `getCommittee` method of NEO native contract.
|
||||||
|
func GetCommittee() []interop.PublicKey {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getCommittee", contract.ReadStates).([]interop.PublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCandidates represents `getCandidates` method of NEO native contract.
|
||||||
|
func GetCandidates() []interop.PublicKey {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getCandidates", contract.ReadStates).([]interop.PublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNextBlockValidators represents `getNextBlockValidators` method of NEO native contract.
|
||||||
|
func GetNextBlockValidators() []interop.PublicKey {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getNextBlockValidators", contract.ReadStates).([]interop.PublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGASPerBlock represents `getGasPerBlock` method of NEO native contract.
|
||||||
|
func GetGASPerBlock() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getGasPerBlock", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetGASPerBlock represents `setGasPerBlock` method of NEO native contract.
|
||||||
|
func SetGASPerBlock(amount int) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setGasPerBlock", contract.WriteStates, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterCandidate represents `registerCandidate` method of NEO native contract.
|
||||||
|
func RegisterCandidate(pub interop.PublicKey) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "registerCandidate", contract.WriteStates, pub).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnregisterCandidate represents `unregisterCandidate` method of NEO native contract.
|
||||||
|
func UnregisterCandidate(pub interop.PublicKey) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "unregisterCandidate", contract.WriteStates, pub).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vote represents `vote` method of NEO native contract.
|
||||||
|
func Vote(addr interop.Hash160, pub interop.PublicKey) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "vote", contract.WriteStates, addr, pub).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnclaimedGAS represents `unclaimedGas` method of NEO native contract.
|
||||||
|
func UnclaimedGAS(addr interop.Hash160, end int) int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "unclaimedGas", contract.ReadStates, addr, end).(int)
|
||||||
|
}
|
41
pkg/interop/native/notary/notary.go
Normal file
41
pkg/interop/native/notary/notary.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package notary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash represents Notary contract hash.
|
||||||
|
const Hash = "\x0c\xcf\x26\x94\x3f\xb5\xc9\xb6\x05\xe2\x06\xd2\xa2\x75\xbe\x3e\xa6\xa4\x75\xf4"
|
||||||
|
|
||||||
|
// LockDepositUntil represents `lockDepositUntil` method of Notary native contract.
|
||||||
|
func LockDepositUntil(addr interop.Hash160, till int) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "lockDepositUntil", contract.WriteStates,
|
||||||
|
addr, till).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Withdraw represents `withdraw` method of Notary native contract.
|
||||||
|
func Withdraw(from, to interop.Hash160) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "withdraw", contract.WriteStates,
|
||||||
|
from, to).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BalanceOf represents `balanceOf` method of Notary native contract.
|
||||||
|
func BalanceOf(addr interop.Hash160) int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "balanceOf", contract.ReadStates, addr).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpirationOf represents `expirationOf` method of Notary native contract.
|
||||||
|
func ExpirationOf(addr interop.Hash160) int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "expirationOf", contract.ReadStates, addr).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMaxNotValidBeforeDelta represents `getMaxNotValidBeforeDelta` method of Notary native contract.
|
||||||
|
func GetMaxNotValidBeforeDelta() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getMaxNotValidBeforeDelta", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMaxNotValidBeforeDelta represents `setMaxNotValidBeforeDelta` method of Notary native contract.
|
||||||
|
func SetMaxNotValidBeforeDelta(value int) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setMaxNotValidBeforeDelta", contract.WriteStates, value)
|
||||||
|
}
|
16
pkg/interop/native/oracle/oracle.go
Normal file
16
pkg/interop/native/oracle/oracle.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package oracle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash represents Oracle contract hash.
|
||||||
|
const Hash = "\xee\x80\x4c\x14\x29\x68\xd4\x78\x8b\x8a\xff\x51\xda\xde\xdf\xcb\x42\xe7\xc0\x8d"
|
||||||
|
|
||||||
|
// Request represents `request` method of Oracle native contract.
|
||||||
|
func Request(url string, filter []byte, cb string, userData interface{}, gasForResponse int) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "request",
|
||||||
|
contract.WriteStates|contract.AllowNotify,
|
||||||
|
url, filter, cb, userData, gasForResponse)
|
||||||
|
}
|
84
pkg/interop/native/policy/policy.go
Normal file
84
pkg/interop/native/policy/policy.go
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash represents Policy contract hash.
|
||||||
|
const Hash = "\xf2\xe2\x08\xed\xcd\x14\x6c\xbe\xe4\x67\x6e\xdf\x79\xb7\x5e\x50\x98\xd3\xbc\x79"
|
||||||
|
|
||||||
|
// GetMaxTransactionsPerBlock represents `getMaxTransactionsPerBlock` method of Policy native contract.
|
||||||
|
func GetMaxTransactionsPerBlock() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getMaxTransactionsPerBlock", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMaxTransactionsPerBlock represents `setMaxTransactionsPerBlock` method of Policy native contract.
|
||||||
|
func SetMaxTransactionsPerBlock(value int) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setMaxTransactionsPerBlock", contract.WriteStates, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMaxBlockSize represents `getMaxBlockSize` method of Policy native contract.
|
||||||
|
func GetMaxBlockSize() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getMaxBlockSize", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMaxBlockSize represents `setMaxBlockSize` method of Policy native contract.
|
||||||
|
func SetMaxBlockSize(value int) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setMaxBlockSize", contract.WriteStates, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFeePerByte represents `getFeePerByte` method of Policy native contract.
|
||||||
|
func GetFeePerByte() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getFeePerByte", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFeePerByte represents `setFeePerByte` method of Policy native contract.
|
||||||
|
func SetFeePerByte(value int) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setFeePerByte", contract.WriteStates, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMaxBlockSystemFee represents `getMaxBlockSystemFee` method of Policy native contract.
|
||||||
|
func GetMaxBlockSystemFee() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getMaxBlockSystemFee", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMaxBlockSystemFee represents `setMaxBlockSystemFee` method of Policy native contract.
|
||||||
|
func SetMaxBlockSystemFee(value int) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setMaxBlockSystemFee", contract.WriteStates, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExecFeeFactor represents `getExecFeeFactor` method of Policy native contract.
|
||||||
|
func GetExecFeeFactor() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getExecFeeFactor", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetExecFeeFactor represents `setExecFeeFactor` method of Policy native contract.
|
||||||
|
func SetExecFeeFactor(value int) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setExecFeeFactor", contract.WriteStates, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStoragePrice represents `getStoragePrice` method of Policy native contract.
|
||||||
|
func GetStoragePrice() int {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getStoragePrice", contract.ReadStates).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStoragePrice represents `setStoragePrice` method of Policy native contract.
|
||||||
|
func SetStoragePrice(value int) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "setStoragePrice", contract.WriteStates, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBlocked represents `isBlocked` method of Policy native contract.
|
||||||
|
func IsBlocked(addr interop.Hash160) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "isBlocked", contract.ReadStates, addr).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockAccount represents `blockAccount` method of Policy native contract.
|
||||||
|
func BlockAccount(addr interop.Hash160) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "blockAccount", contract.WriteStates, addr).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnblockAccount represents `unblockAccount` method of Policy native contract.
|
||||||
|
func UnblockAccount(addr interop.Hash160) bool {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "unblockAccount", contract.WriteStates, addr).(bool)
|
||||||
|
}
|
31
pkg/interop/native/roles/roles.go
Normal file
31
pkg/interop/native/roles/roles.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package roles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash represents RoleManagement contract hash.
|
||||||
|
const Hash = "\x02\x8b\x00\x50\x70\xb6\x0d\xf1\xc8\xe2\x09\x78\x7b\x49\xce\xbb\x71\x14\x7b\x59"
|
||||||
|
|
||||||
|
// Role represents node role.
|
||||||
|
type Role byte
|
||||||
|
|
||||||
|
// Various node roles.
|
||||||
|
const (
|
||||||
|
StateValidator Role = 4
|
||||||
|
Oracle Role = 8
|
||||||
|
P2PNotary Role = 128
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetDesignatedByRole represents `getDesignatedByRole` method of RoleManagement native contract.
|
||||||
|
func GetDesignatedByRole(r Role, height uint32) []interop.PublicKey {
|
||||||
|
return contract.Call(interop.Hash160(Hash), "getDesignatedByRole",
|
||||||
|
contract.ReadStates, r, height).([]interop.PublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DesignateAsRole represents `designateAsRole` method of RoleManagement native contract.
|
||||||
|
func DesignateAsRole(r Role, pubs []interop.PublicKey) {
|
||||||
|
contract.Call(interop.Hash160(Hash), "designateAsRole",
|
||||||
|
contract.WriteStates, r, pubs)
|
||||||
|
}
|
|
@ -2,38 +2,15 @@ package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Transaction represents a NEO transaction. It's similar to Transaction class
|
|
||||||
// in Neo .net framework.
|
|
||||||
type Transaction struct {
|
|
||||||
// Hash represents the hash (256 bit BE value in a 32 byte slice) of the
|
|
||||||
// given transaction (which also is its ID).
|
|
||||||
Hash interop.Hash256
|
|
||||||
// Version represents the transaction version.
|
|
||||||
Version int
|
|
||||||
// Nonce is a random number to avoid hash collision.
|
|
||||||
Nonce int
|
|
||||||
// Sender represents the sender (160 bit BE value in a 20 byte slice) of the
|
|
||||||
// given Transaction.
|
|
||||||
Sender interop.Hash160
|
|
||||||
// SysFee represents fee to be burned.
|
|
||||||
SysFee int
|
|
||||||
// NetFee represents fee to be distributed to consensus nodes.
|
|
||||||
NetFee int
|
|
||||||
// ValidUntilBlock is the maximum blockchain height exceeding which
|
|
||||||
// transaction should fail verification.
|
|
||||||
ValidUntilBlock int
|
|
||||||
// Script represents code to run in NeoVM for this transaction.
|
|
||||||
Script []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetScriptContainer returns the transaction that initially triggered current
|
// GetScriptContainer returns the transaction that initially triggered current
|
||||||
// execution context. It never changes in a single execution, no matter how deep
|
// execution context. It never changes in a single execution, no matter how deep
|
||||||
// this execution goes. This function uses
|
// this execution goes. This function uses
|
||||||
// `System.Runtime.GetScriptContainer` syscall.
|
// `System.Runtime.GetScriptContainer` syscall.
|
||||||
func GetScriptContainer() *Transaction {
|
func GetScriptContainer() *ledger.Transaction {
|
||||||
return &Transaction{}
|
return &ledger.Transaction{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExecutingScriptHash returns script hash (160 bit in BE form represented
|
// GetExecutingScriptHash returns script hash (160 bit in BE form represented
|
||||||
|
|
Loading…
Reference in a new issue