mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-27 03:58:06 +00:00
core: implement System.Contract.Call interop
This commit is contained in:
parent
301c1b7601
commit
ec900c7ff7
4 changed files with 51 additions and 14 deletions
|
@ -84,6 +84,16 @@ type ContractMD struct {
|
||||||
Methods map[string]MethodAndPrice
|
Methods map[string]MethodAndPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetContract returns script of the contract with the specified hash.
|
||||||
|
func (ic *Context) GetContract(h util.Uint160) ([]byte, bool) {
|
||||||
|
cs, err := ic.DAO.GetContractState(h)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
hasDynamicInvoke := (cs.Properties & smartcontract.HasDynamicInvoke) != 0
|
||||||
|
return cs.Script, hasDynamicInvoke
|
||||||
|
}
|
||||||
|
|
||||||
// NewContractMD returns Contract with the specified list of methods.
|
// NewContractMD returns Contract with the specified list of methods.
|
||||||
func NewContractMD(name string) *ContractMD {
|
func NewContractMD(name string) *ContractMD {
|
||||||
c := &ContractMD{
|
c := &ContractMD{
|
||||||
|
|
|
@ -11,6 +11,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/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/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/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"
|
||||||
|
@ -470,6 +471,39 @@ func storageContextAsReadOnly(ic *interop.Context, v *vm.VM) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// contractCall calls a contract.
|
||||||
|
func contractCall(ic *interop.Context, v *vm.VM) error {
|
||||||
|
h := v.Estack().Pop().Bytes()
|
||||||
|
method := v.Estack().Pop().Item()
|
||||||
|
args := v.Estack().Pop().Item()
|
||||||
|
return contractCallExInternal(ic, v, h, method, args, smartcontract.All)
|
||||||
|
}
|
||||||
|
|
||||||
|
// contractCallEx calls a contract with flags.
|
||||||
|
func contractCallEx(ic *interop.Context, v *vm.VM) error {
|
||||||
|
h := v.Estack().Pop().Bytes()
|
||||||
|
method := v.Estack().Pop().Item()
|
||||||
|
args := v.Estack().Pop().Item()
|
||||||
|
flags := smartcontract.CallFlag(int32(v.Estack().Pop().BigInt().Int64()))
|
||||||
|
return contractCallExInternal(ic, v, h, method, args, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func contractCallExInternal(ic *interop.Context, v *vm.VM, h []byte, method vm.StackItem, args vm.StackItem, _ smartcontract.CallFlag) error {
|
||||||
|
u, err := util.Uint160DecodeBytesBE(h)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("invalid contract hash")
|
||||||
|
}
|
||||||
|
script, _ := ic.GetContract(u)
|
||||||
|
if script == nil {
|
||||||
|
return errors.New("contract not found")
|
||||||
|
}
|
||||||
|
// TODO perform flags checking after #923
|
||||||
|
v.LoadScript(script)
|
||||||
|
v.Estack().PushVal(args)
|
||||||
|
v.Estack().PushVal(method)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// contractDestroy destroys a contract.
|
// contractDestroy destroys a contract.
|
||||||
func contractDestroy(ic *interop.Context, v *vm.VM) error {
|
func contractDestroy(ic *interop.Context, v *vm.VM) error {
|
||||||
if ic.Trigger != trigger.Application {
|
if ic.Trigger != trigger.Application {
|
||||||
|
|
|
@ -16,8 +16,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
||||||
"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/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"
|
||||||
)
|
)
|
||||||
|
@ -27,18 +25,7 @@ import (
|
||||||
func SpawnVM(ic *interop.Context) *vm.VM {
|
func SpawnVM(ic *interop.Context) *vm.VM {
|
||||||
vm := vm.New()
|
vm := vm.New()
|
||||||
bc := ic.Chain.(*Blockchain)
|
bc := ic.Chain.(*Blockchain)
|
||||||
vm.SetScriptGetter(func(hash util.Uint160) ([]byte, bool) {
|
vm.SetScriptGetter(ic.GetContract)
|
||||||
if c := bc.contracts.ByHash(hash); c != nil {
|
|
||||||
meta := c.Metadata()
|
|
||||||
return meta.Script, (meta.Manifest.Features&smartcontract.HasDynamicInvoke != 0)
|
|
||||||
}
|
|
||||||
cs, err := ic.DAO.GetContractState(hash)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
hasDynamicInvoke := (cs.Properties & smartcontract.HasDynamicInvoke) != 0
|
|
||||||
return cs.Script, hasDynamicInvoke
|
|
||||||
})
|
|
||||||
vm.RegisterInteropGetter(getSystemInterop(ic))
|
vm.RegisterInteropGetter(getSystemInterop(ic))
|
||||||
vm.RegisterInteropGetter(getNeoInterop(ic))
|
vm.RegisterInteropGetter(getNeoInterop(ic))
|
||||||
vm.RegisterInteropGetter(bc.contracts.GetNativeInterop(ic))
|
vm.RegisterInteropGetter(bc.contracts.GetNativeInterop(ic))
|
||||||
|
@ -84,6 +71,8 @@ var systemInterops = []interop.Function{
|
||||||
{Name: "System.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
|
{Name: "System.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
|
||||||
{Name: "System.Blockchain.GetTransaction", Func: bcGetTransaction, Price: 200},
|
{Name: "System.Blockchain.GetTransaction", Func: bcGetTransaction, Price: 200},
|
||||||
{Name: "System.Blockchain.GetTransactionHeight", Func: bcGetTransactionHeight, Price: 100},
|
{Name: "System.Blockchain.GetTransactionHeight", Func: bcGetTransactionHeight, Price: 100},
|
||||||
|
{Name: "System.Contract.Call", Func: contractCall, Price: 1},
|
||||||
|
{Name: "System.Contract.CallEx", Func: contractCallEx, Price: 1},
|
||||||
{Name: "System.Contract.Destroy", Func: contractDestroy, Price: 1},
|
{Name: "System.Contract.Destroy", Func: contractDestroy, Price: 1},
|
||||||
{Name: "System.Contract.GetStorageContext", Func: contractGetStorageContext, Price: 1},
|
{Name: "System.Contract.GetStorageContext", Func: contractGetStorageContext, Price: 1},
|
||||||
{Name: "System.ExecutionEngine.GetCallingScriptHash", Func: engineGetCallingScriptHash, Price: 1},
|
{Name: "System.ExecutionEngine.GetCallingScriptHash", Func: engineGetCallingScriptHash, Price: 1},
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"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/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"
|
||||||
|
@ -85,6 +86,9 @@ func TestNativeContract_Invoke(t *testing.T) {
|
||||||
tn := newTestNative()
|
tn := newTestNative()
|
||||||
chain.registerNative(tn)
|
chain.registerNative(tn)
|
||||||
|
|
||||||
|
err := chain.dao.PutContractState(&state.Contract{Script: tn.meta.Script})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "sum", int64(14), int64(28))
|
emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "sum", int64(14), int64(28))
|
||||||
script := w.Bytes()
|
script := w.Bytes()
|
||||||
|
|
Loading…
Reference in a new issue