From 5b4f38d717277880eab81dc01d9f153a3bfb3f43 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 16 Jun 2020 11:17:18 +0300 Subject: [PATCH] core: implement System.Contract.IsStandard syscall --- pkg/core/interop_system.go | 16 ++++++++++++++++ pkg/core/interop_system_test.go | 30 ++++++++++++++++++++++++++++++ pkg/core/interops.go | 1 + 3 files changed, 47 insertions(+) diff --git a/pkg/core/interop_system.go b/pkg/core/interop_system.go index 2688fcc6c..54cebba2b 100644 --- a/pkg/core/interop_system.go +++ b/pkg/core/interop_system.go @@ -470,3 +470,19 @@ func contractDestroy(ic *interop.Context, v *vm.VM) error { } return nil } + +// contractIsStandard checks if contract is standard (sig or multisig) contract. +func contractIsStandard(ic *interop.Context, v *vm.VM) error { + h := v.Estack().Pop().Bytes() + u, err := util.Uint160DecodeBytesBE(h) + if err != nil { + return err + } + var result bool + cs, _ := ic.DAO.GetContractState(u) + if cs == nil || vm.IsStandardContract(cs.Script) { + result = true + } + v.Estack().PushVal(result) + return nil +} diff --git a/pkg/core/interop_system_test.go b/pkg/core/interop_system_test.go index 3a06fcb4a..eefedd34e 100644 --- a/pkg/core/interop_system_test.go +++ b/pkg/core/interop_system_test.go @@ -4,6 +4,10 @@ import ( "math/big" "testing" + "github.com/nspcc-dev/dbft/crypto" + "github.com/nspcc-dev/neo-go/pkg/core/state" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/stretchr/testify/require" ) @@ -145,3 +149,29 @@ func TestBCGetBlock(t *testing.T) { require.True(t, ok) }) } + +func TestContractIsStandard(t *testing.T) { + v, ic, chain := createVM(t) + defer chain.Close() + + t.Run("True", func(t *testing.T) { + priv, err := keys.NewPrivateKey() + require.NoError(t, err) + + pub := priv.PublicKey() + err = ic.DAO.PutContractState(&state.Contract{ID: 42, Script: pub.GetVerificationScript()}) + require.NoError(t, err) + + v.Estack().PushVal(pub.GetScriptHash().BytesBE()) + require.NoError(t, contractIsStandard(ic, v)) + require.True(t, v.Estack().Pop().Bool()) + }) + t.Run("False", func(t *testing.T) { + script := []byte{byte(opcode.PUSHT)} + require.NoError(t, ic.DAO.PutContractState(&state.Contract{ID: 24, Script: script})) + + v.Estack().PushVal(crypto.Hash160(script).BytesBE()) + require.NoError(t, contractIsStandard(ic, v)) + require.False(t, v.Estack().Pop().Bool()) + }) +} diff --git a/pkg/core/interops.go b/pkg/core/interops.go index 7f0c3ee35..848f97f9a 100644 --- a/pkg/core/interops.go +++ b/pkg/core/interops.go @@ -91,6 +91,7 @@ var systemInterops = []interop.Function{ AllowedTriggers: trigger.Application, RequiredFlags: smartcontract.AllowModifyStates}, {Name: "System.Contract.Destroy", Func: contractDestroy, Price: 1000000, AllowedTriggers: trigger.Application, RequiredFlags: smartcontract.AllowModifyStates}, + {Name: "System.Contract.IsStandard", Func: contractIsStandard, Price: 30000}, {Name: "System.Contract.Update", Func: contractUpdate, Price: 0, AllowedTriggers: trigger.Application, RequiredFlags: smartcontract.AllowModifyStates}, {Name: "System.Enumerator.Concat", Func: enumerator.Concat, Price: 400},