diff --git a/pkg/core/interop_neo.go b/pkg/core/interop_neo.go index fddeca7bc..852666740 100644 --- a/pkg/core/interop_neo.go +++ b/pkg/core/interop_neo.go @@ -216,6 +216,20 @@ func (ic *interopContext) invocationTxGetScript(v *vm.VM) error { return nil } +// witnessGetVerificationScript returns current witness' script. +func (ic *interopContext) witnessGetVerificationScript(v *vm.VM) error { + witInterface := v.Estack().Pop().Value() + wit, ok := witInterface.(*transaction.Witness) + if !ok { + return errors.New("value is not a witness") + } + // It's important not to share wit.VerificationScript slice with the code running in VM. + script := make([]byte, len(wit.VerificationScript)) + copy(script, wit.VerificationScript) + v.Estack().PushVal(script) + return nil +} + // bcGetValidators returns validators. func (ic *interopContext) bcGetValidators(v *vm.VM) error { validators := ic.dao.GetValidators() diff --git a/pkg/core/interop_neo_test.go b/pkg/core/interop_neo_test.go index d84dc4472..0013e9461 100644 --- a/pkg/core/interop_neo_test.go +++ b/pkg/core/interop_neo_test.go @@ -126,6 +126,19 @@ func TestInvocationTxGetScript(t *testing.T) { require.Equal(t, inv.Script, value) } +func TestWitnessGetVerificationScript(t *testing.T) { + v := vm.New() + script := []byte{byte(opcode.PUSHM1), byte(opcode.RET)} + witness := transaction.Witness{InvocationScript: nil, VerificationScript: script} + + context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), nil, nil) + v.Estack().PushVal(vm.NewInteropItem(&witness)) + err := context.witnessGetVerificationScript(v) + require.NoError(t, err) + value := v.Estack().Pop().Value().([]byte) + require.Equal(t, witness.VerificationScript, value) +} + func TestPopInputFromVM(t *testing.T) { v, tx, _ := createVMAndTX(t) v.Estack().PushVal(vm.NewInteropItem(&tx.Inputs[0])) diff --git a/pkg/core/interops.go b/pkg/core/interops.go index c0e405ec1..312817580 100644 --- a/pkg/core/interops.go +++ b/pkg/core/interops.go @@ -175,6 +175,7 @@ var neoInterops = []interopedFunction{ {Name: "Neo.Transaction.GetType", Func: (*interopContext).txGetType, Price: 1}, {Name: "Neo.Transaction.GetUnspentCoins", Func: (*interopContext).txGetUnspentCoins, Price: 200}, {Name: "Neo.Transaction.GetWitnesses", Func: (*interopContext).txGetWitnesses, Price: 200}, + {Name: "Neo.Witness.GetVerificationScript", Func: (*interopContext).witnessGetVerificationScript, Price: 100}, // {Name: "Neo.Enumerator.Concat", Func: (*interopContext).enumeratorConcat, Price: 1}, // {Name: "Neo.Enumerator.Create", Func: (*interopContext).enumeratorCreate, Price: 1}, // {Name: "Neo.Enumerator.Next", Func: (*interopContext).enumeratorNext, Price: 1}, @@ -187,7 +188,6 @@ var neoInterops = []interopedFunction{ {Name: "Neo.Runtime.Deserialize", Func: (*interopContext).runtimeDeserialize, Price: 1}, {Name: "Neo.Runtime.Serialize", Func: (*interopContext).runtimeSerialize, Price: 1}, // {Name: "Neo.Storage.Find", Func: (*interopContext).storageFind, Price: 1}, - // {Name: "Neo.Witness.GetVerificationScript", Func: (*interopContext).witnessGetVerificationScript, Price: 100}, // Aliases. // {Name: "Neo.Iterator.Next", Func: (*interopContext).enumeratorNext, Price: 1},