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
|
||||
}
|
||||
|
||||
const interopPrefix = "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
|
||||
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]
|
||||
// @FIXME this could cause runtime errors.
|
||||
if ok {
|
||||
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)
|
||||
return nil
|
||||
}
|
||||
isBuiltin = isCustomBuiltin(f)
|
||||
|
||||
ast.Walk(c, n.Args[0])
|
||||
c.emitExplicitConvert(c.typeOf(n.Args[0]), typ)
|
||||
return nil
|
||||
}
|
||||
case *ast.ArrayType:
|
||||
// For now we will assume that there are only byte slice conversions.
|
||||
// E.g. []byte("foobar") or []byte(scriptHash).
|
||||
|
@ -1190,8 +1197,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
// not the assertion type.
|
||||
case *ast.TypeAssertExpr:
|
||||
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)})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
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() {
|
||||
emit.Int(c.prog.BinWriter, 2)
|
||||
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
|
||||
// of bytecode space.
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,37 @@ func TestTypeConversion(t *testing.T) {
|
|||
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) {
|
||||
src := `package foo
|
||||
type mystr string
|
||||
|
|
|
@ -239,7 +239,7 @@ func scAndVMInteropTypeFromExpr(named *types.Named) (smartcontract.ParamType, st
|
|||
name := named.Obj().Name()
|
||||
pkg := named.Obj().Pkg().Name()
|
||||
switch pkg {
|
||||
case "runtime", "contract":
|
||||
case "ledger", "contract":
|
||||
return smartcontract.ArrayType, stackitem.ArrayT // Block, Transaction, Contract
|
||||
case "interop":
|
||||
if name != "Interface" {
|
||||
|
|
|
@ -16,7 +16,7 @@ func TestCodeGen_DebugInfo(t *testing.T) {
|
|||
src := `package foo
|
||||
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/runtime"
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
|
||||
func Main(op string) bool {
|
||||
var s string
|
||||
_ = s
|
||||
|
@ -47,7 +47,7 @@ func unexportedMethod() int { return 1 }
|
|||
func MethodParams(addr interop.Hash160, h interop.Hash256,
|
||||
sig interop.Signature, pub interop.PublicKey,
|
||||
inter interop.Interface,
|
||||
ctx storage.Context, tx runtime.Transaction) bool {
|
||||
ctx storage.Context, tx ledger.Transaction) bool {
|
||||
return true
|
||||
}
|
||||
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"
|
||||
)
|
||||
|
||||
// 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.
|
||||
func TestNamesASCII(t *testing.T) {
|
||||
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 (
|
||||
"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
|
||||
// execution context. It never changes in a single execution, no matter how deep
|
||||
// this execution goes. This function uses
|
||||
// `System.Runtime.GetScriptContainer` syscall.
|
||||
func GetScriptContainer() *Transaction {
|
||||
return &Transaction{}
|
||||
func GetScriptContainer() *ledger.Transaction {
|
||||
return &ledger.Transaction{}
|
||||
}
|
||||
|
||||
// GetExecutingScriptHash returns script hash (160 bit in BE form represented
|
||||
|
|
Loading…
Reference in a new issue