Merge pull request #1647 from nspcc-dev/contractcall

Update `System.Contract.Call`
This commit is contained in:
Roman Khimov 2021-01-15 21:02:01 +03:00 committed by GitHub
commit e36e71ffbd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 360 additions and 685 deletions

View file

@ -24,6 +24,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
@ -821,7 +822,9 @@ func contractDeploy(ctx *cli.Context) error {
return cli.NewExitError(fmt.Errorf("failed to get management contract's hash: %w", err), 1) return cli.NewExitError(fmt.Errorf("failed to get management contract's hash: %w", err), 1)
} }
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(buf.BinWriter, mgmtHash, "deploy", f, manifestBytes) emit.AppCall(buf.BinWriter, mgmtHash, "deploy",
callflag.ReadStates|callflag.WriteStates|callflag.AllowNotify,
f, manifestBytes)
if buf.Err != nil { if buf.Err != nil {
return cli.NewExitError(fmt.Errorf("failed to create deployment script: %w", buf.Err), 1) return cli.NewExitError(fmt.Errorf("failed to create deployment script: %w", buf.Err), 1)
} }

Binary file not shown.

View file

@ -36,7 +36,7 @@ func Fail() {
func Update(script, manifest []byte) { func Update(script, manifest []byte) {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
mgmt := storage.Get(ctx, mgmtKey).(interop.Hash160) mgmt := storage.Get(ctx, mgmtKey).(interop.Hash160)
contract.Call(mgmt, "update", script, manifest) contract.Call(mgmt, "update", contract.All, script, manifest)
} }
// GetValue returns stored value. // GetValue returns stored value.

View file

@ -11,6 +11,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
@ -105,7 +106,7 @@ func handleCandidate(ctx *cli.Context, method string) error {
return err return err
} }
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, neoContractHash, method, acc.PrivateKey().PublicKey().Bytes()) emit.AppCall(w.BinWriter, neoContractHash, method, callflag.WriteStates, acc.PrivateKey().PublicKey().Bytes())
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{ tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{
Account: acc.Contract.ScriptHash(), Account: acc.Contract.ScriptHash(),
@ -167,7 +168,7 @@ func handleVote(ctx *cli.Context) error {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, neoContractHash, "vote", addr.BytesBE(), pubArg) emit.AppCall(w.BinWriter, neoContractHash, "vote", callflag.WriteStates, addr.BytesBE(), pubArg)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{ tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{

View file

@ -46,7 +46,7 @@ func Migrate(script []byte, manifest []byte) bool {
return false return false
} }
mgmt := storage.Get(ctx, mgmtKey).(interop.Hash160) mgmt := storage.Get(ctx, mgmtKey).(interop.Hash160)
contract.Call(mgmt, "update", script, manifest) contract.Call(mgmt, "update", contract.All, script, manifest)
runtime.Log("Contract updated.") runtime.Log("Contract updated.")
return true return true
} }
@ -58,7 +58,7 @@ func Tick() bool {
ticksLeft = ticksLeft.(int) - 1 ticksLeft = ticksLeft.(int) - 1
if ticksLeft == 0 { if ticksLeft == 0 {
runtime.Log("Fired!") runtime.Log("Fired!")
return contract.Call(runtime.GetExecutingScriptHash(), "selfDestroy").(bool) return contract.Call(runtime.GetExecutingScriptHash(), "selfDestroy", contract.All).(bool)
} }
storage.Put(ctx, ticksKey, ticksLeft) storage.Put(ctx, ticksKey, ticksLeft)
i := binary.Itoa(ticksLeft.(int), 10) i := binary.Itoa(ticksLeft.(int), 10)
@ -73,7 +73,7 @@ func SelfDestroy() bool {
return false return false
} }
mgmt := storage.Get(ctx, mgmtKey).(interop.Hash160) mgmt := storage.Get(ctx, mgmtKey).(interop.Hash160)
contract.Call(mgmt, "destroy") contract.Call(mgmt, "destroy", contract.All)
runtime.Log("Destroyed.") runtime.Log("Destroyed.")
return true return true
} }

View file

@ -13,6 +13,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
@ -28,7 +29,7 @@ var (
func NewTransferFromOwner(bc blockchainer.Blockchainer, contractHash, to util.Uint160, amount int64, func NewTransferFromOwner(bc blockchainer.Blockchainer, contractHash, to util.Uint160, amount int64,
nonce, validUntil uint32) (*transaction.Transaction, error) { nonce, validUntil uint32) (*transaction.Transaction, error) {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, contractHash, "transfer", ownerHash, to, amount, nil) emit.AppCall(w.BinWriter, contractHash, "transfer", callflag.All, ownerHash, to, amount, nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
if w.Err != nil { if w.Err != nil {
return nil, w.Err return nil, w.Err
@ -76,7 +77,7 @@ func NewDeployTx(bc blockchainer.Blockchainer, name string, sender util.Uint160,
return nil, util.Uint160{}, err return nil, util.Uint160{}, err
} }
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(buf.BinWriter, bc.ManagementContractHash(), "deploy", neb, rawManifest) emit.AppCall(buf.BinWriter, bc.ManagementContractHash(), "deploy", callflag.All, neb, rawManifest)
if buf.Err != nil { if buf.Err != nil {
return nil, util.Uint160{}, buf.Err return nil, util.Uint160{}, buf.Err
} }

View file

@ -866,14 +866,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
emit.Opcodes(c.prog.BinWriter, opcode.PACK) emit.Opcodes(c.prog.BinWriter, opcode.PACK)
numArgs -= varSize - 1 numArgs -= varSize - 1
} }
// CallFlag in CallEx interop should be the last argument c.emitReverse(numArgs)
// but this can't be reflected in signature due to varargs.
// It is first in compiler interop though, thus we just need to reverse 1 values less.
if f != nil && isSyscall(f) && f.pkg.Name() == "contract" && f.name == "CallEx" {
c.emitReverse(numArgs - 1)
} else {
c.emitReverse(numArgs)
}
} }
// Check builtin first to avoid nil pointer on funcScope! // Check builtin first to avoid nil pointer on funcScope!

View file

@ -17,7 +17,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
cinterop "github.com/nspcc-dev/neo-go/pkg/interop" cinterop "github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
@ -120,7 +120,7 @@ func spawnVM(t *testing.T, ic *interop.Context, src string) *vm.VM {
require.NoError(t, err) require.NoError(t, err)
v := core.SpawnVM(ic) v := core.SpawnVM(ic)
invokeMethod(t, testMainIdent, b, v, di) invokeMethod(t, testMainIdent, b, v, di)
v.LoadScriptWithFlags(b, smartcontract.All) v.LoadScriptWithFlags(b, callflag.All)
return v return v
} }
@ -150,7 +150,7 @@ func TestAppCall(t *testing.T) {
return a + n return a + n
} }
func CallInner() int { func CallInner() int {
return contract.Call(%s, "get42").(int) return contract.Call(%s, "get42", contract.All).(int)
}` }`
srcInner = fmt.Sprintf(srcInner, srcInner = fmt.Sprintf(srcInner,
fmt.Sprintf("%#v", cinterop.Hash160(barH.BytesBE()))) fmt.Sprintf("%#v", cinterop.Hash160(barH.BytesBE())))
@ -222,7 +222,7 @@ func TestAppCall(t *testing.T) {
func Main() []byte { func Main() []byte {
x := []byte{1, 2} x := []byte{1, 2}
y := []byte{3, 4} y := []byte{3, 4}
result := contract.Call([]byte(scriptHash), "append", x, y) result := contract.Call([]byte(scriptHash), "append", contract.All, x, y)
return result.([]byte) return result.([]byte)
} }
` `
@ -241,7 +241,7 @@ func TestAppCall(t *testing.T) {
x := []byte{1, 2} x := []byte{1, 2}
y := []byte{3, 4} y := []byte{3, 4}
var addr = []byte(` + fmt.Sprintf("%#v", string(ih.BytesBE())) + `) var addr = []byte(` + fmt.Sprintf("%#v", string(ih.BytesBE())) + `)
result := contract.Call(addr, "append", x, y) result := contract.Call(addr, "append", contract.All, x, y)
return result.([]byte) return result.([]byte)
} }
` `
@ -257,7 +257,7 @@ func TestAppCall(t *testing.T) {
import "github.com/nspcc-dev/neo-go/pkg/interop/contract" import "github.com/nspcc-dev/neo-go/pkg/interop/contract"
func Main() int { func Main() int {
var addr = []byte(` + fmt.Sprintf("%#v", string(ih.BytesBE())) + `) var addr = []byte(` + fmt.Sprintf("%#v", string(ih.BytesBE())) + `)
result := contract.Call(addr, "add3", 39) result := contract.Call(addr, "add3", contract.All, 39)
return result.(int) return result.(int)
}` }`
@ -272,7 +272,7 @@ func TestAppCall(t *testing.T) {
import ee "github.com/nspcc-dev/neo-go/pkg/interop/contract" import ee "github.com/nspcc-dev/neo-go/pkg/interop/contract"
func Main() int { func Main() int {
var addr = []byte(` + fmt.Sprintf("%#v", string(ih.BytesBE())) + `) var addr = []byte(` + fmt.Sprintf("%#v", string(ih.BytesBE())) + `)
result := ee.Call(addr, "add3", 39) result := ee.Call(addr, "add3", ee.All, 39)
return result.(int) return result.(int)
}` }`
v := spawnVM(t, ic, src) v := spawnVM(t, ic, src)
@ -288,7 +288,7 @@ func getAppCallScript(h string) string {
func Main() []byte { func Main() []byte {
x := []byte{1, 2} x := []byte{1, 2}
y := []byte{3, 4} y := []byte{3, 4}
result := contract.Call(` + h + `, "append", x, y) result := contract.Call(` + h + `, "append", contract.All, x, y)
return result.([]byte) return result.([]byte)
} }
` `
@ -298,7 +298,7 @@ func getCallExScript(h string, flags string) string {
return `package foo return `package foo
import "github.com/nspcc-dev/neo-go/pkg/interop/contract" import "github.com/nspcc-dev/neo-go/pkg/interop/contract"
func Main() int { func Main() int {
result := contract.CallEx(` + flags + `, ` + h + `, "callInner") result := contract.Call(` + h + `, "callInner", ` + flags + `)
return result.(int) return result.(int)
}` }`
} }

View file

@ -23,7 +23,6 @@ var syscalls = map[string]map[string]string{
}, },
"contract": { "contract": {
"Call": interopnames.SystemContractCall, "Call": interopnames.SystemContractCall,
"CallEx": interopnames.SystemContractCallEx,
"CreateStandardAccount": interopnames.SystemContractCreateStandardAccount, "CreateStandardAccount": interopnames.SystemContractCreateStandardAccount,
"IsStandard": interopnames.SystemContractIsStandard, "IsStandard": interopnames.SystemContractIsStandard,
"GetCallFlags": interopnames.SystemContractGetCallFlags, "GetCallFlags": interopnames.SystemContractGetCallFlags,

View file

@ -5,7 +5,7 @@ import (
"testing" "testing"
"github.com/nspcc-dev/neo-go/pkg/interop/contract" "github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -13,14 +13,14 @@ import (
// Checks that changes in `smartcontract` are reflected in compiler interop package. // Checks that changes in `smartcontract` are reflected in compiler interop package.
func TestCallFlags(t *testing.T) { func TestCallFlags(t *testing.T) {
require.EqualValues(t, contract.ReadStates, smartcontract.ReadStates) require.EqualValues(t, contract.ReadStates, callflag.ReadStates)
require.EqualValues(t, contract.WriteStates, smartcontract.WriteStates) require.EqualValues(t, contract.WriteStates, callflag.WriteStates)
require.EqualValues(t, contract.AllowCall, smartcontract.AllowCall) require.EqualValues(t, contract.AllowCall, callflag.AllowCall)
require.EqualValues(t, contract.AllowNotify, smartcontract.AllowNotify) require.EqualValues(t, contract.AllowNotify, callflag.AllowNotify)
require.EqualValues(t, contract.States, smartcontract.States) require.EqualValues(t, contract.States, callflag.States)
require.EqualValues(t, contract.ReadOnly, smartcontract.ReadOnly) require.EqualValues(t, contract.ReadOnly, callflag.ReadOnly)
require.EqualValues(t, contract.All, smartcontract.All) require.EqualValues(t, contract.All, callflag.All)
require.EqualValues(t, contract.NoneFlag, smartcontract.NoneFlag) require.EqualValues(t, contract.NoneFlag, callflag.NoneFlag)
} }
func TestStoragePutGet(t *testing.T) { func TestStoragePutGet(t *testing.T) {

View file

@ -9,7 +9,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/compiler" "github.com/nspcc-dev/neo-go/pkg/compiler"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -85,7 +85,7 @@ func invokeMethod(t *testing.T, method string, script []byte, v *vm.VM, di *comp
} }
} }
require.True(t, mainOffset >= 0) require.True(t, mainOffset >= 0)
v.LoadScriptWithFlags(script, smartcontract.All) v.LoadScriptWithFlags(script, callflag.All)
v.Jump(v.Context(), mainOffset) v.Jump(v.Context(), mainOffset)
if initOffset >= 0 { if initOffset >= 0 {
v.Call(v.Context(), initOffset) v.Call(v.Context(), initOffset)

View file

@ -20,6 +20,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "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/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
@ -54,10 +55,10 @@ func initServiceNextConsensus(t *testing.T, newAcc *wallet.Account, offset uint3
// Transfer funds to new validator. // Transfer funds to new validator.
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.GoverningTokenHash(), "transfer", emit.AppCall(w.BinWriter, bc.GoverningTokenHash(), "transfer", callflag.All,
acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(native.NEOTotalSupply), nil) acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(native.NEOTotalSupply), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.UtilityTokenHash(), "transfer", emit.AppCall(w.BinWriter, bc.UtilityTokenHash(), "transfer", callflag.All,
acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(1_000_000_000), nil) acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(1_000_000_000), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
require.NoError(t, w.Err) require.NoError(t, w.Err)
@ -74,7 +75,7 @@ func initServiceNextConsensus(t *testing.T, newAcc *wallet.Account, offset uint3
// Register new candidate. // Register new candidate.
w.Reset() w.Reset()
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.GoverningTokenHash(), "registerCandidate", newPriv.PublicKey().Bytes()) emit.AppCall(w.BinWriter, bc.GoverningTokenHash(), "registerCandidate", callflag.All, newPriv.PublicKey().Bytes())
require.NoError(t, w.Err) require.NoError(t, w.Err)
tx = transaction.New(netmode.UnitTestNet, w.Bytes(), 20_000_000) tx = transaction.New(netmode.UnitTestNet, w.Bytes(), 20_000_000)
@ -92,7 +93,7 @@ func initServiceNextConsensus(t *testing.T, newAcc *wallet.Account, offset uint3
// Vote for new candidate. // Vote for new candidate.
w.Reset() w.Reset()
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.GoverningTokenHash(), "vote", emit.AppCall(w.BinWriter, bc.GoverningTokenHash(), "vote", callflag.All,
newPriv.GetScriptHash(), newPriv.PublicKey().Bytes()) newPriv.GetScriptHash(), newPriv.PublicKey().Bytes())
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
require.NoError(t, w.Err) require.NoError(t, w.Err)

View file

@ -27,13 +27,12 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -624,7 +623,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
systemInterop := bc.newInteropContext(trigger.Application, cache, block, tx) systemInterop := bc.newInteropContext(trigger.Application, cache, block, tx)
v := systemInterop.SpawnVM() v := systemInterop.SpawnVM()
v.LoadScriptWithFlags(tx.Script, smartcontract.All) v.LoadScriptWithFlags(tx.Script, callflag.All)
v.SetPriceGetter(bc.getPrice) v.SetPriceGetter(bc.getPrice)
v.GasLimit = tx.SystemFee v.GasLimit = tx.SystemFee
@ -765,7 +764,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
func (bc *Blockchain) runPersist(script []byte, block *block.Block, cache *dao.Cached, trig trigger.Type) (*state.AppExecResult, error) { func (bc *Blockchain) runPersist(script []byte, block *block.Block, cache *dao.Cached, trig trigger.Type) (*state.AppExecResult, error) {
systemInterop := bc.newInteropContext(trig, cache, block, nil) systemInterop := bc.newInteropContext(trig, cache, block, nil)
v := systemInterop.SpawnVM() v := systemInterop.SpawnVM()
v.LoadScriptWithFlags(script, smartcontract.WriteStates|smartcontract.AllowCall) v.LoadScriptWithFlags(script, callflag.WriteStates|callflag.AllowCall)
v.SetPriceGetter(bc.getPrice) v.SetPriceGetter(bc.getPrice)
if err := v.Run(); err != nil { if err := v.Run(); err != nil {
return nil, fmt.Errorf("VM has failed: %w", err) return nil, fmt.Errorf("VM has failed: %w", err)
@ -1659,7 +1658,7 @@ func (bc *Blockchain) initVerificationVM(ic *interop.Context, hash util.Uint160,
if bc.contracts.ByHash(hash) != nil { if bc.contracts.ByHash(hash) != nil {
return ErrNativeContractWitness return ErrNativeContractWitness
} }
v.LoadScriptWithFlags(witness.VerificationScript, smartcontract.NoneFlag) v.LoadScriptWithFlags(witness.VerificationScript, callflag.NoneFlag)
} else { } else {
cs, err := ic.GetContract(hash) cs, err := ic.GetContract(hash)
if err != nil { if err != nil {
@ -1670,12 +1669,11 @@ func (bc *Blockchain) initVerificationVM(ic *interop.Context, hash util.Uint160,
return ErrInvalidVerificationContract return ErrInvalidVerificationContract
} }
initMD := cs.Manifest.ABI.GetMethod(manifest.MethodInit) initMD := cs.Manifest.ABI.GetMethod(manifest.MethodInit)
v.LoadScriptWithHash(cs.NEF.Script, hash, smartcontract.ReadStates) v.LoadScriptWithHash(cs.NEF.Script, hash, callflag.ReadStates)
v.Jump(v.Context(), md.Offset) v.Jump(v.Context(), md.Offset)
if cs.ID <= 0 { if cs.ID <= 0 {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.Opcodes(w.BinWriter, opcode.DEPTH, opcode.PACK)
emit.String(w.BinWriter, manifest.MethodVerify) emit.String(w.BinWriter, manifest.MethodVerify)
if w.Err != nil { if w.Err != nil {
return w.Err return w.Err

View file

@ -28,6 +28,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
@ -272,12 +273,12 @@ func TestVerifyTx(t *testing.T) {
if sc.Equals(gasHash) { if sc.Equals(gasHash) {
amount = 1_000_000_000 amount = 1_000_000_000
} }
emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", emit.AppCall(w.BinWriter, sc, "transfer", callflag.All,
neoOwner, a.Contract.ScriptHash(), amount, nil) neoOwner, a.Contract.ScriptHash(), amount, nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
} }
} }
emit.AppCallWithOperationAndArgs(w.BinWriter, gasHash, "transfer", emit.AppCall(w.BinWriter, gasHash, "transfer", callflag.All,
neoOwner, testchain.CommitteeScriptHash(), int64(1_000_000_000), nil) neoOwner, testchain.CommitteeScriptHash(), int64(1_000_000_000), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
require.NoError(t, w.Err) require.NoError(t, w.Err)
@ -973,7 +974,7 @@ func TestVerifyTx(t *testing.T) {
transaction.NotaryServiceFeePerKey + // fee for Notary attribute transaction.NotaryServiceFeePerKey + // fee for Notary attribute
fee.Opcode(bc.GetBaseExecFee(), // Notary verification script fee.Opcode(bc.GetBaseExecFee(), // Notary verification script
opcode.PUSHDATA1, opcode.RET, // invocation script opcode.PUSHDATA1, opcode.RET, // invocation script
opcode.DEPTH, opcode.PACK, opcode.PUSHDATA1, opcode.RET, // arguments for native verification call opcode.PUSHDATA1, opcode.RET, // arguments for native verification call
opcode.PUSHDATA1, opcode.SYSCALL, opcode.RET) + // Neo.Native.Call opcode.PUSHDATA1, opcode.SYSCALL, opcode.RET) + // Neo.Native.Call
native.NotaryVerificationPrice // Notary witness verification price native.NotaryVerificationPrice // Notary witness verification price
tx.Scripts = []transaction.Witness{ tx.Scripts = []transaction.Witness{

View file

@ -25,6 +25,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
@ -298,7 +299,7 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
// Now invoke this contract. // Now invoke this contract.
script := io.NewBufBinWriter() script := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(script.BinWriter, cHash, "putValue", "testkey", "testvalue") emit.AppCall(script.BinWriter, cHash, "putValue", callflag.All, "testkey", "testvalue")
txInv := transaction.New(testchain.Network(), script.Bytes(), 1*native.GASFactor) txInv := transaction.New(testchain.Network(), script.Bytes(), 1*native.GASFactor)
txInv.Nonce = getNextNonce() txInv.Nonce = getNextNonce()
@ -328,7 +329,7 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
require.NoError(t, bc.AddBlock(b)) require.NoError(t, bc.AddBlock(b))
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, cHash, "init") emit.AppCall(w.BinWriter, cHash, "init", callflag.All)
initTx := transaction.New(testchain.Network(), w.Bytes(), 1*native.GASFactor) initTx := transaction.New(testchain.Network(), w.Bytes(), 1*native.GASFactor)
initTx.Nonce = getNextNonce() initTx.Nonce = getNextNonce()
initTx.ValidUntilBlock = validUntilBlock initTx.ValidUntilBlock = validUntilBlock
@ -383,7 +384,7 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
func newNEP17Transfer(sc, from, to util.Uint160, amount int64, additionalArgs ...interface{}) *transaction.Transaction { func newNEP17Transfer(sc, from, to util.Uint160, amount int64, additionalArgs ...interface{}) *transaction.Transaction {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", from, to, amount, additionalArgs) emit.AppCall(w.BinWriter, sc, "transfer", callflag.All, from, to, amount, additionalArgs)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
script := w.Bytes() script := w.Bytes()
@ -430,7 +431,7 @@ func addNetworkFee(bc *Blockchain, tx *transaction.Transaction, sender *wallet.A
func prepareContractMethodInvoke(chain *Blockchain, sysfee int64, func prepareContractMethodInvoke(chain *Blockchain, sysfee int64,
hash util.Uint160, method string, args ...interface{}) (*transaction.Transaction, error) { hash util.Uint160, method string, args ...interface{}) (*transaction.Transaction, error) {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, hash, method, args...) emit.AppCall(w.BinWriter, hash, method, callflag.All, args...)
if w.Err != nil { if w.Err != nil {
return nil, w.Err return nil, w.Err
} }
@ -487,7 +488,7 @@ func invokeContractMethodBy(t *testing.T, chain *Blockchain, signer *wallet.Acco
require.Equal(t, 0, len(res[0].Stack)) require.Equal(t, 0, len(res[0].Stack))
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, hash, method, args...) emit.AppCall(w.BinWriter, hash, method, callflag.All, args...)
if w.Err != nil { if w.Err != nil {
return nil, w.Err return nil, w.Err
} }

View file

@ -1,37 +0,0 @@
package callback
import (
"errors"
"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/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
// Callback is an interface for arbitrary callbacks.
type Callback interface {
// ArgCount returns expected number of arguments.
ArgCount() int
// LoadContext loads context and arguments on stack.
LoadContext(*vm.VM, []stackitem.Item)
}
// Invoke invokes provided callback.
func Invoke(ic *interop.Context) error {
cb := ic.VM.Estack().Pop().Interop().Value().(Callback)
args := ic.VM.Estack().Pop().Array()
if cb.ArgCount() != len(args) {
return errors.New("invalid argument count")
}
cb.LoadContext(ic.VM, args)
switch t := cb.(type) {
case *MethodCallback:
id := interopnames.ToID([]byte(interopnames.SystemContractCall))
return ic.SyscallHandler(ic.VM, id)
case *SyscallCallback:
return ic.SyscallHandler(ic.VM, t.desc.ID)
default:
return nil
}
}

View file

@ -1,61 +0,0 @@
package callback
import (
"errors"
"fmt"
"strings"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"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"
)
// MethodCallback represents callback for contract method.
type MethodCallback struct {
contract *state.Contract
method *manifest.Method
}
var _ Callback = (*MethodCallback)(nil)
// ArgCount implements Callback interface.
func (s *MethodCallback) ArgCount() int {
return len(s.method.Parameters)
}
// LoadContext implements Callback interface.
func (s *MethodCallback) LoadContext(v *vm.VM, args []stackitem.Item) {
v.Estack().PushVal(args)
v.Estack().PushVal(s.method.Name)
v.Estack().PushVal(s.contract.Hash.BytesBE())
}
// CreateFromMethod creates callback for a contract method.
func CreateFromMethod(ic *interop.Context) error {
rawHash := ic.VM.Estack().Pop().Bytes()
h, err := util.Uint160DecodeBytesBE(rawHash)
if err != nil {
return err
}
cs, err := ic.GetContract(h)
if err != nil {
return fmt.Errorf("contract not found: %w", err)
}
method := string(ic.VM.Estack().Pop().Bytes())
if strings.HasPrefix(method, "_") {
return errors.New("invalid method name")
}
currCs, err := ic.GetContract(ic.VM.GetCurrentScriptHash())
if err == nil && !currCs.Manifest.CanCall(h, &cs.Manifest, method) {
return errors.New("method call is not allowed")
}
md := cs.Manifest.ABI.GetMethod(method)
ic.VM.Estack().PushVal(stackitem.NewInterop(&MethodCallback{
contract: cs,
method: md,
}))
return nil
}

View file

@ -1,42 +0,0 @@
package callback
import (
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
// PointerCallback represents callback for a pointer.
type PointerCallback struct {
paramCount int
offset int
context *vm.Context
}
var _ Callback = (*PointerCallback)(nil)
// ArgCount implements Callback interface.
func (p *PointerCallback) ArgCount() int {
return p.paramCount
}
// LoadContext implements Callback interface.
func (p *PointerCallback) LoadContext(v *vm.VM, args []stackitem.Item) {
v.Call(p.context, p.offset)
for i := len(args) - 1; i >= 0; i-- {
v.Estack().PushVal(args[i])
}
}
// Create creates callback using pointer and parameters count.
func Create(ic *interop.Context) error {
ctx := ic.VM.Estack().Pop().Item().(*vm.Context)
offset := ic.VM.Estack().Pop().Item().(*stackitem.Pointer).Position()
count := ic.VM.Estack().Pop().BigInt().Int64()
ic.VM.Estack().PushVal(stackitem.NewInterop(&PointerCallback{
paramCount: int(count),
offset: offset,
context: ctx,
}))
return nil
}

View file

@ -1,42 +0,0 @@
package callback
import (
"errors"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
// SyscallCallback represents callback for a syscall.
type SyscallCallback struct {
desc *interop.Function
}
var _ Callback = (*SyscallCallback)(nil)
// ArgCount implements Callback interface.
func (p *SyscallCallback) ArgCount() int {
return p.desc.ParamCount
}
// LoadContext implements Callback interface.
func (p *SyscallCallback) LoadContext(v *vm.VM, args []stackitem.Item) {
for i := len(args) - 1; i >= 0; i-- {
v.Estack().PushVal(args[i])
}
}
// CreateFromSyscall creates callback from syscall.
func CreateFromSyscall(ic *interop.Context) error {
id := uint32(ic.VM.Estack().Pop().BigInt().Int64())
f := ic.GetFunction(id)
if f == nil {
return errors.New("syscall not found")
}
if f.DisallowCallback {
return errors.New("syscall is not allowed to be used in a callback")
}
ic.VM.Estack().PushVal(stackitem.NewInterop(&SyscallCallback{f}))
return nil
}

View file

@ -11,7 +11,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto" "github.com/nspcc-dev/neo-go/pkg/crypto"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
@ -70,14 +70,12 @@ type Function struct {
ID uint32 ID uint32
Name string Name string
Func func(*Context) error Func func(*Context) error
// DisallowCallback is true iff syscall can't be used in a callback.
DisallowCallback bool
// ParamCount is a number of function parameters. // ParamCount is a number of function parameters.
ParamCount int ParamCount int
Price int64 Price int64
// RequiredFlags is a set of flags which must be set during script invocations. // RequiredFlags is a set of flags which must be set during script invocations.
// Default value is NoneFlag i.e. no flags are required. // Default value is NoneFlag i.e. no flags are required.
RequiredFlags smartcontract.CallFlag RequiredFlags callflag.CallFlag
} }
// Method is a signature for a native method. // Method is a signature for a native method.
@ -88,7 +86,7 @@ type MethodAndPrice struct {
Func Method Func Method
MD *manifest.Method MD *manifest.Method
Price int64 Price int64
RequiredFlags smartcontract.CallFlag RequiredFlags callflag.CallFlag
} }
// Contract is an interface for all native contracts. // Contract is an interface for all native contracts.
@ -132,7 +130,7 @@ func NewContractMD(name string) *ContractMD {
func (c *ContractMD) AddMethod(md *MethodAndPrice, desc *manifest.Method) { func (c *ContractMD) AddMethod(md *MethodAndPrice, desc *manifest.Method) {
c.Manifest.ABI.Methods = append(c.Manifest.ABI.Methods, *desc) c.Manifest.ABI.Methods = append(c.Manifest.ABI.Methods, *desc)
md.MD = desc md.MD = desc
desc.Safe = md.RequiredFlags&(smartcontract.All^smartcontract.ReadOnly) == 0 desc.Safe = md.RequiredFlags&(callflag.All^callflag.ReadOnly) == 0
c.Methods[desc.Name] = *md c.Methods[desc.Name] = *md
} }

View file

@ -8,33 +8,26 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
// Call calls a contract. // Call calls a contract with flags.
func Call(ic *interop.Context) error { func Call(ic *interop.Context) error {
h := ic.VM.Estack().Pop().Bytes() h := ic.VM.Estack().Pop().Bytes()
method := ic.VM.Estack().Pop().String() method := ic.VM.Estack().Pop().String()
args := ic.VM.Estack().Pop().Array() fs := callflag.CallFlag(int32(ic.VM.Estack().Pop().BigInt().Int64()))
return callExInternal(ic, h, method, args, smartcontract.All) if fs&^callflag.All != 0 {
}
// CallEx calls a contract with flags.
func CallEx(ic *interop.Context) error {
h := ic.VM.Estack().Pop().Bytes()
method := ic.VM.Estack().Pop().String()
args := ic.VM.Estack().Pop().Array()
flags := smartcontract.CallFlag(int32(ic.VM.Estack().Pop().BigInt().Int64()))
if flags&^smartcontract.All != 0 {
return errors.New("call flags out of range") return errors.New("call flags out of range")
} }
return callExInternal(ic, h, method, args, flags) args := ic.VM.Estack().Pop().Array()
return callInternal(ic, h, method, fs, args)
} }
func callExInternal(ic *interop.Context, h []byte, name string, args []stackitem.Item, f smartcontract.CallFlag) error { func callInternal(ic *interop.Context, h []byte, name string, f callflag.CallFlag, args []stackitem.Item) error {
u, err := util.Uint160DecodeBytesBE(h) u, err := util.Uint160DecodeBytesBE(h)
if err != nil { if err != nil {
return errors.New("invalid contract hash") return errors.New("invalid contract hash")
@ -50,8 +43,12 @@ func callExInternal(ic *interop.Context, h []byte, name string, args []stackitem
if md == nil { if md == nil {
return errors.New("method not found") return errors.New("method not found")
} }
hasReturn := md.ReturnType != smartcontract.VoidType
if !hasReturn {
ic.VM.Estack().PushVal(stackitem.Null{})
}
if md.Safe { if md.Safe {
f &^= smartcontract.WriteStates f &^= callflag.WriteStates
} else if ctx := ic.VM.Context(); ctx != nil && ctx.IsDeployed() { } else if ctx := ic.VM.Context(); ctx != nil && ctx.IsDeployed() {
curr, err := ic.GetContract(ic.VM.GetCurrentScriptHash()) curr, err := ic.GetContract(ic.VM.GetCurrentScriptHash())
if err == nil { if err == nil {
@ -60,18 +57,12 @@ func callExInternal(ic *interop.Context, h []byte, name string, args []stackitem
} }
} }
} }
return CallExInternal(ic, cs, name, args, f, vm.EnsureNotEmpty) return callExFromNative(ic, ic.VM.GetCurrentScriptHash(), cs, name, args, f, hasReturn)
}
// CallExInternal calls a contract with flags and can't be invoked directly by user.
func CallExInternal(ic *interop.Context, cs *state.Contract,
name string, args []stackitem.Item, f smartcontract.CallFlag, checkReturn vm.CheckReturnState) error {
return callExFromNative(ic, ic.VM.GetCurrentScriptHash(), cs, name, args, f, checkReturn)
} }
// callExFromNative calls a contract with flags using provided calling hash. // callExFromNative calls a contract with flags using provided calling hash.
func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contract, func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contract,
name string, args []stackitem.Item, f smartcontract.CallFlag, checkReturn vm.CheckReturnState) error { name string, args []stackitem.Item, f callflag.CallFlag, hasReturn bool) error {
md := cs.Manifest.ABI.GetMethod(name) md := cs.Manifest.ABI.GetMethod(name)
if md == nil { if md == nil {
return fmt.Errorf("method '%s' not found", name) return fmt.Errorf("method '%s' not found", name)
@ -82,7 +73,7 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
} }
ic.VM.Invocations[cs.Hash]++ ic.VM.Invocations[cs.Hash]++
ic.VM.LoadScriptWithCallingHash(caller, cs.NEF.Script, cs.Hash, ic.VM.Context().GetCallFlags()&f) ic.VM.LoadScriptWithCallingHash(caller, cs.NEF.Script, cs.Hash, ic.VM.Context().GetCallFlags()&f, true, uint16(len(args)))
var isNative bool var isNative bool
for i := range ic.Natives { for i := range ic.Natives {
if ic.Natives[i].Metadata().Hash.Equals(cs.Hash) { if ic.Natives[i].Metadata().Hash.Equals(cs.Hash) {
@ -90,17 +81,20 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
break break
} }
} }
for i := len(args) - 1; i >= 0; i-- {
ic.VM.Estack().PushVal(args[i])
}
if isNative { if isNative {
ic.VM.Estack().PushVal(args)
ic.VM.Estack().PushVal(name) ic.VM.Estack().PushVal(name)
} else { } else {
for i := len(args) - 1; i >= 0; i-- {
ic.VM.Estack().PushVal(args[i])
}
// use Jump not Call here because context was loaded in LoadScript above. // use Jump not Call here because context was loaded in LoadScript above.
ic.VM.Jump(ic.VM.Context(), md.Offset) ic.VM.Jump(ic.VM.Context(), md.Offset)
} }
ic.VM.Context().CheckReturn = checkReturn if hasReturn {
ic.VM.Context().RetCount = 1
} else {
ic.VM.Context().RetCount = 0
}
md = cs.Manifest.ABI.GetMethod(manifest.MethodInit) md = cs.Manifest.ABI.GetMethod(manifest.MethodInit)
if md != nil { if md != nil {
@ -114,9 +108,9 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
var ErrNativeCall = errors.New("error during call from native") var ErrNativeCall = errors.New("error during call from native")
// CallFromNative performs synchronous call from native contract. // CallFromNative performs synchronous call from native contract.
func CallFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contract, method string, args []stackitem.Item, checkReturn vm.CheckReturnState) error { func CallFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contract, method string, args []stackitem.Item, hasReturn bool) error {
startSize := ic.VM.Istack().Len() startSize := ic.VM.Istack().Len()
if err := callExFromNative(ic, caller, cs, method, args, smartcontract.All, checkReturn); err != nil { if err := callExFromNative(ic, caller, cs, method, args, callflag.All, hasReturn); err != nil {
return err return err
} }

View file

@ -20,7 +20,6 @@ const (
SystemCallbackCreateFromSyscall = "System.Callback.CreateFromSyscall" SystemCallbackCreateFromSyscall = "System.Callback.CreateFromSyscall"
SystemCallbackInvoke = "System.Callback.Invoke" SystemCallbackInvoke = "System.Callback.Invoke"
SystemContractCall = "System.Contract.Call" SystemContractCall = "System.Contract.Call"
SystemContractCallEx = "System.Contract.CallEx"
SystemContractCallNative = "System.Contract.CallNative" SystemContractCallNative = "System.Contract.CallNative"
SystemContractCreateStandardAccount = "System.Contract.CreateStandardAccount" SystemContractCreateStandardAccount = "System.Contract.CreateStandardAccount"
SystemContractIsStandard = "System.Contract.IsStandard" SystemContractIsStandard = "System.Contract.IsStandard"
@ -86,7 +85,6 @@ var names = []string{
SystemCallbackCreateFromSyscall, SystemCallbackCreateFromSyscall,
SystemCallbackInvoke, SystemCallbackInvoke,
SystemContractCall, SystemContractCall,
SystemContractCallEx,
SystemContractCallNative, SystemContractCallNative,
SystemContractCreateStandardAccount, SystemContractCreateStandardAccount,
SystemContractIsStandard, SystemContractIsStandard,

View file

@ -11,7 +11,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
@ -64,7 +64,7 @@ func TestGetScriptHash(t *testing.T) {
} }
ic := &interop.Context{VM: vm.New()} ic := &interop.Context{VM: vm.New()}
ic.VM.LoadScriptWithFlags(scripts[0].s, smartcontract.All) ic.VM.LoadScriptWithFlags(scripts[0].s, callflag.All)
require.NoError(t, GetEntryScriptHash(ic)) require.NoError(t, GetEntryScriptHash(ic))
checkStack(t, ic.VM, scripts[0].h.BytesBE()) checkStack(t, ic.VM, scripts[0].h.BytesBE())
require.NoError(t, GetCallingScriptHash(ic)) require.NoError(t, GetCallingScriptHash(ic))
@ -72,7 +72,7 @@ func TestGetScriptHash(t *testing.T) {
require.NoError(t, GetExecutingScriptHash(ic)) require.NoError(t, GetExecutingScriptHash(ic))
checkStack(t, ic.VM, scripts[0].h.BytesBE()) checkStack(t, ic.VM, scripts[0].h.BytesBE())
ic.VM.LoadScriptWithHash(scripts[1].s, scripts[1].h, smartcontract.All) ic.VM.LoadScriptWithHash(scripts[1].s, scripts[1].h, callflag.All)
require.NoError(t, GetEntryScriptHash(ic)) require.NoError(t, GetEntryScriptHash(ic))
checkStack(t, ic.VM, scripts[0].h.BytesBE()) checkStack(t, ic.VM, scripts[0].h.BytesBE())
require.NoError(t, GetCallingScriptHash(ic)) require.NoError(t, GetCallingScriptHash(ic))
@ -108,7 +108,7 @@ func TestLog(t *testing.T) {
t.Run("big message", func(t *testing.T) { t.Run("big message", func(t *testing.T) {
ic := &interop.Context{Log: zap.NewNop(), VM: vm.New()} ic := &interop.Context{Log: zap.NewNop(), VM: vm.New()}
ic.VM.LoadScriptWithHash([]byte{1}, h, smartcontract.All) ic.VM.LoadScriptWithHash([]byte{1}, h, callflag.All)
ic.VM.Estack().PushVal(string(make([]byte, MaxNotificationSize+1))) ic.VM.Estack().PushVal(string(make([]byte, MaxNotificationSize+1)))
require.Error(t, Log(ic)) require.Error(t, Log(ic))
}) })
@ -116,7 +116,7 @@ func TestLog(t *testing.T) {
t.Run("good", func(t *testing.T) { t.Run("good", func(t *testing.T) {
log, buf := newL(zapcore.InfoLevel) log, buf := newL(zapcore.InfoLevel)
ic := &interop.Context{Log: log, VM: vm.New()} ic := &interop.Context{Log: log, VM: vm.New()}
ic.VM.LoadScriptWithHash([]byte{1}, h, smartcontract.All) ic.VM.LoadScriptWithHash([]byte{1}, h, callflag.All)
ic.VM.Estack().PushVal("hello") ic.VM.Estack().PushVal("hello")
require.NoError(t, Log(ic)) require.NoError(t, Log(ic))
@ -137,7 +137,7 @@ func TestNotify(t *testing.T) {
h := random.Uint160() h := random.Uint160()
newIC := func(name string, args interface{}) *interop.Context { newIC := func(name string, args interface{}) *interop.Context {
ic := &interop.Context{VM: vm.New()} ic := &interop.Context{VM: vm.New()}
ic.VM.LoadScriptWithHash([]byte{1}, h, smartcontract.NoneFlag) ic.VM.LoadScriptWithHash([]byte{1}, h, callflag.NoneFlag)
ic.VM.Estack().PushVal(args) ic.VM.Estack().PushVal(args)
ic.VM.Estack().PushVal(name) ic.VM.Estack().PushVal(name)
return ic return ic

View file

@ -6,7 +6,7 @@ import (
"github.com/nspcc-dev/neo-go/internal/random" "github.com/nspcc-dev/neo-go/internal/random"
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"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/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -103,13 +103,13 @@ func TestRuntimeGetInvocationCounter(t *testing.T) {
t.Run("No invocations", func(t *testing.T) { t.Run("No invocations", func(t *testing.T) {
h1 := h h1 := h
h1[0] ^= 0xFF h1[0] ^= 0xFF
ic.VM.LoadScriptWithHash([]byte{1}, h1, smartcontract.NoneFlag) ic.VM.LoadScriptWithHash([]byte{1}, h1, callflag.NoneFlag)
// do not return an error in this case. // do not return an error in this case.
require.NoError(t, GetInvocationCounter(ic)) require.NoError(t, GetInvocationCounter(ic))
checkStack(t, ic.VM, 1) checkStack(t, ic.VM, 1)
}) })
t.Run("NonZero", func(t *testing.T) { t.Run("NonZero", func(t *testing.T) {
ic.VM.LoadScriptWithHash([]byte{1}, h, smartcontract.NoneFlag) ic.VM.LoadScriptWithHash([]byte{1}, h, callflag.NoneFlag)
require.NoError(t, GetInvocationCounter(ic)) require.NoError(t, GetInvocationCounter(ic))
checkStack(t, ic.VM, 42) checkStack(t, ic.VM, 42)
}) })

View file

@ -8,7 +8,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"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/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
) )
@ -53,7 +53,7 @@ func checkScope(ic *interop.Context, tx *transaction.Transaction, v *vm.VM, hash
if callingScriptHash.Equals(util.Uint160{}) { if callingScriptHash.Equals(util.Uint160{}) {
return false, nil return false, nil
} }
if !v.Context().GetCallFlags().Has(smartcontract.ReadStates) { if !v.Context().GetCallFlags().Has(callflag.ReadStates) {
return false, errors.New("missing ReadStates call flag") return false, errors.New("missing ReadStates call flag")
} }
cs, err := ic.GetContract(callingScriptHash) cs, err := ic.GetContract(callingScriptHash)

View file

@ -9,7 +9,6 @@ import (
"github.com/nspcc-dev/neo-go/internal/random" "github.com/nspcc-dev/neo-go/internal/random"
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/callback"
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
@ -20,10 +19,10 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -418,7 +417,7 @@ func TestStorageDelete(t *testing.T) {
defer bc.Close() defer bc.Close()
require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs)) require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs))
v.LoadScriptWithHash(cs.NEF.Script, cs.Hash, smartcontract.All) v.LoadScriptWithHash(cs.NEF.Script, cs.Hash, callflag.All)
put := func(key, value string, flag int) { put := func(key, value string, flag int) {
v.Estack().PushVal(flag) v.Estack().PushVal(flag)
v.Estack().PushVal(value) v.Estack().PushVal(value)
@ -503,13 +502,12 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
updateOff := w.Len() updateOff := w.Len()
emit.Int(w.BinWriter, 2) emit.Int(w.BinWriter, 2)
emit.Opcodes(w.BinWriter, opcode.PACK) emit.Opcodes(w.BinWriter, opcode.PACK)
emit.String(w.BinWriter, "update") emit.AppCallNoArgs(w.BinWriter, mgmtHash, "update", callflag.All)
emit.AppCall(w.BinWriter, mgmtHash) emit.Opcodes(w.BinWriter, opcode.DROP)
emit.Opcodes(w.BinWriter, opcode.RET) emit.Opcodes(w.BinWriter, opcode.RET)
destroyOff := w.Len() destroyOff := w.Len()
emit.Opcodes(w.BinWriter, opcode.NEWARRAY0) emit.AppCall(w.BinWriter, mgmtHash, "destroy", callflag.All)
emit.String(w.BinWriter, "destroy") emit.Opcodes(w.BinWriter, opcode.DROP)
emit.AppCall(w.BinWriter, mgmtHash)
emit.Opcodes(w.BinWriter, opcode.RET) emit.Opcodes(w.BinWriter, opcode.RET)
invalidStackOff := w.Len() invalidStackOff := w.Len()
emit.Opcodes(w.BinWriter, opcode.NEWARRAY0, opcode.DUP, opcode.DUP, opcode.APPEND, opcode.NEWMAP) emit.Opcodes(w.BinWriter, opcode.NEWARRAY0, opcode.DUP, opcode.DUP, opcode.APPEND, opcode.NEWMAP)
@ -655,14 +653,14 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
func loadScript(ic *interop.Context, script []byte, args ...interface{}) { func loadScript(ic *interop.Context, script []byte, args ...interface{}) {
ic.SpawnVM() ic.SpawnVM()
ic.VM.LoadScriptWithFlags(script, smartcontract.AllowCall) ic.VM.LoadScriptWithFlags(script, callflag.AllowCall)
for i := range args { for i := range args {
ic.VM.Estack().PushVal(args[i]) ic.VM.Estack().PushVal(args[i])
} }
ic.VM.GasLimit = -1 ic.VM.GasLimit = -1
} }
func loadScriptWithHashAndFlags(ic *interop.Context, script []byte, hash util.Uint160, f smartcontract.CallFlag, args ...interface{}) { func loadScriptWithHashAndFlags(ic *interop.Context, script []byte, hash util.Uint160, f callflag.CallFlag, args ...interface{}) {
ic.SpawnVM() ic.SpawnVM()
ic.VM.LoadScriptWithHash(script, hash, f) ic.VM.LoadScriptWithHash(script, hash, f)
for i := range args { for i := range args {
@ -686,6 +684,7 @@ func TestContractCall(t *testing.T) {
t.Run("Good", func(t *testing.T) { t.Run("Good", func(t *testing.T) {
loadScript(ic, currScript, 42) loadScript(ic, currScript, 42)
ic.VM.Estack().PushVal(addArgs) ic.VM.Estack().PushVal(addArgs)
ic.VM.Estack().PushVal(callflag.All)
ic.VM.Estack().PushVal("add") ic.VM.Estack().PushVal("add")
ic.VM.Estack().PushVal(h.BytesBE()) ic.VM.Estack().PushVal(h.BytesBE())
require.NoError(t, contract.Call(ic)) require.NoError(t, contract.Call(ic))
@ -697,16 +696,16 @@ func TestContractCall(t *testing.T) {
t.Run("CallExInvalidFlag", func(t *testing.T) { t.Run("CallExInvalidFlag", func(t *testing.T) {
loadScript(ic, currScript, 42) loadScript(ic, currScript, 42)
ic.VM.Estack().PushVal(byte(0xFF))
ic.VM.Estack().PushVal(addArgs) ic.VM.Estack().PushVal(addArgs)
ic.VM.Estack().PushVal(byte(0xFF))
ic.VM.Estack().PushVal("add") ic.VM.Estack().PushVal("add")
ic.VM.Estack().PushVal(h.BytesBE()) ic.VM.Estack().PushVal(h.BytesBE())
require.Error(t, contract.CallEx(ic)) require.Error(t, contract.Call(ic))
}) })
runInvalid := func(args ...interface{}) func(t *testing.T) { runInvalid := func(args ...interface{}) func(t *testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
loadScriptWithHashAndFlags(ic, currScript, h, smartcontract.All, 42) loadScriptWithHashAndFlags(ic, currScript, h, callflag.All, 42)
for i := range args { for i := range args {
ic.VM.Estack().PushVal(args[i]) ic.VM.Estack().PushVal(args[i])
} }
@ -736,6 +735,7 @@ func TestContractCall(t *testing.T) {
t.Run("Many", func(t *testing.T) { t.Run("Many", func(t *testing.T) {
loadScript(ic, currScript, 42) loadScript(ic, currScript, 42)
ic.VM.Estack().PushVal(stackitem.NewArray(nil)) ic.VM.Estack().PushVal(stackitem.NewArray(nil))
ic.VM.Estack().PushVal(callflag.All)
ic.VM.Estack().PushVal("invalidReturn") ic.VM.Estack().PushVal("invalidReturn")
ic.VM.Estack().PushVal(h.BytesBE()) ic.VM.Estack().PushVal(h.BytesBE())
require.NoError(t, contract.Call(ic)) require.NoError(t, contract.Call(ic))
@ -744,6 +744,7 @@ func TestContractCall(t *testing.T) {
t.Run("Void", func(t *testing.T) { t.Run("Void", func(t *testing.T) {
loadScript(ic, currScript, 42) loadScript(ic, currScript, 42)
ic.VM.Estack().PushVal(stackitem.NewArray(nil)) ic.VM.Estack().PushVal(stackitem.NewArray(nil))
ic.VM.Estack().PushVal(callflag.All)
ic.VM.Estack().PushVal("justReturn") ic.VM.Estack().PushVal("justReturn")
ic.VM.Estack().PushVal(h.BytesBE()) ic.VM.Estack().PushVal(h.BytesBE())
require.NoError(t, contract.Call(ic)) require.NoError(t, contract.Call(ic))
@ -757,6 +758,7 @@ func TestContractCall(t *testing.T) {
t.Run("IsolatedStack", func(t *testing.T) { t.Run("IsolatedStack", func(t *testing.T) {
loadScript(ic, currScript, 42) loadScript(ic, currScript, 42)
ic.VM.Estack().PushVal(stackitem.NewArray(nil)) ic.VM.Estack().PushVal(stackitem.NewArray(nil))
ic.VM.Estack().PushVal(callflag.All)
ic.VM.Estack().PushVal("drop") ic.VM.Estack().PushVal("drop")
ic.VM.Estack().PushVal(h.BytesBE()) ic.VM.Estack().PushVal(h.BytesBE())
require.NoError(t, contract.Call(ic)) require.NoError(t, contract.Call(ic))
@ -768,6 +770,7 @@ func TestContractCall(t *testing.T) {
loadScript(ic, currScript, 42) loadScript(ic, currScript, 42)
ic.VM.Estack().PushVal(stackitem.NewArray([]stackitem.Item{stackitem.Make(5)})) ic.VM.Estack().PushVal(stackitem.NewArray([]stackitem.Item{stackitem.Make(5)}))
ic.VM.Estack().PushVal(callflag.All)
ic.VM.Estack().PushVal("add3") ic.VM.Estack().PushVal("add3")
ic.VM.Estack().PushVal(h.BytesBE()) ic.VM.Estack().PushVal(h.BytesBE())
require.NoError(t, contract.Call(ic)) require.NoError(t, contract.Call(ic))
@ -782,153 +785,9 @@ func TestContractGetCallFlags(t *testing.T) {
v, ic, bc := createVM(t) v, ic, bc := createVM(t)
defer bc.Close() defer bc.Close()
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, util.Uint160{1, 2, 3}, smartcontract.All) v.LoadScriptWithHash([]byte{byte(opcode.RET)}, util.Uint160{1, 2, 3}, callflag.All)
require.NoError(t, contractGetCallFlags(ic)) require.NoError(t, contractGetCallFlags(ic))
require.Equal(t, int64(smartcontract.All), v.Estack().Pop().Value().(*big.Int).Int64()) require.Equal(t, int64(callflag.All), v.Estack().Pop().Value().(*big.Int).Int64())
}
func TestPointerCallback(t *testing.T) {
_, ic, bc := createVM(t)
defer bc.Close()
script := []byte{
byte(opcode.NOP), byte(opcode.INC), byte(opcode.RET),
byte(opcode.DIV), byte(opcode.RET),
}
t.Run("Good", func(t *testing.T) {
loadScript(ic, script, 2, stackitem.NewPointer(3, script))
ic.VM.Estack().PushVal(ic.VM.Context())
require.NoError(t, callback.Create(ic))
args := stackitem.NewArray([]stackitem.Item{stackitem.Make(3), stackitem.Make(12)})
ic.VM.Estack().InsertAt(vm.NewElement(args), 1)
require.NoError(t, callback.Invoke(ic))
require.NoError(t, ic.VM.Run())
require.Equal(t, 1, ic.VM.Estack().Len())
require.Equal(t, big.NewInt(5), ic.VM.Estack().Pop().Item().Value())
})
t.Run("Invalid", func(t *testing.T) {
t.Run("NotEnoughParameters", func(t *testing.T) {
loadScript(ic, script, 2, stackitem.NewPointer(3, script))
ic.VM.Estack().PushVal(ic.VM.Context())
require.NoError(t, callback.Create(ic))
args := stackitem.NewArray([]stackitem.Item{stackitem.Make(3)})
ic.VM.Estack().InsertAt(vm.NewElement(args), 1)
require.Error(t, callback.Invoke(ic))
})
})
}
func TestMethodCallback(t *testing.T) {
_, ic, bc := createVM(t)
defer bc.Close()
cs, currCs := getTestContractState(bc)
require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs))
require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, currCs))
ic.Functions = append(ic.Functions, systemInterops)
rawHash := cs.Hash.BytesBE()
t.Run("Invalid", func(t *testing.T) {
runInvalid := func(args ...interface{}) func(t *testing.T) {
return func(t *testing.T) {
loadScript(ic, currCs.NEF.Script, 42)
for i := range args {
ic.VM.Estack().PushVal(args[i])
}
require.Error(t, callback.CreateFromMethod(ic))
}
}
t.Run("Hash", runInvalid("add", rawHash[1:]))
t.Run("MissingHash", runInvalid("add", util.Uint160{}.BytesBE()))
t.Run("MissingMethod", runInvalid("sub", rawHash))
t.Run("DisallowedMethod", runInvalid("ret7", rawHash))
t.Run("Initialize", runInvalid("_initialize", rawHash))
t.Run("NotEnoughArguments", func(t *testing.T) {
loadScript(ic, currCs.NEF.Script, 42, "add", rawHash)
require.NoError(t, callback.CreateFromMethod(ic))
ic.VM.Estack().InsertAt(vm.NewElement(stackitem.NewArray([]stackitem.Item{stackitem.Make(1)})), 1)
require.Error(t, callback.Invoke(ic))
})
t.Run("CallIsNotAllowed", func(t *testing.T) {
ic.SpawnVM()
ic.VM.Load(currCs.NEF.Script)
ic.VM.Estack().PushVal("add")
ic.VM.Estack().PushVal(rawHash)
require.NoError(t, callback.CreateFromMethod(ic))
args := stackitem.NewArray([]stackitem.Item{stackitem.Make(1), stackitem.Make(5)})
ic.VM.Estack().InsertAt(vm.NewElement(args), 1)
require.Error(t, callback.Invoke(ic))
})
})
t.Run("Good", func(t *testing.T) {
loadScript(ic, currCs.NEF.Script, 42, "add", rawHash)
require.NoError(t, callback.CreateFromMethod(ic))
args := stackitem.NewArray([]stackitem.Item{stackitem.Make(1), stackitem.Make(5)})
ic.VM.Estack().InsertAt(vm.NewElement(args), 1)
require.NoError(t, callback.Invoke(ic))
require.NoError(t, ic.VM.Run())
require.Equal(t, 2, ic.VM.Estack().Len())
require.Equal(t, big.NewInt(6), ic.VM.Estack().Pop().Item().Value())
require.Equal(t, big.NewInt(42), ic.VM.Estack().Pop().Item().Value())
})
}
func TestSyscallCallback(t *testing.T) {
_, ic, bc := createVM(t)
defer bc.Close()
ic.Functions = append(ic.Functions, []interop.Function{
{
ID: 0x42,
Func: func(ic *interop.Context) error {
a := ic.VM.Estack().Pop().BigInt()
b := ic.VM.Estack().Pop().BigInt()
ic.VM.Estack().PushVal(new(big.Int).Add(a, b))
return nil
},
ParamCount: 2,
},
{
ID: 0x53,
Func: func(_ *interop.Context) error { return nil },
DisallowCallback: true,
},
})
t.Run("Good", func(t *testing.T) {
args := stackitem.NewArray([]stackitem.Item{stackitem.Make(12), stackitem.Make(30)})
loadScript(ic, []byte{byte(opcode.RET)}, args, 0x42)
require.NoError(t, callback.CreateFromSyscall(ic))
require.NoError(t, callback.Invoke(ic))
require.Equal(t, 1, ic.VM.Estack().Len())
require.Equal(t, big.NewInt(42), ic.VM.Estack().Pop().Item().Value())
})
t.Run("Invalid", func(t *testing.T) {
t.Run("InvalidParameterCount", func(t *testing.T) {
args := stackitem.NewArray([]stackitem.Item{stackitem.Make(12)})
loadScript(ic, []byte{byte(opcode.RET)}, args, 0x42)
require.NoError(t, callback.CreateFromSyscall(ic))
require.Error(t, callback.Invoke(ic))
})
t.Run("MissingSyscall", func(t *testing.T) {
loadScript(ic, []byte{byte(opcode.RET)}, stackitem.NewArray(nil), 0x43)
require.Error(t, callback.CreateFromSyscall(ic))
})
t.Run("Disallowed", func(t *testing.T) {
loadScript(ic, []byte{byte(opcode.RET)}, stackitem.NewArray(nil), 0x53)
require.Error(t, callback.CreateFromSyscall(ic))
})
})
} }
func TestRuntimeCheckWitness(t *testing.T) { func TestRuntimeCheckWitness(t *testing.T) {
@ -955,7 +814,7 @@ func TestRuntimeCheckWitness(t *testing.T) {
check(t, ic, []byte{1, 2, 3}, true) check(t, ic, []byte{1, 2, 3}, true)
}) })
t.Run("script container is not a transaction", func(t *testing.T) { t.Run("script container is not a transaction", func(t *testing.T) {
loadScriptWithHashAndFlags(ic, script, scriptHash, smartcontract.ReadStates) loadScriptWithHashAndFlags(ic, script, scriptHash, callflag.ReadStates)
check(t, ic, random.Uint160().BytesBE(), true) check(t, ic, random.Uint160().BytesBE(), true)
}) })
t.Run("check scope", func(t *testing.T) { t.Run("check scope", func(t *testing.T) {
@ -972,8 +831,8 @@ func TestRuntimeCheckWitness(t *testing.T) {
} }
ic.Container = tx ic.Container = tx
callingScriptHash := scriptHash callingScriptHash := scriptHash
loadScriptWithHashAndFlags(ic, script, callingScriptHash, smartcontract.All) loadScriptWithHashAndFlags(ic, script, callingScriptHash, callflag.All)
ic.VM.LoadScriptWithHash([]byte{0x1}, random.Uint160(), smartcontract.AllowCall) ic.VM.LoadScriptWithHash([]byte{0x1}, random.Uint160(), callflag.AllowCall)
check(t, ic, hash.BytesBE(), true) check(t, ic, hash.BytesBE(), true)
}) })
t.Run("CustomGroups, unknown contract", func(t *testing.T) { t.Run("CustomGroups, unknown contract", func(t *testing.T) {
@ -989,8 +848,8 @@ func TestRuntimeCheckWitness(t *testing.T) {
} }
ic.Container = tx ic.Container = tx
callingScriptHash := scriptHash callingScriptHash := scriptHash
loadScriptWithHashAndFlags(ic, script, callingScriptHash, smartcontract.All) loadScriptWithHashAndFlags(ic, script, callingScriptHash, callflag.All)
ic.VM.LoadScriptWithHash([]byte{0x1}, random.Uint160(), smartcontract.ReadStates) ic.VM.LoadScriptWithHash([]byte{0x1}, random.Uint160(), callflag.ReadStates)
check(t, ic, hash.BytesBE(), true) check(t, ic, hash.BytesBE(), true)
}) })
}) })
@ -999,16 +858,16 @@ func TestRuntimeCheckWitness(t *testing.T) {
t.Run("calling scripthash", func(t *testing.T) { t.Run("calling scripthash", func(t *testing.T) {
t.Run("hashed witness", func(t *testing.T) { t.Run("hashed witness", func(t *testing.T) {
callingScriptHash := scriptHash callingScriptHash := scriptHash
loadScriptWithHashAndFlags(ic, script, callingScriptHash, smartcontract.All) loadScriptWithHashAndFlags(ic, script, callingScriptHash, callflag.All)
ic.VM.LoadScriptWithHash([]byte{0x1}, random.Uint160(), smartcontract.All) ic.VM.LoadScriptWithHash([]byte{0x1}, random.Uint160(), callflag.All)
check(t, ic, callingScriptHash.BytesBE(), false, true) check(t, ic, callingScriptHash.BytesBE(), false, true)
}) })
t.Run("keyed witness", func(t *testing.T) { t.Run("keyed witness", func(t *testing.T) {
pk, err := keys.NewPrivateKey() pk, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
callingScriptHash := pk.PublicKey().GetScriptHash() callingScriptHash := pk.PublicKey().GetScriptHash()
loadScriptWithHashAndFlags(ic, script, callingScriptHash, smartcontract.All) loadScriptWithHashAndFlags(ic, script, callingScriptHash, callflag.All)
ic.VM.LoadScriptWithHash([]byte{0x1}, random.Uint160(), smartcontract.All) ic.VM.LoadScriptWithHash([]byte{0x1}, random.Uint160(), callflag.All)
check(t, ic, pk.PublicKey().Bytes(), false, true) check(t, ic, pk.PublicKey().Bytes(), false, true)
}) })
}) })
@ -1023,7 +882,7 @@ func TestRuntimeCheckWitness(t *testing.T) {
}, },
}, },
} }
loadScriptWithHashAndFlags(ic, script, scriptHash, smartcontract.ReadStates) loadScriptWithHashAndFlags(ic, script, scriptHash, callflag.ReadStates)
ic.Container = tx ic.Container = tx
check(t, ic, hash.BytesBE(), false, true) check(t, ic, hash.BytesBE(), false, true)
}) })
@ -1037,7 +896,7 @@ func TestRuntimeCheckWitness(t *testing.T) {
}, },
}, },
} }
loadScriptWithHashAndFlags(ic, script, scriptHash, smartcontract.ReadStates) loadScriptWithHashAndFlags(ic, script, scriptHash, callflag.ReadStates)
ic.Container = tx ic.Container = tx
check(t, ic, hash.BytesBE(), false, true) check(t, ic, hash.BytesBE(), false, true)
}) })
@ -1052,7 +911,7 @@ func TestRuntimeCheckWitness(t *testing.T) {
}, },
}, },
} }
loadScriptWithHashAndFlags(ic, script, scriptHash, smartcontract.ReadStates) loadScriptWithHashAndFlags(ic, script, scriptHash, callflag.ReadStates)
ic.Container = tx ic.Container = tx
check(t, ic, hash.BytesBE(), false, true) check(t, ic, hash.BytesBE(), false, true)
}) })
@ -1068,7 +927,7 @@ func TestRuntimeCheckWitness(t *testing.T) {
}, },
}, },
} }
loadScriptWithHashAndFlags(ic, script, scriptHash, smartcontract.ReadStates) loadScriptWithHashAndFlags(ic, script, scriptHash, callflag.ReadStates)
ic.Container = tx ic.Container = tx
check(t, ic, hash.BytesBE(), false, false) check(t, ic, hash.BytesBE(), false, false)
}) })
@ -1098,8 +957,8 @@ func TestRuntimeCheckWitness(t *testing.T) {
}, },
} }
require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, contractState)) require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, contractState))
loadScriptWithHashAndFlags(ic, contractScript, contractScriptHash, smartcontract.All) loadScriptWithHashAndFlags(ic, contractScript, contractScriptHash, callflag.All)
ic.VM.LoadScriptWithHash([]byte{0x1}, random.Uint160(), smartcontract.ReadStates) ic.VM.LoadScriptWithHash([]byte{0x1}, random.Uint160(), callflag.ReadStates)
ic.Container = tx ic.Container = tx
check(t, ic, targetHash.BytesBE(), false, true) check(t, ic, targetHash.BytesBE(), false, true)
}) })
@ -1114,7 +973,7 @@ func TestRuntimeCheckWitness(t *testing.T) {
}, },
}, },
} }
loadScriptWithHashAndFlags(ic, script, scriptHash, smartcontract.ReadStates) loadScriptWithHashAndFlags(ic, script, scriptHash, callflag.ReadStates)
ic.Container = tx ic.Container = tx
check(t, ic, hash.BytesBE(), false, false) check(t, ic, hash.BytesBE(), false, false)
}) })

View file

@ -10,7 +10,6 @@ package core
import ( import (
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/binary" "github.com/nspcc-dev/neo-go/pkg/core/interop/binary"
"github.com/nspcc-dev/neo-go/pkg/core/interop/callback"
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/core/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/core/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator" "github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator"
@ -19,7 +18,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop/json" "github.com/nspcc-dev/neo-go/pkg/core/interop/json"
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
) )
@ -42,42 +41,36 @@ var systemInterops = []interop.Function{
{Name: interopnames.SystemBinaryItoa, Func: binary.Itoa, Price: 1 << 12, ParamCount: 2}, {Name: interopnames.SystemBinaryItoa, Func: binary.Itoa, Price: 1 << 12, ParamCount: 2},
{Name: interopnames.SystemBinarySerialize, Func: binary.Serialize, Price: 1 << 12, ParamCount: 1}, {Name: interopnames.SystemBinarySerialize, Func: binary.Serialize, Price: 1 << 12, ParamCount: 1},
{Name: interopnames.SystemBlockchainGetBlock, Func: bcGetBlock, Price: 1 << 16, {Name: interopnames.SystemBlockchainGetBlock, Func: bcGetBlock, Price: 1 << 16,
RequiredFlags: smartcontract.ReadStates, ParamCount: 1}, RequiredFlags: callflag.ReadStates, ParamCount: 1},
{Name: interopnames.SystemBlockchainGetHeight, Func: bcGetHeight, Price: 1 << 4, {Name: interopnames.SystemBlockchainGetHeight, Func: bcGetHeight, Price: 1 << 4,
RequiredFlags: smartcontract.ReadStates}, RequiredFlags: callflag.ReadStates},
{Name: interopnames.SystemBlockchainGetTransaction, Func: bcGetTransaction, Price: 1 << 15, {Name: interopnames.SystemBlockchainGetTransaction, Func: bcGetTransaction, Price: 1 << 15,
RequiredFlags: smartcontract.ReadStates, ParamCount: 1}, RequiredFlags: callflag.ReadStates, ParamCount: 1},
{Name: interopnames.SystemBlockchainGetTransactionFromBlock, Func: bcGetTransactionFromBlock, Price: 1 << 15, {Name: interopnames.SystemBlockchainGetTransactionFromBlock, Func: bcGetTransactionFromBlock, Price: 1 << 15,
RequiredFlags: smartcontract.ReadStates, ParamCount: 2}, RequiredFlags: callflag.ReadStates, ParamCount: 2},
{Name: interopnames.SystemBlockchainGetTransactionHeight, Func: bcGetTransactionHeight, Price: 1 << 15, {Name: interopnames.SystemBlockchainGetTransactionHeight, Func: bcGetTransactionHeight, Price: 1 << 15,
RequiredFlags: smartcontract.ReadStates, ParamCount: 1}, RequiredFlags: callflag.ReadStates, ParamCount: 1},
{Name: interopnames.SystemCallbackCreate, Func: callback.Create, Price: 1 << 4, ParamCount: 3, DisallowCallback: true},
{Name: interopnames.SystemCallbackCreateFromMethod, Func: callback.CreateFromMethod, Price: 1 << 15, ParamCount: 2, DisallowCallback: true},
{Name: interopnames.SystemCallbackCreateFromSyscall, Func: callback.CreateFromSyscall, Price: 1 << 4, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemCallbackInvoke, Func: callback.Invoke, Price: 1 << 15, ParamCount: 2, DisallowCallback: true},
{Name: interopnames.SystemContractCall, Func: contract.Call, Price: 1 << 15, {Name: interopnames.SystemContractCall, Func: contract.Call, Price: 1 << 15,
RequiredFlags: smartcontract.AllowCall, ParamCount: 3, DisallowCallback: true}, RequiredFlags: callflag.AllowCall, ParamCount: 4},
{Name: interopnames.SystemContractCallEx, Func: contract.CallEx, Price: 1 << 15, {Name: interopnames.SystemContractCallNative, Func: native.Call, Price: 0, ParamCount: 1},
RequiredFlags: smartcontract.AllowCall, ParamCount: 4, DisallowCallback: true}, {Name: interopnames.SystemContractCreateStandardAccount, Func: contractCreateStandardAccount, Price: 1 << 8, ParamCount: 1},
{Name: interopnames.SystemContractCallNative, Func: native.Call, Price: 0, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemContractIsStandard, Func: contractIsStandard, Price: 1 << 10, RequiredFlags: callflag.ReadStates, ParamCount: 1},
{Name: interopnames.SystemContractCreateStandardAccount, Func: contractCreateStandardAccount, Price: 1 << 8, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemContractGetCallFlags, Func: contractGetCallFlags, Price: 1 << 10},
{Name: interopnames.SystemContractIsStandard, Func: contractIsStandard, Price: 1 << 10, RequiredFlags: smartcontract.ReadStates, ParamCount: 1}, {Name: interopnames.SystemContractNativeOnPersist, Func: native.OnPersist, Price: 0, RequiredFlags: callflag.WriteStates},
{Name: interopnames.SystemContractGetCallFlags, Func: contractGetCallFlags, Price: 1 << 10, DisallowCallback: true}, {Name: interopnames.SystemContractNativePostPersist, Func: native.PostPersist, Price: 0, RequiredFlags: callflag.WriteStates},
{Name: interopnames.SystemContractNativeOnPersist, Func: native.OnPersist, Price: 0, RequiredFlags: smartcontract.WriteStates, DisallowCallback: true}, {Name: interopnames.SystemEnumeratorConcat, Func: enumerator.Concat, Price: 1 << 4, ParamCount: 2},
{Name: interopnames.SystemContractNativePostPersist, Func: native.PostPersist, Price: 0, RequiredFlags: smartcontract.WriteStates, DisallowCallback: true}, {Name: interopnames.SystemEnumeratorCreate, Func: enumerator.Create, Price: 1 << 4, ParamCount: 1},
{Name: interopnames.SystemEnumeratorConcat, Func: enumerator.Concat, Price: 1 << 4, ParamCount: 2, DisallowCallback: true}, {Name: interopnames.SystemEnumeratorNext, Func: enumerator.Next, Price: 1 << 15, ParamCount: 1},
{Name: interopnames.SystemEnumeratorCreate, Func: enumerator.Create, Price: 1 << 4, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemEnumeratorValue, Func: enumerator.Value, Price: 1 << 4, ParamCount: 1},
{Name: interopnames.SystemEnumeratorNext, Func: enumerator.Next, Price: 1 << 15, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemIteratorConcat, Func: iterator.Concat, Price: 1 << 4, ParamCount: 2},
{Name: interopnames.SystemEnumeratorValue, Func: enumerator.Value, Price: 1 << 4, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemIteratorCreate, Func: iterator.Create, Price: 1 << 4, ParamCount: 1},
{Name: interopnames.SystemIteratorConcat, Func: iterator.Concat, Price: 1 << 4, ParamCount: 2, DisallowCallback: true}, {Name: interopnames.SystemIteratorKey, Func: iterator.Key, Price: 1 << 4, ParamCount: 1},
{Name: interopnames.SystemIteratorCreate, Func: iterator.Create, Price: 1 << 4, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemIteratorKeys, Func: iterator.Keys, Price: 1 << 4, ParamCount: 1},
{Name: interopnames.SystemIteratorKey, Func: iterator.Key, Price: 1 << 4, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemIteratorValues, Func: iterator.Values, Price: 1 << 4, ParamCount: 1},
{Name: interopnames.SystemIteratorKeys, Func: iterator.Keys, Price: 1 << 4, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemIteratorValues, Func: iterator.Values, Price: 1 << 4, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemJSONDeserialize, Func: json.Deserialize, Price: 1 << 14, ParamCount: 1}, {Name: interopnames.SystemJSONDeserialize, Func: json.Deserialize, Price: 1 << 14, ParamCount: 1},
{Name: interopnames.SystemJSONSerialize, Func: json.Serialize, Price: 1 << 12, ParamCount: 1}, {Name: interopnames.SystemJSONSerialize, Func: json.Serialize, Price: 1 << 12, ParamCount: 1},
{Name: interopnames.SystemRuntimeCheckWitness, Func: runtime.CheckWitness, Price: 1 << 10, {Name: interopnames.SystemRuntimeCheckWitness, Func: runtime.CheckWitness, Price: 1 << 10,
RequiredFlags: smartcontract.NoneFlag, ParamCount: 1}, RequiredFlags: callflag.NoneFlag, ParamCount: 1},
{Name: interopnames.SystemRuntimeGasLeft, Func: runtime.GasLeft, Price: 1 << 4}, {Name: interopnames.SystemRuntimeGasLeft, Func: runtime.GasLeft, Price: 1 << 4},
{Name: interopnames.SystemRuntimeGetCallingScriptHash, Func: runtime.GetCallingScriptHash, Price: 1 << 4}, {Name: interopnames.SystemRuntimeGetCallingScriptHash, Func: runtime.GetCallingScriptHash, Price: 1 << 4},
{Name: interopnames.SystemRuntimeGetEntryScriptHash, Func: runtime.GetEntryScriptHash, Price: 1 << 4}, {Name: interopnames.SystemRuntimeGetEntryScriptHash, Func: runtime.GetEntryScriptHash, Price: 1 << 4},
@ -85,29 +78,29 @@ var systemInterops = []interop.Function{
{Name: interopnames.SystemRuntimeGetInvocationCounter, Func: runtime.GetInvocationCounter, Price: 1 << 4}, {Name: interopnames.SystemRuntimeGetInvocationCounter, Func: runtime.GetInvocationCounter, Price: 1 << 4},
{Name: interopnames.SystemRuntimeGetNotifications, Func: runtime.GetNotifications, Price: 1 << 8, ParamCount: 1}, {Name: interopnames.SystemRuntimeGetNotifications, Func: runtime.GetNotifications, Price: 1 << 8, ParamCount: 1},
{Name: interopnames.SystemRuntimeGetScriptContainer, Func: engineGetScriptContainer, Price: 1 << 3}, {Name: interopnames.SystemRuntimeGetScriptContainer, Func: engineGetScriptContainer, Price: 1 << 3},
{Name: interopnames.SystemRuntimeGetTime, Func: runtime.GetTime, Price: 1 << 3, RequiredFlags: smartcontract.ReadStates}, {Name: interopnames.SystemRuntimeGetTime, Func: runtime.GetTime, Price: 1 << 3, RequiredFlags: callflag.ReadStates},
{Name: interopnames.SystemRuntimeGetTrigger, Func: runtime.GetTrigger, Price: 1 << 3}, {Name: interopnames.SystemRuntimeGetTrigger, Func: runtime.GetTrigger, Price: 1 << 3},
{Name: interopnames.SystemRuntimeLog, Func: runtime.Log, Price: 1 << 15, RequiredFlags: smartcontract.AllowNotify, {Name: interopnames.SystemRuntimeLog, Func: runtime.Log, Price: 1 << 15, RequiredFlags: callflag.AllowNotify,
ParamCount: 1, DisallowCallback: true}, ParamCount: 1},
{Name: interopnames.SystemRuntimeNotify, Func: runtime.Notify, Price: 1 << 15, RequiredFlags: smartcontract.AllowNotify, {Name: interopnames.SystemRuntimeNotify, Func: runtime.Notify, Price: 1 << 15, RequiredFlags: callflag.AllowNotify,
ParamCount: 2, DisallowCallback: true}, ParamCount: 2},
{Name: interopnames.SystemRuntimePlatform, Func: runtime.Platform, Price: 1 << 3}, {Name: interopnames.SystemRuntimePlatform, Func: runtime.Platform, Price: 1 << 3},
{Name: interopnames.SystemStorageDelete, Func: storageDelete, Price: 0, {Name: interopnames.SystemStorageDelete, Func: storageDelete, Price: 0,
RequiredFlags: smartcontract.WriteStates, ParamCount: 2, DisallowCallback: true}, RequiredFlags: callflag.WriteStates, ParamCount: 2},
{Name: interopnames.SystemStorageFind, Func: storageFind, Price: 1 << 15, RequiredFlags: smartcontract.ReadStates, {Name: interopnames.SystemStorageFind, Func: storageFind, Price: 1 << 15, RequiredFlags: callflag.ReadStates,
ParamCount: 2, DisallowCallback: true}, ParamCount: 2},
{Name: interopnames.SystemStorageGet, Func: storageGet, Price: 1 << 15, RequiredFlags: smartcontract.ReadStates, {Name: interopnames.SystemStorageGet, Func: storageGet, Price: 1 << 15, RequiredFlags: callflag.ReadStates,
ParamCount: 2, DisallowCallback: true}, ParamCount: 2},
{Name: interopnames.SystemStorageGetContext, Func: storageGetContext, Price: 1 << 4, {Name: interopnames.SystemStorageGetContext, Func: storageGetContext, Price: 1 << 4,
RequiredFlags: smartcontract.ReadStates, DisallowCallback: true}, RequiredFlags: callflag.ReadStates},
{Name: interopnames.SystemStorageGetReadOnlyContext, Func: storageGetReadOnlyContext, Price: 1 << 4, {Name: interopnames.SystemStorageGetReadOnlyContext, Func: storageGetReadOnlyContext, Price: 1 << 4,
RequiredFlags: smartcontract.ReadStates, DisallowCallback: true}, RequiredFlags: callflag.ReadStates},
{Name: interopnames.SystemStoragePut, Func: storagePut, Price: 0, RequiredFlags: smartcontract.WriteStates, {Name: interopnames.SystemStoragePut, Func: storagePut, Price: 0, RequiredFlags: callflag.WriteStates,
ParamCount: 3, DisallowCallback: true}, // These don't have static price in C# code. ParamCount: 3}, // These don't have static price in C# code.
{Name: interopnames.SystemStoragePutEx, Func: storagePutEx, Price: 0, RequiredFlags: smartcontract.WriteStates, {Name: interopnames.SystemStoragePutEx, Func: storagePutEx, Price: 0, RequiredFlags: callflag.WriteStates,
ParamCount: 4, DisallowCallback: true}, ParamCount: 4},
{Name: interopnames.SystemStorageAsReadOnly, Func: storageContextAsReadOnly, Price: 1 << 4, {Name: interopnames.SystemStorageAsReadOnly, Func: storageContextAsReadOnly, Price: 1 << 4,
RequiredFlags: smartcontract.ReadStates, ParamCount: 1, DisallowCallback: true}, RequiredFlags: callflag.ReadStates, ParamCount: 1},
} }
var neoInterops = []interop.Function{ var neoInterops = []interop.Function{

View file

@ -16,6 +16,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -78,13 +79,13 @@ func newDesignate(p2pSigExtensionsEnabled bool) *Designate {
desc := newDescriptor("getDesignatedByRole", smartcontract.ArrayType, desc := newDescriptor("getDesignatedByRole", smartcontract.ArrayType,
manifest.NewParameter("role", smartcontract.IntegerType), manifest.NewParameter("role", smartcontract.IntegerType),
manifest.NewParameter("index", smartcontract.IntegerType)) manifest.NewParameter("index", smartcontract.IntegerType))
md := newMethodAndPrice(s.getDesignatedByRole, 1000000, smartcontract.ReadStates) md := newMethodAndPrice(s.getDesignatedByRole, 1000000, callflag.ReadStates)
s.AddMethod(md, desc) s.AddMethod(md, desc)
desc = newDescriptor("designateAsRole", smartcontract.VoidType, desc = newDescriptor("designateAsRole", smartcontract.VoidType,
manifest.NewParameter("role", smartcontract.IntegerType), manifest.NewParameter("role", smartcontract.IntegerType),
manifest.NewParameter("nodes", smartcontract.ArrayType)) manifest.NewParameter("nodes", smartcontract.ArrayType))
md = newMethodAndPrice(s.designateAsRole, 0, smartcontract.WriteStates) md = newMethodAndPrice(s.designateAsRole, 0, callflag.WriteStates)
s.AddMethod(md, desc) s.AddMethod(md, desc)
return s return s

View file

@ -7,6 +7,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
// Call calls specified native contract method. // Call calls specified native contract method.
@ -27,7 +28,6 @@ func Call(ic *interop.Context) error {
return errors.New("it is not allowed to use Neo.Native.Call directly to call native contracts. System.Contract.Call should be used") return errors.New("it is not allowed to use Neo.Native.Call directly to call native contracts. System.Contract.Call should be used")
} }
operation := ic.VM.Estack().Pop().String() operation := ic.VM.Estack().Pop().String()
args := ic.VM.Estack().Pop().Array()
m, ok := c.Metadata().Methods[operation] m, ok := c.Metadata().Methods[operation]
if !ok { if !ok {
return fmt.Errorf("method %s not found", operation) return fmt.Errorf("method %s not found", operation)
@ -40,6 +40,10 @@ func Call(ic *interop.Context) error {
return errors.New("gas limit exceeded") return errors.New("gas limit exceeded")
} }
ctx := ic.VM.Context() ctx := ic.VM.Context()
args := make([]stackitem.Item, len(m.MD.Parameters))
for i := range args {
args[i] = ic.VM.Estack().Pop().Item()
}
result := m.Func(ic, args) result := m.Func(ic, args)
if m.MD.ReturnType != smartcontract.VoidType { if m.MD.ReturnType != smartcontract.VoidType {
ctx.Estack().PushVal(result) ctx.Estack().PushVal(result)

View file

@ -17,10 +17,10 @@ import (
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/util" "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/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
@ -65,32 +65,32 @@ func newManagement() *Management {
desc := newDescriptor("getContract", smartcontract.ArrayType, desc := newDescriptor("getContract", smartcontract.ArrayType,
manifest.NewParameter("hash", smartcontract.Hash160Type)) manifest.NewParameter("hash", smartcontract.Hash160Type))
md := newMethodAndPrice(m.getContract, 1000000, smartcontract.ReadStates) md := newMethodAndPrice(m.getContract, 1000000, callflag.ReadStates)
m.AddMethod(md, desc) m.AddMethod(md, desc)
desc = newDescriptor("deploy", smartcontract.ArrayType, desc = newDescriptor("deploy", smartcontract.ArrayType,
manifest.NewParameter("script", smartcontract.ByteArrayType), manifest.NewParameter("script", smartcontract.ByteArrayType),
manifest.NewParameter("manifest", smartcontract.ByteArrayType)) manifest.NewParameter("manifest", smartcontract.ByteArrayType))
md = newMethodAndPrice(m.deploy, 0, smartcontract.WriteStates|smartcontract.AllowNotify) md = newMethodAndPrice(m.deploy, 0, callflag.WriteStates|callflag.AllowNotify)
m.AddMethod(md, desc) m.AddMethod(md, desc)
desc = newDescriptor("update", smartcontract.VoidType, desc = newDescriptor("update", smartcontract.VoidType,
manifest.NewParameter("script", smartcontract.ByteArrayType), manifest.NewParameter("script", smartcontract.ByteArrayType),
manifest.NewParameter("manifest", smartcontract.ByteArrayType)) manifest.NewParameter("manifest", smartcontract.ByteArrayType))
md = newMethodAndPrice(m.update, 0, smartcontract.WriteStates|smartcontract.AllowNotify) md = newMethodAndPrice(m.update, 0, callflag.WriteStates|callflag.AllowNotify)
m.AddMethod(md, desc) m.AddMethod(md, desc)
desc = newDescriptor("destroy", smartcontract.VoidType) desc = newDescriptor("destroy", smartcontract.VoidType)
md = newMethodAndPrice(m.destroy, 1000000, smartcontract.WriteStates|smartcontract.AllowNotify) md = newMethodAndPrice(m.destroy, 1000000, callflag.WriteStates|callflag.AllowNotify)
m.AddMethod(md, desc) m.AddMethod(md, desc)
desc = newDescriptor("getMinimumDeploymentFee", smartcontract.IntegerType) desc = newDescriptor("getMinimumDeploymentFee", smartcontract.IntegerType)
md = newMethodAndPrice(m.getMinimumDeploymentFee, 100_0000, smartcontract.ReadStates) md = newMethodAndPrice(m.getMinimumDeploymentFee, 100_0000, callflag.ReadStates)
m.AddMethod(md, desc) m.AddMethod(md, desc)
desc = newDescriptor("setMinimumDeploymentFee", smartcontract.BoolType, desc = newDescriptor("setMinimumDeploymentFee", smartcontract.BoolType,
manifest.NewParameter("value", smartcontract.IntegerType)) manifest.NewParameter("value", smartcontract.IntegerType))
md = newMethodAndPrice(m.setMinimumDeploymentFee, 300_0000, smartcontract.WriteStates) md = newMethodAndPrice(m.setMinimumDeploymentFee, 300_0000, callflag.WriteStates)
m.AddMethod(md, desc) m.AddMethod(md, desc)
hashParam := manifest.NewParameter("Hash", smartcontract.Hash160Type) hashParam := manifest.NewParameter("Hash", smartcontract.Hash160Type)
@ -221,7 +221,7 @@ func (m *Management) deploy(ic *interop.Context, args []stackitem.Item) stackite
if err != nil { if err != nil {
panic(err) panic(err)
} }
callDeploy(ic, newcontract, false) m.callDeploy(ic, newcontract, false)
m.emitNotification(ic, contractDeployNotificationName, newcontract.Hash) m.emitNotification(ic, contractDeployNotificationName, newcontract.Hash)
return contractToStack(newcontract) return contractToStack(newcontract)
} }
@ -277,7 +277,7 @@ func (m *Management) update(ic *interop.Context, args []stackitem.Item) stackite
if err != nil { if err != nil {
panic(err) panic(err)
} }
callDeploy(ic, contract, true) m.callDeploy(ic, contract, true)
m.emitNotification(ic, contractUpdateNotificationName, contract.Hash) m.emitNotification(ic, contractUpdateNotificationName, contract.Hash)
return stackitem.Null{} return stackitem.Null{}
} }
@ -379,11 +379,11 @@ func (m *Management) setMinimumDeploymentFee(ic *interop.Context, args []stackit
return stackitem.NewBool(true) return stackitem.NewBool(true)
} }
func callDeploy(ic *interop.Context, cs *state.Contract, isUpdate bool) { func (m *Management) callDeploy(ic *interop.Context, cs *state.Contract, isUpdate bool) {
md := cs.Manifest.ABI.GetMethod(manifest.MethodDeploy) md := cs.Manifest.ABI.GetMethod(manifest.MethodDeploy)
if md != nil { if md != nil {
err := contract.CallExInternal(ic, cs, manifest.MethodDeploy, err := contract.CallFromNative(ic, m.Hash, cs, manifest.MethodDeploy,
[]stackitem.Item{stackitem.NewBool(isUpdate)}, smartcontract.All, vm.EnsureIsEmpty) []stackitem.Item{stackitem.NewBool(isUpdate)}, false)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -22,6 +22,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -110,44 +111,44 @@ func newNEO() *NEO {
desc := newDescriptor("unclaimedGas", smartcontract.IntegerType, desc := newDescriptor("unclaimedGas", smartcontract.IntegerType,
manifest.NewParameter("account", smartcontract.Hash160Type), manifest.NewParameter("account", smartcontract.Hash160Type),
manifest.NewParameter("end", smartcontract.IntegerType)) manifest.NewParameter("end", smartcontract.IntegerType))
md := newMethodAndPrice(n.unclaimedGas, 3000000, smartcontract.ReadStates) md := newMethodAndPrice(n.unclaimedGas, 3000000, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("registerCandidate", smartcontract.BoolType, desc = newDescriptor("registerCandidate", smartcontract.BoolType,
manifest.NewParameter("pubkey", smartcontract.ByteArrayType)) manifest.NewParameter("pubkey", smartcontract.ByteArrayType))
md = newMethodAndPrice(n.registerCandidate, 5000000, smartcontract.WriteStates) md = newMethodAndPrice(n.registerCandidate, 5000000, callflag.WriteStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("unregisterCandidate", smartcontract.BoolType, desc = newDescriptor("unregisterCandidate", smartcontract.BoolType,
manifest.NewParameter("pubkey", smartcontract.ByteArrayType)) manifest.NewParameter("pubkey", smartcontract.ByteArrayType))
md = newMethodAndPrice(n.unregisterCandidate, 5000000, smartcontract.WriteStates) md = newMethodAndPrice(n.unregisterCandidate, 5000000, callflag.WriteStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("vote", smartcontract.BoolType, desc = newDescriptor("vote", smartcontract.BoolType,
manifest.NewParameter("account", smartcontract.Hash160Type), manifest.NewParameter("account", smartcontract.Hash160Type),
manifest.NewParameter("pubkey", smartcontract.ByteArrayType)) manifest.NewParameter("pubkey", smartcontract.ByteArrayType))
md = newMethodAndPrice(n.vote, 5000000, smartcontract.WriteStates) md = newMethodAndPrice(n.vote, 5000000, callflag.WriteStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("getCandidates", smartcontract.ArrayType) desc = newDescriptor("getCandidates", smartcontract.ArrayType)
md = newMethodAndPrice(n.getCandidatesCall, 100000000, smartcontract.ReadStates) md = newMethodAndPrice(n.getCandidatesCall, 100000000, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("getСommittee", smartcontract.ArrayType) desc = newDescriptor("getСommittee", smartcontract.ArrayType)
md = newMethodAndPrice(n.getCommittee, 100000000, smartcontract.ReadStates) md = newMethodAndPrice(n.getCommittee, 100000000, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("getNextBlockValidators", smartcontract.ArrayType) desc = newDescriptor("getNextBlockValidators", smartcontract.ArrayType)
md = newMethodAndPrice(n.getNextBlockValidators, 100000000, smartcontract.ReadStates) md = newMethodAndPrice(n.getNextBlockValidators, 100000000, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("getGasPerBlock", smartcontract.IntegerType) desc = newDescriptor("getGasPerBlock", smartcontract.IntegerType)
md = newMethodAndPrice(n.getGASPerBlock, 100_0000, smartcontract.ReadStates) md = newMethodAndPrice(n.getGASPerBlock, 100_0000, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("setGasPerBlock", smartcontract.BoolType, desc = newDescriptor("setGasPerBlock", smartcontract.BoolType,
manifest.NewParameter("gasPerBlock", smartcontract.IntegerType)) manifest.NewParameter("gasPerBlock", smartcontract.IntegerType))
md = newMethodAndPrice(n.setGASPerBlock, 500_0000, smartcontract.WriteStates) md = newMethodAndPrice(n.setGASPerBlock, 500_0000, callflag.WriteStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
return n return n

View file

@ -12,9 +12,9 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util" "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/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
@ -47,20 +47,20 @@ func newNEP17Native(name string) *nep17TokenNative {
n.Manifest.SupportedStandards = []string{manifest.NEP17StandardName} n.Manifest.SupportedStandards = []string{manifest.NEP17StandardName}
desc := newDescriptor("symbol", smartcontract.StringType) desc := newDescriptor("symbol", smartcontract.StringType)
md := newMethodAndPrice(n.Symbol, 0, smartcontract.NoneFlag) md := newMethodAndPrice(n.Symbol, 0, callflag.NoneFlag)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("decimals", smartcontract.IntegerType) desc = newDescriptor("decimals", smartcontract.IntegerType)
md = newMethodAndPrice(n.Decimals, 0, smartcontract.NoneFlag) md = newMethodAndPrice(n.Decimals, 0, callflag.NoneFlag)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("totalSupply", smartcontract.IntegerType) desc = newDescriptor("totalSupply", smartcontract.IntegerType)
md = newMethodAndPrice(n.TotalSupply, 1000000, smartcontract.ReadStates) md = newMethodAndPrice(n.TotalSupply, 1000000, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("balanceOf", smartcontract.IntegerType, desc = newDescriptor("balanceOf", smartcontract.IntegerType,
manifest.NewParameter("account", smartcontract.Hash160Type)) manifest.NewParameter("account", smartcontract.Hash160Type))
md = newMethodAndPrice(n.balanceOf, 1000000, smartcontract.ReadStates) md = newMethodAndPrice(n.balanceOf, 1000000, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
transferParams := []manifest.Parameter{ transferParams := []manifest.Parameter{
@ -71,7 +71,7 @@ func newNEP17Native(name string) *nep17TokenNative {
desc = newDescriptor("transfer", smartcontract.BoolType, desc = newDescriptor("transfer", smartcontract.BoolType,
append(transferParams, manifest.NewParameter("data", smartcontract.AnyType))..., append(transferParams, manifest.NewParameter("data", smartcontract.AnyType))...,
) )
md = newMethodAndPrice(n.Transfer, 9000000, smartcontract.WriteStates|smartcontract.AllowCall|smartcontract.AllowNotify) md = newMethodAndPrice(n.Transfer, 9000000, callflag.WriteStates|callflag.AllowCall|callflag.AllowNotify)
n.AddMethod(md, desc) n.AddMethod(md, desc)
n.AddEvent("Transfer", transferParams...) n.AddEvent("Transfer", transferParams...)
@ -143,7 +143,7 @@ func (c *nep17TokenNative) postTransfer(ic *interop.Context, from, to *util.Uint
stackitem.NewBigInteger(amount), stackitem.NewBigInteger(amount),
data, data,
} }
if err := contract.CallFromNative(ic, c.Hash, cs, manifest.MethodOnPayment, args, vm.EnsureIsEmpty); err != nil { if err := contract.CallFromNative(ic, c.Hash, cs, manifest.MethodOnPayment, args, false); err != nil {
panic(err) panic(err)
} }
} }
@ -278,7 +278,7 @@ func newDescriptor(name string, ret smartcontract.ParamType, ps ...manifest.Para
} }
} }
func newMethodAndPrice(f interop.Method, price int64, flags smartcontract.CallFlag) *interop.MethodAndPrice { func newMethodAndPrice(f interop.Method, price int64, flags callflag.CallFlag) *interop.MethodAndPrice {
return &interop.MethodAndPrice{ return &interop.MethodAndPrice{
Func: f, Func: f,
Price: price, Price: price,

View file

@ -17,9 +17,9 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util" "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/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
@ -59,43 +59,43 @@ func newNotary() *Notary {
manifest.NewParameter("from", smartcontract.Hash160Type), manifest.NewParameter("from", smartcontract.Hash160Type),
manifest.NewParameter("amount", smartcontract.IntegerType), manifest.NewParameter("amount", smartcontract.IntegerType),
manifest.NewParameter("data", smartcontract.AnyType)) manifest.NewParameter("data", smartcontract.AnyType))
md := newMethodAndPrice(n.onPayment, 100_0000, smartcontract.WriteStates) md := newMethodAndPrice(n.onPayment, 100_0000, callflag.WriteStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("lockDepositUntil", smartcontract.BoolType, desc = newDescriptor("lockDepositUntil", smartcontract.BoolType,
manifest.NewParameter("address", smartcontract.Hash160Type), manifest.NewParameter("address", smartcontract.Hash160Type),
manifest.NewParameter("till", smartcontract.IntegerType)) manifest.NewParameter("till", smartcontract.IntegerType))
md = newMethodAndPrice(n.lockDepositUntil, 100_0000, smartcontract.WriteStates) md = newMethodAndPrice(n.lockDepositUntil, 100_0000, callflag.WriteStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("withdraw", smartcontract.BoolType, desc = newDescriptor("withdraw", smartcontract.BoolType,
manifest.NewParameter("from", smartcontract.Hash160Type), manifest.NewParameter("from", smartcontract.Hash160Type),
manifest.NewParameter("to", smartcontract.Hash160Type)) manifest.NewParameter("to", smartcontract.Hash160Type))
md = newMethodAndPrice(n.withdraw, 100_0000, smartcontract.WriteStates) md = newMethodAndPrice(n.withdraw, 100_0000, callflag.WriteStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("balanceOf", smartcontract.IntegerType, desc = newDescriptor("balanceOf", smartcontract.IntegerType,
manifest.NewParameter("addr", smartcontract.Hash160Type)) manifest.NewParameter("addr", smartcontract.Hash160Type))
md = newMethodAndPrice(n.balanceOf, 100_0000, smartcontract.ReadStates) md = newMethodAndPrice(n.balanceOf, 100_0000, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("expirationOf", smartcontract.IntegerType, desc = newDescriptor("expirationOf", smartcontract.IntegerType,
manifest.NewParameter("addr", smartcontract.Hash160Type)) manifest.NewParameter("addr", smartcontract.Hash160Type))
md = newMethodAndPrice(n.expirationOf, 100_0000, smartcontract.ReadStates) md = newMethodAndPrice(n.expirationOf, 100_0000, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("verify", smartcontract.BoolType, desc = newDescriptor("verify", smartcontract.BoolType,
manifest.NewParameter("signature", smartcontract.SignatureType)) manifest.NewParameter("signature", smartcontract.SignatureType))
md = newMethodAndPrice(n.verify, 100_0000, smartcontract.ReadStates) md = newMethodAndPrice(n.verify, 100_0000, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("getMaxNotValidBeforeDelta", smartcontract.IntegerType) desc = newDescriptor("getMaxNotValidBeforeDelta", smartcontract.IntegerType)
md = newMethodAndPrice(n.getMaxNotValidBeforeDelta, 100_0000, smartcontract.ReadStates) md = newMethodAndPrice(n.getMaxNotValidBeforeDelta, 100_0000, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("setMaxNotValidBeforeDelta", smartcontract.BoolType, desc = newDescriptor("setMaxNotValidBeforeDelta", smartcontract.BoolType,
manifest.NewParameter("value", smartcontract.IntegerType)) manifest.NewParameter("value", smartcontract.IntegerType))
md = newMethodAndPrice(n.setMaxNotValidBeforeDelta, 300_0000, smartcontract.WriteStates) md = newMethodAndPrice(n.setMaxNotValidBeforeDelta, 300_0000, callflag.WriteStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
return n return n
@ -276,7 +276,7 @@ func (n *Notary) withdraw(ic *interop.Context, args []stackitem.Item) stackitem.
panic(fmt.Errorf("failed to get GAS contract state: %w", err)) panic(fmt.Errorf("failed to get GAS contract state: %w", err))
} }
transferArgs := []stackitem.Item{stackitem.NewByteArray(n.Hash.BytesBE()), stackitem.NewByteArray(to.BytesBE()), stackitem.NewBigInteger(deposit.Amount), stackitem.Null{}} transferArgs := []stackitem.Item{stackitem.NewByteArray(n.Hash.BytesBE()), stackitem.NewByteArray(to.BytesBE()), stackitem.NewBigInteger(deposit.Amount), stackitem.Null{}}
err = contract.CallFromNative(ic, n.Hash, cs, "transfer", transferArgs, vm.EnsureNotEmpty) err = contract.CallFromNative(ic, n.Hash, cs, "transfer", transferArgs, true)
if err != nil { if err != nil {
panic(fmt.Errorf("failed to transfer GAS from Notary account: %w", err)) panic(fmt.Errorf("failed to transfer GAS from Notary account: %w", err))
} }

View file

@ -20,9 +20,9 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -56,6 +56,7 @@ func init() {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.Int(w.BinWriter, 0) emit.Int(w.BinWriter, 0)
emit.Opcodes(w.BinWriter, opcode.NEWARRAY) emit.Opcodes(w.BinWriter, opcode.NEWARRAY)
emit.Int(w.BinWriter, int64(callflag.All))
emit.String(w.BinWriter, "finish") emit.String(w.BinWriter, "finish")
emit.Bytes(w.BinWriter, h.BytesBE()) emit.Bytes(w.BinWriter, h.BytesBE())
emit.Syscall(w.BinWriter, interopnames.SystemContractCall) emit.Syscall(w.BinWriter, interopnames.SystemContractCall)
@ -94,15 +95,15 @@ func newOracle() *Oracle {
manifest.NewParameter("callback", smartcontract.StringType), manifest.NewParameter("callback", smartcontract.StringType),
manifest.NewParameter("userData", smartcontract.AnyType), manifest.NewParameter("userData", smartcontract.AnyType),
manifest.NewParameter("gasForResponse", smartcontract.IntegerType)) manifest.NewParameter("gasForResponse", smartcontract.IntegerType))
md := newMethodAndPrice(o.request, oracleRequestPrice, smartcontract.WriteStates|smartcontract.AllowNotify) md := newMethodAndPrice(o.request, oracleRequestPrice, callflag.WriteStates|callflag.AllowNotify)
o.AddMethod(md, desc) o.AddMethod(md, desc)
desc = newDescriptor("finish", smartcontract.VoidType) desc = newDescriptor("finish", smartcontract.VoidType)
md = newMethodAndPrice(o.finish, 0, smartcontract.WriteStates|smartcontract.AllowCall|smartcontract.AllowNotify) md = newMethodAndPrice(o.finish, 0, callflag.WriteStates|callflag.AllowCall|callflag.AllowNotify)
o.AddMethod(md, desc) o.AddMethod(md, desc)
desc = newDescriptor("verify", smartcontract.BoolType) desc = newDescriptor("verify", smartcontract.BoolType)
md = newMethodAndPrice(o.verify, 100_0000, smartcontract.NoneFlag) md = newMethodAndPrice(o.verify, 100_0000, callflag.NoneFlag)
o.AddMethod(md, desc) o.AddMethod(md, desc)
o.AddEvent("OracleRequest", manifest.NewParameter("Id", smartcontract.IntegerType), o.AddEvent("OracleRequest", manifest.NewParameter("Id", smartcontract.IntegerType),
@ -238,7 +239,7 @@ func (o *Oracle) FinishInternal(ic *interop.Context) error {
if err != nil { if err != nil {
return err return err
} }
return contract.CallFromNative(ic, o.Hash, cs, req.CallbackMethod, args, vm.EnsureIsEmpty) return contract.CallFromNative(ic, o.Hash, cs, req.CallbackMethod, args, false)
} }
func (o *Oracle) request(ic *interop.Context, args []stackitem.Item) stackitem.Item { func (o *Oracle) request(ic *interop.Context, args []stackitem.Item) stackitem.Item {

View file

@ -14,6 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/network/payload" "github.com/nspcc-dev/neo-go/pkg/network/payload"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -85,72 +86,72 @@ func newPolicy() *Policy {
p.ContractID = policyContractID p.ContractID = policyContractID
desc := newDescriptor("getMaxTransactionsPerBlock", smartcontract.IntegerType) desc := newDescriptor("getMaxTransactionsPerBlock", smartcontract.IntegerType)
md := newMethodAndPrice(p.getMaxTransactionsPerBlock, 1000000, smartcontract.ReadStates) md := newMethodAndPrice(p.getMaxTransactionsPerBlock, 1000000, callflag.ReadStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("getMaxBlockSize", smartcontract.IntegerType) desc = newDescriptor("getMaxBlockSize", smartcontract.IntegerType)
md = newMethodAndPrice(p.getMaxBlockSize, 1000000, smartcontract.ReadStates) md = newMethodAndPrice(p.getMaxBlockSize, 1000000, callflag.ReadStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("getFeePerByte", smartcontract.IntegerType) desc = newDescriptor("getFeePerByte", smartcontract.IntegerType)
md = newMethodAndPrice(p.getFeePerByte, 1000000, smartcontract.ReadStates) md = newMethodAndPrice(p.getFeePerByte, 1000000, callflag.ReadStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("isBlocked", smartcontract.BoolType, desc = newDescriptor("isBlocked", smartcontract.BoolType,
manifest.NewParameter("account", smartcontract.Hash160Type)) manifest.NewParameter("account", smartcontract.Hash160Type))
md = newMethodAndPrice(p.isBlocked, 1000000, smartcontract.ReadStates) md = newMethodAndPrice(p.isBlocked, 1000000, callflag.ReadStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("getMaxBlockSystemFee", smartcontract.IntegerType) desc = newDescriptor("getMaxBlockSystemFee", smartcontract.IntegerType)
md = newMethodAndPrice(p.getMaxBlockSystemFee, 1000000, smartcontract.ReadStates) md = newMethodAndPrice(p.getMaxBlockSystemFee, 1000000, callflag.ReadStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("getExecFeeFactor", smartcontract.IntegerType) desc = newDescriptor("getExecFeeFactor", smartcontract.IntegerType)
md = newMethodAndPrice(p.getExecFeeFactor, 1000000, smartcontract.ReadStates) md = newMethodAndPrice(p.getExecFeeFactor, 1000000, callflag.ReadStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("setExecFeeFactor", smartcontract.BoolType, desc = newDescriptor("setExecFeeFactor", smartcontract.BoolType,
manifest.NewParameter("value", smartcontract.IntegerType)) manifest.NewParameter("value", smartcontract.IntegerType))
md = newMethodAndPrice(p.setExecFeeFactor, 3000000, smartcontract.WriteStates) md = newMethodAndPrice(p.setExecFeeFactor, 3000000, callflag.WriteStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("getStoragePrice", smartcontract.IntegerType) desc = newDescriptor("getStoragePrice", smartcontract.IntegerType)
md = newMethodAndPrice(p.getStoragePrice, 1000000, smartcontract.ReadStates) md = newMethodAndPrice(p.getStoragePrice, 1000000, callflag.ReadStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("setStoragePrice", smartcontract.BoolType, desc = newDescriptor("setStoragePrice", smartcontract.BoolType,
manifest.NewParameter("value", smartcontract.IntegerType)) manifest.NewParameter("value", smartcontract.IntegerType))
md = newMethodAndPrice(p.setStoragePrice, 3000000, smartcontract.WriteStates) md = newMethodAndPrice(p.setStoragePrice, 3000000, callflag.WriteStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("setMaxBlockSize", smartcontract.BoolType, desc = newDescriptor("setMaxBlockSize", smartcontract.BoolType,
manifest.NewParameter("value", smartcontract.IntegerType)) manifest.NewParameter("value", smartcontract.IntegerType))
md = newMethodAndPrice(p.setMaxBlockSize, 3000000, smartcontract.WriteStates) md = newMethodAndPrice(p.setMaxBlockSize, 3000000, callflag.WriteStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("setMaxTransactionsPerBlock", smartcontract.BoolType, desc = newDescriptor("setMaxTransactionsPerBlock", smartcontract.BoolType,
manifest.NewParameter("value", smartcontract.IntegerType)) manifest.NewParameter("value", smartcontract.IntegerType))
md = newMethodAndPrice(p.setMaxTransactionsPerBlock, 3000000, smartcontract.WriteStates) md = newMethodAndPrice(p.setMaxTransactionsPerBlock, 3000000, callflag.WriteStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("setFeePerByte", smartcontract.BoolType, desc = newDescriptor("setFeePerByte", smartcontract.BoolType,
manifest.NewParameter("value", smartcontract.IntegerType)) manifest.NewParameter("value", smartcontract.IntegerType))
md = newMethodAndPrice(p.setFeePerByte, 3000000, smartcontract.WriteStates) md = newMethodAndPrice(p.setFeePerByte, 3000000, callflag.WriteStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("setMaxBlockSystemFee", smartcontract.BoolType, desc = newDescriptor("setMaxBlockSystemFee", smartcontract.BoolType,
manifest.NewParameter("value", smartcontract.IntegerType)) manifest.NewParameter("value", smartcontract.IntegerType))
md = newMethodAndPrice(p.setMaxBlockSystemFee, 3000000, smartcontract.WriteStates) md = newMethodAndPrice(p.setMaxBlockSystemFee, 3000000, callflag.WriteStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("blockAccount", smartcontract.BoolType, desc = newDescriptor("blockAccount", smartcontract.BoolType,
manifest.NewParameter("account", smartcontract.Hash160Type)) manifest.NewParameter("account", smartcontract.Hash160Type))
md = newMethodAndPrice(p.blockAccount, 3000000, smartcontract.WriteStates) md = newMethodAndPrice(p.blockAccount, 3000000, callflag.WriteStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("unblockAccount", smartcontract.BoolType, desc = newDescriptor("unblockAccount", smartcontract.BoolType,
manifest.NewParameter("account", smartcontract.Hash160Type)) manifest.NewParameter("account", smartcontract.Hash160Type))
md = newMethodAndPrice(p.unblockAccount, 3000000, smartcontract.WriteStates) md = newMethodAndPrice(p.unblockAccount, 3000000, callflag.WriteStates)
p.AddMethod(md, desc) p.AddMethod(md, desc)
return p return p

View file

@ -14,6 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
@ -75,7 +76,7 @@ func newTestNative() *testNative {
md := &interop.MethodAndPrice{ md := &interop.MethodAndPrice{
Func: tn.sum, Func: tn.sum,
Price: testSumPrice, Price: testSumPrice,
RequiredFlags: smartcontract.NoneFlag, RequiredFlags: callflag.NoneFlag,
} }
tn.meta.AddMethod(md, desc) tn.meta.AddMethod(md, desc)
@ -92,7 +93,7 @@ func newTestNative() *testNative {
md = &interop.MethodAndPrice{ md = &interop.MethodAndPrice{
Func: tn.callOtherContractNoReturn, Func: tn.callOtherContractNoReturn,
Price: testSumPrice, Price: testSumPrice,
RequiredFlags: smartcontract.NoneFlag} RequiredFlags: callflag.NoneFlag}
tn.meta.AddMethod(md, desc) tn.meta.AddMethod(md, desc)
desc = &manifest.Method{ desc = &manifest.Method{
@ -107,7 +108,7 @@ func newTestNative() *testNative {
md = &interop.MethodAndPrice{ md = &interop.MethodAndPrice{
Func: tn.callOtherContractWithReturn, Func: tn.callOtherContractWithReturn,
Price: testSumPrice, Price: testSumPrice,
RequiredFlags: smartcontract.NoneFlag} RequiredFlags: callflag.NoneFlag}
tn.meta.AddMethod(md, desc) tn.meta.AddMethod(md, desc)
return tn return tn
@ -137,7 +138,7 @@ func toUint160(item stackitem.Item) util.Uint160 {
return u return u
} }
func (tn *testNative) call(ic *interop.Context, args []stackitem.Item, checkReturn vm.CheckReturnState) { func (tn *testNative) call(ic *interop.Context, args []stackitem.Item, hasReturn bool) {
cs, err := ic.GetContract(toUint160(args[0])) cs, err := ic.GetContract(toUint160(args[0]))
if err != nil { if err != nil {
panic(err) panic(err)
@ -146,19 +147,19 @@ func (tn *testNative) call(ic *interop.Context, args []stackitem.Item, checkRetu
if err != nil { if err != nil {
panic(err) panic(err)
} }
err = contract.CallFromNative(ic, tn.meta.Hash, cs, string(bs), args[2].Value().([]stackitem.Item), checkReturn) err = contract.CallFromNative(ic, tn.meta.Hash, cs, string(bs), args[2].Value().([]stackitem.Item), hasReturn)
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }
func (tn *testNative) callOtherContractNoReturn(ic *interop.Context, args []stackitem.Item) stackitem.Item { func (tn *testNative) callOtherContractNoReturn(ic *interop.Context, args []stackitem.Item) stackitem.Item {
tn.call(ic, args, vm.EnsureIsEmpty) tn.call(ic, args, false)
return stackitem.Null{} return stackitem.Null{}
} }
func (tn *testNative) callOtherContractWithReturn(ic *interop.Context, args []stackitem.Item) stackitem.Item { func (tn *testNative) callOtherContractWithReturn(ic *interop.Context, args []stackitem.Item) stackitem.Item {
tn.call(ic, args, vm.EnsureNotEmpty) tn.call(ic, args, true)
bi := ic.VM.Estack().Pop().BigInt() bi := ic.VM.Estack().Pop().BigInt()
return stackitem.Make(bi.Add(bi, big.NewInt(1))) return stackitem.Make(bi.Add(bi, big.NewInt(1)))
} }
@ -183,6 +184,7 @@ func TestNativeContract_Invoke(t *testing.T) {
price += 3 * fee.Opcode(chain.GetBaseExecFee(), opcode.PUSHINT8, opcode.PUSHDATA1) price += 3 * fee.Opcode(chain.GetBaseExecFee(), opcode.PUSHINT8, opcode.PUSHDATA1)
price += 2 * fee.Opcode(chain.GetBaseExecFee(), opcode.SYSCALL) price += 2 * fee.Opcode(chain.GetBaseExecFee(), opcode.SYSCALL)
price += fee.Opcode(chain.GetBaseExecFee(), opcode.PACK) price += fee.Opcode(chain.GetBaseExecFee(), opcode.PACK)
price += fee.Opcode(chain.GetBaseExecFee(), opcode.PUSHINT8)
res, err := invokeContractMethod(chain, price, tn.Metadata().Hash, "sum", int64(14), int64(28)) res, err := invokeContractMethod(chain, price, tn.Metadata().Hash, "sum", int64(14), int64(28))
require.NoError(t, err) require.NoError(t, err)
checkResult(t, res, stackitem.Make(42)) checkResult(t, res, stackitem.Make(42))
@ -220,8 +222,9 @@ func TestNativeContract_InvokeInternal(t *testing.T) {
v := ic.SpawnVM() v := ic.SpawnVM()
t.Run("fail, bad current script hash", func(t *testing.T) { t.Run("fail, bad current script hash", func(t *testing.T) {
v.LoadScriptWithHash([]byte{1}, util.Uint160{1, 2, 3}, smartcontract.All) v.LoadScriptWithHash([]byte{1}, util.Uint160{1, 2, 3}, callflag.All)
v.Estack().PushVal(stackitem.NewArray([]stackitem.Item{stackitem.NewBigInteger(big.NewInt(14)), stackitem.NewBigInteger(big.NewInt(28))})) v.Estack().PushVal(14)
v.Estack().PushVal(28)
v.Estack().PushVal("sum") v.Estack().PushVal("sum")
v.Estack().PushVal(tn.Metadata().Name) v.Estack().PushVal(tn.Metadata().Name)
@ -230,8 +233,9 @@ func TestNativeContract_InvokeInternal(t *testing.T) {
}) })
t.Run("success", func(t *testing.T) { t.Run("success", func(t *testing.T) {
v.LoadScriptWithHash([]byte{1}, tn.Metadata().Hash, smartcontract.All) v.LoadScriptWithHash([]byte{1}, tn.Metadata().Hash, callflag.All)
v.Estack().PushVal(stackitem.NewArray([]stackitem.Item{stackitem.NewBigInteger(big.NewInt(14)), stackitem.NewBigInteger(big.NewInt(28))})) v.Estack().PushVal(14)
v.Estack().PushVal(28)
v.Estack().PushVal("sum") v.Estack().PushVal("sum")
v.Estack().PushVal(tn.Metadata().Name) v.Estack().PushVal(tn.Metadata().Name)
@ -272,6 +276,7 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) {
res, err := invokeContractMethod(chain, testSumPrice*4+10000, tn.Metadata().Hash, "callOtherContractNoReturn", cs.Hash, "justReturn", []interface{}{}) res, err := invokeContractMethod(chain, testSumPrice*4+10000, tn.Metadata().Hash, "callOtherContractNoReturn", cs.Hash, "justReturn", []interface{}{})
require.NoError(t, err) require.NoError(t, err)
drainTN(t) drainTN(t)
require.Equal(t, vm.HaltState, res.VMState, res.FaultException)
checkResult(t, res, stackitem.Null{}) // simple call is done with EnsureNotEmpty checkResult(t, res, stackitem.Null{}) // simple call is done with EnsureNotEmpty
}) })
t.Run("non-native, with return", func(t *testing.T) { t.Run("non-native, with return", func(t *testing.T) {

View file

@ -11,6 +11,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
@ -29,8 +30,7 @@ func (bc *Blockchain) setNodesByRole(t *testing.T, ok bool, r native.Role, nodes
emit.Int(w.BinWriter, int64(r)) emit.Int(w.BinWriter, int64(r))
emit.Int(w.BinWriter, 2) emit.Int(w.BinWriter, 2)
emit.Opcodes(w.BinWriter, opcode.PACK) emit.Opcodes(w.BinWriter, opcode.PACK)
emit.String(w.BinWriter, "designateAsRole") emit.AppCallNoArgs(w.BinWriter, bc.contracts.Designate.Hash, "designateAsRole", callflag.All)
emit.AppCall(w.BinWriter, bc.contracts.Designate.Hash)
require.NoError(t, w.Err) require.NoError(t, w.Err)
tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 0) tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 0)
tx.NetworkFee = 10_000_000 tx.NetworkFee = 10_000_000

View file

@ -11,6 +11,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
@ -75,11 +76,11 @@ func TestNEO_Vote(t *testing.T) {
to := accs[i].Contract.ScriptHash() to := accs[i].Contract.ScriptHash()
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.NEO.Hash, "transfer", emit.AppCall(w.BinWriter, bc.contracts.NEO.Hash, "transfer", callflag.All,
neoOwner.BytesBE(), to.BytesBE(), neoOwner.BytesBE(), to.BytesBE(),
big.NewInt(int64(sz-i)*1000000).Int64(), nil) big.NewInt(int64(sz-i)*1000000).Int64(), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.GAS.Hash, "transfer", emit.AppCall(w.BinWriter, bc.contracts.GAS.Hash, "transfer", callflag.All,
neoOwner.BytesBE(), to.BytesBE(), neoOwner.BytesBE(), to.BytesBE(),
int64(1_000_000_000), nil) int64(1_000_000_000), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
@ -141,7 +142,7 @@ func TestNEO_Vote(t *testing.T) {
h := accs[i].PrivateKey().GetScriptHash() h := accs[i].PrivateKey().GetScriptHash()
gasBalance[i] = bc.GetUtilityTokenBalance(h) gasBalance[i] = bc.GetUtilityTokenBalance(h)
neoBalance[i], _ = bc.GetGoverningTokenBalance(h) neoBalance[i], _ = bc.GetGoverningTokenBalance(h)
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.NEO.Hash, "transfer", emit.AppCall(w.BinWriter, bc.contracts.NEO.Hash, "transfer", callflag.All,
h.BytesBE(), h.BytesBE(), int64(1), nil) h.BytesBE(), h.BytesBE(), int64(1), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
require.NoError(t, w.Err) require.NoError(t, w.Err)

View file

@ -11,6 +11,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
@ -174,7 +175,8 @@ func TestNotaryContractPipeline(t *testing.T) {
// `withdraw`: bad witness // `withdraw`: bad witness
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, notaryHash, "withdraw", testchain.MultisigScriptHash(), acc.PrivateKey().PublicKey().GetScriptHash()) emit.AppCall(w.BinWriter, notaryHash, "withdraw", callflag.All,
testchain.MultisigScriptHash(), acc.PrivateKey().PublicKey().GetScriptHash())
require.NoError(t, w.Err) require.NoError(t, w.Err)
script := w.Bytes() script := w.Bytes()
withdrawTx := transaction.New(chain.GetConfig().Magic, script, 10000000) withdrawTx := transaction.New(chain.GetConfig().Magic, script, 10000000)

View file

@ -16,6 +16,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
@ -32,9 +33,11 @@ func getOracleContractState(h util.Uint160) *state.Contract {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.Int(w.BinWriter, 5) emit.Int(w.BinWriter, 5)
emit.Opcodes(w.BinWriter, opcode.PACK) emit.Opcodes(w.BinWriter, opcode.PACK)
emit.Int(w.BinWriter, int64(callflag.All))
emit.String(w.BinWriter, "request") emit.String(w.BinWriter, "request")
emit.Bytes(w.BinWriter, h.BytesBE()) emit.Bytes(w.BinWriter, h.BytesBE())
emit.Syscall(w.BinWriter, interopnames.SystemContractCall) emit.Syscall(w.BinWriter, interopnames.SystemContractCall)
emit.Opcodes(w.BinWriter, opcode.DROP)
emit.Opcodes(w.BinWriter, opcode.RET) emit.Opcodes(w.BinWriter, opcode.RET)
// `handle` method aborts if len(userData) == 2 // `handle` method aborts if len(userData) == 2
@ -171,7 +174,7 @@ func TestOracle_Request(t *testing.T) {
// We need to ensure that callback is called thus, executing full script is necessary. // We need to ensure that callback is called thus, executing full script is necessary.
resp.ID = 1 resp.ID = 1
ic.VM.LoadScriptWithFlags(tx.Script, smartcontract.All) ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
require.NoError(t, ic.VM.Run()) require.NoError(t, ic.VM.Run())
si := ic.DAO.GetStorageItem(cs.ID, []byte("lastOracleResponse")) si := ic.DAO.GetStorageItem(cs.ID, []byte("lastOracleResponse"))
@ -211,7 +214,7 @@ func TestOracle_Request(t *testing.T) {
}} }}
ic := bc.newInteropContext(trigger.Application, bc.dao, bc.newBlock(tx), tx) ic := bc.newInteropContext(trigger.Application, bc.dao, bc.newBlock(tx), tx)
ic.VM = ic.SpawnVM() ic.VM = ic.SpawnVM()
ic.VM.LoadScriptWithFlags(tx.Script, smartcontract.All) ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
require.Error(t, ic.VM.Run()) require.Error(t, ic.VM.Run())
// Request is cleaned up even if callback failed. // Request is cleaned up even if callback failed.

View file

@ -40,17 +40,9 @@ func GetCallFlags() int64 {
} }
// Call executes previously deployed blockchain contract with specified hash // Call executes previously deployed blockchain contract with specified hash
// (20 bytes in BE form) using provided arguments.
// It returns whatever this contract returns. This function uses
// `System.Contract.Call` syscall.
func Call(scriptHash interop.Hash160, method string, args ...interface{}) interface{} {
return nil
}
// CallEx executes previously deployed blockchain contract with specified hash
// (20 bytes in BE form) using provided arguments and call flags. // (20 bytes in BE form) using provided arguments and call flags.
// It returns whatever this contract returns. This function uses // It returns whatever this contract returns. This function uses
// `System.Contract.CallEx` syscall. // `System.Contract.Call` syscall.
func CallEx(f CallFlag, scriptHash interop.Hash160, method string, args ...interface{}) interface{} { func Call(scriptHash interop.Hash160, method string, f CallFlag, args ...interface{}) interface{} {
return nil return nil
} }

View file

@ -9,6 +9,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "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/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
@ -120,8 +121,8 @@ func (c *Client) CreateNEP17MultiTransferTx(acc *wallet.Account, gas int64, reci
} }
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
for i := range recipients { for i := range recipients {
emit.AppCallWithOperationAndArgs(w.BinWriter, recipients[i].Token, "transfer", from, emit.AppCall(w.BinWriter, recipients[i].Token, "transfer",
recipients[i].Address, recipients[i].Amount, nil) callflag.WriteStates|callflag.AllowCall|callflag.AllowNotify, from, recipients[i].Address, recipients[i].Amount, nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
} }
accAddr, err := address.StringToUint160(acc.Address) accAddr, err := address.StringToUint160(acc.Address)

View file

@ -8,6 +8,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "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/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
@ -101,7 +102,7 @@ func expandArrayIntoScript(script *io.BinWriter, slice []Param) error {
// CreateFunctionInvocationScript creates a script to invoke given contract with // CreateFunctionInvocationScript creates a script to invoke given contract with
// given parameters. // given parameters.
func CreateFunctionInvocationScript(contract util.Uint160, params Params) ([]byte, error) { func CreateFunctionInvocationScript(contract util.Uint160, method string, params Params) ([]byte, error) {
script := io.NewBufBinWriter() script := io.NewBufBinWriter()
for i := len(params) - 1; i >= 0; i-- { for i := len(params) - 1; i >= 0; i-- {
switch params[i].Type { switch params[i].Type {
@ -127,6 +128,6 @@ func CreateFunctionInvocationScript(contract util.Uint160, params Params) ([]byt
} }
} }
emit.AppCall(script.BinWriter, contract) emit.AppCallNoArgs(script.BinWriter, contract, method, callflag.All)
return script.Bytes(), nil return script.Bytes(), nil
} }

View file

@ -21,46 +21,44 @@ func TestInvocationScriptCreationGood(t *testing.T) {
ps Params ps Params
script string script string
}{{ }{{
script: "0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, {
ps: Params{{Type: StringT, Value: "transfer"}}, ps: Params{{Type: StringT, Value: "transfer"}},
script: "0c087472616e736665720c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "1f0c087472616e736665720c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, { }, {
ps: Params{{Type: NumberT, Value: 42}}, ps: Params{{Type: NumberT, Value: 42}},
script: "0c0234320c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "1f0c0234320c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, { }, {
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{}}}, ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{}}},
script: "10c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "10c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, { }, {
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.ByteArrayType, Value: Param{Type: StringT, Value: "AwEtR+diEK7HO+Oas9GG4KQP6Nhr+j1Pq/2le6E7iPlq"}}}}}}, ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.ByteArrayType, Value: Param{Type: StringT, Value: "AwEtR+diEK7HO+Oas9GG4KQP6Nhr+j1Pq/2le6E7iPlq"}}}}}},
script: "0c2103012d47e76210aec73be39ab3d186e0a40fe8d86bfa3d4fabfda57ba13b88f96a11c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "0c2103012d47e76210aec73be39ab3d186e0a40fe8d86bfa3d4fabfda57ba13b88f96a11c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, { }, {
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.SignatureType, Value: Param{Type: StringT, Value: "4edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f"}}}}}}, ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.SignatureType, Value: Param{Type: StringT, Value: "4edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f"}}}}}},
script: "0c404edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f11c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "0c404edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f11c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, { }, {
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.StringType, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}}, ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.StringType, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}},
script: "0c283530626566643236666466366534643935376331316530373862323465626365363239313435366611c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "0c283530626566643236666466366534643935376331316530373862323465626365363239313435366611c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, { }, {
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash160Type, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}}, ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash160Type, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}},
script: "0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5011c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5011c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, { }, {
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash256Type, Value: Param{Type: StringT, Value: "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"}}}}}}, ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash256Type, Value: Param{Type: StringT, Value: "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"}}}}}},
script: "0c20e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6011c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "0c20e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6011c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, { }, {
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.PublicKeyType, Value: Param{Type: StringT, Value: "03c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c1"}}}}}}, ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.PublicKeyType, Value: Param{Type: StringT, Value: "03c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c1"}}}}}},
script: "0c2103c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c111c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "0c2103c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c111c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, { }, {
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.IntegerType, Value: Param{Type: NumberT, Value: 42}}}}}}, ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.IntegerType, Value: Param{Type: NumberT, Value: 42}}}}}},
script: "002a11c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "002a11c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, { }, {
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: StringT, Value: "true"}}}}}}, ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: StringT, Value: "true"}}}}}},
script: "1111c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "1111c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}, { }, {
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: StringT, Value: "false"}}}}}}, ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: StringT, Value: "false"}}}}}},
script: "1011c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", script: "1011c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
}} }}
for _, ps := range paramScripts { for _, ps := range paramScripts {
script, err := CreateFunctionInvocationScript(contract, ps.ps) script, err := CreateFunctionInvocationScript(contract, ps.ps[0].String(), ps.ps[1:])
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, ps.script, hex.EncodeToString(script)) assert.Equal(t, ps.script, hex.EncodeToString(script))
} }
@ -86,7 +84,7 @@ func TestInvocationScriptCreationBad(t *testing.T) {
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.UnknownType, Value: Param{}}}}}}, {{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.UnknownType, Value: Param{}}}}}},
} }
for _, ps := range testParams { for _, ps := range testParams {
_, err := CreateFunctionInvocationScript(contract, ps) _, err := CreateFunctionInvocationScript(contract, "", ps)
assert.NotNil(t, err) assert.NotNil(t, err)
} }
} }

View file

@ -14,6 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpc/client" "github.com/nspcc-dev/neo-go/pkg/rpc/client"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
@ -276,7 +277,7 @@ func TestCreateNEP17TransferTx(t *testing.T) {
require.NoError(t, acc.SignTx(tx)) require.NoError(t, acc.SignTx(tx))
require.NoError(t, chain.VerifyTx(tx)) require.NoError(t, chain.VerifyTx(tx))
v := chain.GetTestVM(trigger.Application, tx, nil) v := chain.GetTestVM(trigger.Application, tx, nil)
v.LoadScriptWithFlags(tx.Script, smartcontract.All) v.LoadScriptWithFlags(tx.Script, callflag.All)
require.NoError(t, v.Run()) require.NoError(t, v.Run())
} }

View file

@ -31,7 +31,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/rpc/request" "github.com/nspcc-dev/neo-go/pkg/rpc/request"
"github.com/nspcc-dev/neo-go/pkg/rpc/response" "github.com/nspcc-dev/neo-go/pkg/rpc/response"
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
@ -1097,7 +1097,7 @@ func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *respons
if len(tx.Signers) == 0 { if len(tx.Signers) == 0 {
tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.None}} tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.None}}
} }
script, err := request.CreateFunctionInvocationScript(scriptHash, reqParams[1:checkWitnessHashesIndex]) script, err := request.CreateFunctionInvocationScript(scriptHash, reqParams[1].String(), reqParams[2:checkWitnessHashesIndex])
if err != nil { if err != nil {
return nil, response.NewInternalServerError("can't create invocation script", err) return nil, response.NewInternalServerError("can't create invocation script", err)
} }
@ -1138,14 +1138,7 @@ func (s *Server) invokeContractVerify(reqParams request.Params) (interface{}, *r
return nil, responseErr return nil, responseErr
} }
args := make(request.Params, 1) args := reqParams[1:2]
args[0] = request.Param{
Type: request.StringT,
Value: manifest.MethodVerify,
}
if len(reqParams) > 1 {
args = append(args, reqParams[1])
}
var tx *transaction.Transaction var tx *transaction.Transaction
if len(reqParams) > 2 { if len(reqParams) > 2 {
signers, witnesses, err := reqParams[2].GetSignersWithWitnesses() signers, witnesses, err := reqParams[2].GetSignersWithWitnesses()
@ -1162,7 +1155,7 @@ func (s *Server) invokeContractVerify(reqParams request.Params) (interface{}, *r
if cs == nil { if cs == nil {
return nil, response.NewRPCError("unknown contract", scriptHash.StringBE(), nil) return nil, response.NewRPCError("unknown contract", scriptHash.StringBE(), nil)
} }
script, err := request.CreateFunctionInvocationScript(cs.Hash, args) script, err := request.CreateFunctionInvocationScript(cs.Hash, manifest.MethodVerify, args)
if err != nil { if err != nil {
return nil, response.NewInternalServerError("can't create invocation script", err) return nil, response.NewInternalServerError("can't create invocation script", err)
} }
@ -1188,7 +1181,7 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, tx *transaction.Tr
vm := s.chain.GetTestVM(t, tx, b) vm := s.chain.GetTestVM(t, tx, b)
vm.GasLimit = int64(s.config.MaxGasInvoke) vm.GasLimit = int64(s.config.MaxGasInvoke)
vm.LoadScriptWithFlags(script, smartcontract.All) vm.LoadScriptWithFlags(script, callflag.All)
err = vm.Run() err = vm.Run()
var faultException string var faultException string
if err != nil { if err != nil {

View file

@ -57,7 +57,7 @@ type rpcTestCase struct {
} }
const testContractHash = "743ed26f78e29ecd595535b74a943b1f9ccbc444" const testContractHash = "743ed26f78e29ecd595535b74a943b1f9ccbc444"
const deploymentTxHash = "a4644e08389ced59e875a8d5bdcb8fdded7507ed7dc3915a37e5be71736ac7b4" const deploymentTxHash = "2aef5684c6cf60884cc00400b78c65c5105ed4261a4f614bce74c74927a66bf3"
const genesisBlockHash = "0542f4350c6e236d0509bcd98188b0034bfbecc1a0c7fcdb8e4295310d468b70" const genesisBlockHash = "0542f4350c6e236d0509bcd98188b0034bfbecc1a0c7fcdb8e4295310d468b70"
const verifyContractHash = "a2eb22340979804cb10cc1add0b8822c201f4d8a" const verifyContractHash = "a2eb22340979804cb10cc1add0b8822c201f4d8a"
@ -1408,7 +1408,7 @@ func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
}, },
{ {
Asset: e.chain.UtilityTokenHash(), Asset: e.chain.UtilityTokenHash(),
Amount: "80006564770", Amount: "80006675650",
LastUpdated: 7, LastUpdated: 7,
}}, }},
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(), Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),

Binary file not shown.

View file

@ -1,4 +1,4 @@
package smartcontract package callflag
// CallFlag represents call flag. // CallFlag represents call flag.
type CallFlag byte type CallFlag byte

View file

@ -1,4 +1,4 @@
package smartcontract package callflag
import ( import (
"testing" "testing"

View file

@ -6,7 +6,7 @@ import (
"math/big" "math/big"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"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/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -46,10 +46,12 @@ type Context struct {
isDeployed bool isDeployed bool
// Call flags this context was created with. // Call flags this context was created with.
callFlag smartcontract.CallFlag callFlag callflag.CallFlag
// CheckReturn specifies if amount of return values needs to be checked. // ParamCount specifies number of parameters.
CheckReturn CheckReturnState ParamCount int
// RetCount specifies number of return values.
RetCount int
} }
// CheckReturnState represents possible states of stack after opcode.RET was processed. // CheckReturnState represents possible states of stack after opcode.RET was processed.
@ -69,9 +71,18 @@ var errNoInstParam = errors.New("failed to read instruction parameter")
// NewContext returns a new Context object. // NewContext returns a new Context object.
func NewContext(b []byte) *Context { func NewContext(b []byte) *Context {
return NewContextWithParams(b, 0, -1, 0)
}
// NewContextWithParams creates new Context objects using script, parameter count,
// return value count and initial position in script.
func NewContextWithParams(b []byte, pcount int, rvcount int, pos int) *Context {
return &Context{ return &Context{
prog: b, prog: b,
breakPoints: []int{}, breakPoints: []int{},
ParamCount: pcount,
RetCount: rvcount,
nextip: pos,
} }
} }
@ -194,7 +205,7 @@ func (c *Context) Copy() *Context {
} }
// GetCallFlags returns calling flags context was created with. // GetCallFlags returns calling flags context was created with.
func (c *Context) GetCallFlags() smartcontract.CallFlag { func (c *Context) GetCallFlags() callflag.CallFlag {
return c.callFlag return c.callFlag
} }

View file

@ -10,6 +10,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -150,17 +151,18 @@ func Jmp(w *io.BinWriter, op opcode.Opcode, label uint16) {
Instruction(w, op, buf) Instruction(w, op, buf)
} }
// AppCall emits call to provided contract. // AppCallNoArgs emits call to provided contract.
func AppCall(w *io.BinWriter, scriptHash util.Uint160) { func AppCallNoArgs(w *io.BinWriter, scriptHash util.Uint160, operation string, f callflag.CallFlag) {
Int(w, int64(f))
String(w, operation)
Bytes(w, scriptHash.BytesBE()) Bytes(w, scriptHash.BytesBE())
Syscall(w, interopnames.SystemContractCall) Syscall(w, interopnames.SystemContractCall)
} }
// AppCallWithOperationAndArgs emits an APPCALL with the given operation and arguments. // AppCall emits an APPCALL with the default parameters given operation and arguments.
func AppCallWithOperationAndArgs(w *io.BinWriter, scriptHash util.Uint160, operation string, args ...interface{}) { func AppCall(w *io.BinWriter, scriptHash util.Uint160, operation string, f callflag.CallFlag, args ...interface{}) {
Array(w, args...) Array(w, args...)
String(w, operation) AppCallNoArgs(w, scriptHash, operation, f)
AppCall(w, scriptHash)
} }
func isInstructionJmp(op opcode.Opcode) bool { func isInstructionJmp(op opcode.Opcode) bool {

View file

@ -6,7 +6,7 @@ import (
"sort" "sort"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
@ -15,7 +15,7 @@ type interopIDFuncPrice struct {
ID uint32 ID uint32
Func func(vm *VM) error Func func(vm *VM) error
Price int64 Price int64
RequiredFlags smartcontract.CallFlag RequiredFlags callflag.CallFlag
} }
var defaultVMInterops = []interopIDFuncPrice{ var defaultVMInterops = []interopIDFuncPrice{
@ -24,9 +24,9 @@ var defaultVMInterops = []interopIDFuncPrice{
{ID: interopnames.ToID([]byte(interopnames.SystemBinarySerialize)), {ID: interopnames.ToID([]byte(interopnames.SystemBinarySerialize)),
Func: RuntimeSerialize, Price: 1 << 12}, Func: RuntimeSerialize, Price: 1 << 12},
{ID: interopnames.ToID([]byte(interopnames.SystemRuntimeLog)), {ID: interopnames.ToID([]byte(interopnames.SystemRuntimeLog)),
Func: runtimeLog, Price: 1 << 15, RequiredFlags: smartcontract.AllowNotify}, Func: runtimeLog, Price: 1 << 15, RequiredFlags: callflag.AllowNotify},
{ID: interopnames.ToID([]byte(interopnames.SystemRuntimeNotify)), {ID: interopnames.ToID([]byte(interopnames.SystemRuntimeNotify)),
Func: runtimeNotify, Price: 1 << 15, RequiredFlags: smartcontract.AllowNotify}, Func: runtimeNotify, Price: 1 << 15, RequiredFlags: callflag.AllowNotify},
{ID: interopnames.ToID([]byte(interopnames.SystemEnumeratorCreate)), {ID: interopnames.ToID([]byte(interopnames.SystemEnumeratorCreate)),
Func: EnumeratorCreate, Price: 1 << 4}, Func: EnumeratorCreate, Price: 1 << 4},
{ID: interopnames.ToID([]byte(interopnames.SystemEnumeratorNext)), {ID: interopnames.ToID([]byte(interopnames.SystemEnumeratorNext)),

View file

@ -15,7 +15,7 @@ import (
"testing" "testing"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -114,7 +114,7 @@ func testSyscallHandler(v *VM, id uint32) error {
case 0x77777777: case 0x77777777:
v.Estack().PushVal(stackitem.NewInterop(new(int))) v.Estack().PushVal(stackitem.NewInterop(new(int)))
case 0x66666666: case 0x66666666:
if !v.Context().callFlag.Has(smartcontract.ReadOnly) { if !v.Context().callFlag.Has(callflag.ReadOnly) {
return errors.New("invalid call flags") return errors.New("invalid call flags")
} }
v.Estack().PushVal(stackitem.NewInterop(new(int))) v.Estack().PushVal(stackitem.NewInterop(new(int)))

View file

@ -17,7 +17,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
@ -272,13 +272,13 @@ func (v *VM) Load(prog []byte) {
// will immediately push a new context created from this script to // will immediately push a new context created from this script to
// the invocation stack and starts executing it. // the invocation stack and starts executing it.
func (v *VM) LoadScript(b []byte) { func (v *VM) LoadScript(b []byte) {
v.LoadScriptWithFlags(b, smartcontract.NoneFlag) v.LoadScriptWithFlags(b, callflag.NoneFlag)
} }
// LoadScriptWithFlags loads script and sets call flag to f. // LoadScriptWithFlags loads script and sets call flag to f.
func (v *VM) LoadScriptWithFlags(b []byte, f smartcontract.CallFlag) { func (v *VM) LoadScriptWithFlags(b []byte, f callflag.CallFlag) {
v.checkInvocationStackSize() v.checkInvocationStackSize()
ctx := NewContext(b) ctx := NewContextWithParams(b, 0, -1, 0)
v.estack = v.newItemStack("estack") v.estack = v.newItemStack("estack")
ctx.estack = v.estack ctx.estack = v.estack
ctx.tryStack = NewStack("exception") ctx.tryStack = NewStack("exception")
@ -294,19 +294,26 @@ func (v *VM) LoadScriptWithFlags(b []byte, f smartcontract.CallFlag) {
// assumes that it is used for deployed contracts setting context's parameters // assumes that it is used for deployed contracts setting context's parameters
// accordingly). It's up to user of this function to make sure the script and hash match // accordingly). It's up to user of this function to make sure the script and hash match
// each other. // each other.
func (v *VM) LoadScriptWithHash(b []byte, hash util.Uint160, f smartcontract.CallFlag) { func (v *VM) LoadScriptWithHash(b []byte, hash util.Uint160, f callflag.CallFlag) {
shash := v.GetCurrentScriptHash() shash := v.GetCurrentScriptHash()
v.LoadScriptWithCallingHash(shash, b, hash, f) v.LoadScriptWithCallingHash(shash, b, hash, f, true, 0)
} }
// LoadScriptWithCallingHash is similar to LoadScriptWithHash but sets calling hash explicitly. // LoadScriptWithCallingHash is similar to LoadScriptWithHash but sets calling hash explicitly.
// It should be used for calling from native contracts. // It should be used for calling from native contracts.
func (v *VM) LoadScriptWithCallingHash(caller util.Uint160, b []byte, hash util.Uint160, f smartcontract.CallFlag) { func (v *VM) LoadScriptWithCallingHash(caller util.Uint160, b []byte, hash util.Uint160,
f callflag.CallFlag, hasReturn bool, paramCount uint16) {
v.LoadScriptWithFlags(b, f) v.LoadScriptWithFlags(b, f)
ctx := v.Context() ctx := v.Context()
ctx.isDeployed = true ctx.isDeployed = true
ctx.scriptHash = hash ctx.scriptHash = hash
ctx.callingScriptHash = caller ctx.callingScriptHash = caller
if hasReturn {
ctx.RetCount = 1
} else {
ctx.RetCount = 0
}
ctx.ParamCount = int(paramCount)
} }
// Context returns the current executed context. Nil if there is no context, // Context returns the current executed context. Nil if there is no context,
@ -1274,6 +1281,10 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
newEstack := v.Context().estack newEstack := v.Context().estack
if oldEstack != newEstack { if oldEstack != newEstack {
if oldCtx.RetCount >= 0 && oldEstack.Len() != oldCtx.RetCount {
panic(fmt.Errorf("invalid return values count: expected %d, got %d",
oldCtx.RetCount, oldEstack.Len()))
}
rvcount := oldEstack.Len() rvcount := oldEstack.Len()
for i := rvcount; i > 0; i-- { for i := rvcount; i > 0; i-- {
elem := oldEstack.RemoveAt(i - 1) elem := oldEstack.RemoveAt(i - 1)
@ -1425,19 +1436,6 @@ func (v *VM) unloadContext(ctx *Context) {
if ctx.static != nil && currCtx != nil && ctx.static != currCtx.static { if ctx.static != nil && currCtx != nil && ctx.static != currCtx.static {
ctx.static.Clear() ctx.static.Clear()
} }
switch ctx.CheckReturn {
case NoCheck:
case EnsureIsEmpty:
if currCtx != nil && ctx.estack.len != 0 {
panic("return value amount is > 0")
}
case EnsureNotEmpty:
if currCtx != nil && ctx.estack.len == 0 {
currCtx.estack.PushVal(stackitem.Null{})
} else if ctx.estack.len > 1 {
panic("return value amount is > 1")
}
}
} }
// getTryParams splits TRY(L) instruction parameter into offsets for catch and finally blocks. // getTryParams splits TRY(L) instruction parameter into offsets for catch and finally blocks.
@ -1494,7 +1492,7 @@ func (v *VM) Call(ctx *Context, offset int) {
func (v *VM) call(ctx *Context, offset int) { func (v *VM) call(ctx *Context, offset int) {
v.checkInvocationStackSize() v.checkInvocationStackSize()
newCtx := ctx.Copy() newCtx := ctx.Copy()
newCtx.CheckReturn = NoCheck newCtx.RetCount = -1
newCtx.local = nil newCtx.local = nil
newCtx.arguments = nil newCtx.arguments = nil
newCtx.tryStack = NewStack("exception") newCtx.tryStack = NewStack("exception")

View file

@ -14,7 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -805,7 +805,7 @@ func TestSerializeInterop(t *testing.T) {
require.True(t, vm.HasFailed()) require.True(t, vm.HasFailed())
} }
func getTestCallFlagsFunc(syscall []byte, flags smartcontract.CallFlag, result interface{}) func(t *testing.T) { func getTestCallFlagsFunc(syscall []byte, flags callflag.CallFlag, result interface{}) func(t *testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
script := append([]byte{byte(opcode.SYSCALL)}, syscall...) script := append([]byte{byte(opcode.SYSCALL)}, syscall...)
v := newTestVM() v := newTestVM()
@ -823,11 +823,11 @@ func getTestCallFlagsFunc(syscall []byte, flags smartcontract.CallFlag, result i
func TestCallFlags(t *testing.T) { func TestCallFlags(t *testing.T) {
noFlags := []byte{0x77, 0x77, 0x77, 0x77} noFlags := []byte{0x77, 0x77, 0x77, 0x77}
readOnly := []byte{0x66, 0x66, 0x66, 0x66} readOnly := []byte{0x66, 0x66, 0x66, 0x66}
t.Run("NoFlagsNoRequired", getTestCallFlagsFunc(noFlags, smartcontract.NoneFlag, new(int))) t.Run("NoFlagsNoRequired", getTestCallFlagsFunc(noFlags, callflag.NoneFlag, new(int)))
t.Run("ProvideFlagsNoRequired", getTestCallFlagsFunc(noFlags, smartcontract.AllowCall, new(int))) t.Run("ProvideFlagsNoRequired", getTestCallFlagsFunc(noFlags, callflag.AllowCall, new(int)))
t.Run("NoFlagsSomeRequired", getTestCallFlagsFunc(readOnly, smartcontract.NoneFlag, nil)) t.Run("NoFlagsSomeRequired", getTestCallFlagsFunc(readOnly, callflag.NoneFlag, nil))
t.Run("OnlyOneProvided", getTestCallFlagsFunc(readOnly, smartcontract.AllowCall, nil)) t.Run("OnlyOneProvided", getTestCallFlagsFunc(readOnly, callflag.AllowCall, nil))
t.Run("AllFlagsProvided", getTestCallFlagsFunc(readOnly, smartcontract.ReadOnly, new(int))) t.Run("AllFlagsProvided", getTestCallFlagsFunc(readOnly, callflag.ReadOnly, new(int)))
} }
func callNTimes(n uint16) []byte { func callNTimes(n uint16) []byte {

View file

@ -20,6 +20,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
"go.uber.org/zap" "go.uber.org/zap"
@ -95,7 +96,7 @@ func main() {
rand.Read(value) rand.Read(value)
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, contractHash, "put", key, value) emit.AppCall(w.BinWriter, contractHash, "put", callflag.All, key, value)
handleError("can't create transaction", w.Err) handleError("can't create transaction", w.Err)
tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 4_000_000) tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 4_000_000)