vm: do not increment invocation counter in Call

Everywhere it matters (and that's callExFromNative() now) it's incremented
already, so when we're doing Call() at the same time (and it's done to invoke
`_initialize` method) we're effectively double-incrementing it.
This commit is contained in:
Roman Khimov 2021-11-19 17:02:53 +03:00
parent a577d40de9
commit 7b713762be
2 changed files with 22 additions and 6 deletions

View file

@ -229,21 +229,31 @@ func TestRuntimeGetNotifications(t *testing.T) {
} }
func TestRuntimeGetInvocationCounter(t *testing.T) { func TestRuntimeGetInvocationCounter(t *testing.T) {
v, ic, _ := createVM(t) v, ic, bc := createVM(t)
cs, _ := getTestContractState(bc)
require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs))
ic.VM.Invocations[hash.Hash160([]byte{2})] = 42 ic.VM.Invocations[hash.Hash160([]byte{2})] = 42
t.Run("No invocations", func(t *testing.T) { t.Run("No invocations", func(t *testing.T) {
v.LoadScript([]byte{1}) v.Load([]byte{1})
// do not return an error in this case. // do not return an error in this case.
require.NoError(t, runtime.GetInvocationCounter(ic)) require.NoError(t, runtime.GetInvocationCounter(ic))
require.EqualValues(t, 1, v.Estack().Pop().BigInt().Int64()) require.EqualValues(t, 1, v.Estack().Pop().BigInt().Int64())
}) })
t.Run("NonZero", func(t *testing.T) { t.Run("NonZero", func(t *testing.T) {
v.LoadScript([]byte{2}) v.Load([]byte{2})
require.NoError(t, runtime.GetInvocationCounter(ic)) require.NoError(t, runtime.GetInvocationCounter(ic))
require.EqualValues(t, 42, v.Estack().Pop().BigInt().Int64()) require.EqualValues(t, 42, v.Estack().Pop().BigInt().Int64())
}) })
t.Run("Contract", func(t *testing.T) {
w := io.NewBufBinWriter()
emit.AppCall(w.BinWriter, cs.Hash, "invocCounter", callflag.All)
v.LoadWithFlags(w.Bytes(), callflag.All)
require.NoError(t, v.Run())
require.EqualValues(t, 1, v.Estack().Pop().BigInt().Int64())
})
} }
func TestStoragePut(t *testing.T) { func TestStoragePut(t *testing.T) {
@ -756,6 +766,9 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
burnGasOff := w.Len() burnGasOff := w.Len()
emit.Syscall(w.BinWriter, interopnames.SystemRuntimeBurnGas) emit.Syscall(w.BinWriter, interopnames.SystemRuntimeBurnGas)
emit.Opcodes(w.BinWriter, opcode.RET) emit.Opcodes(w.BinWriter, opcode.RET)
invocCounterOff := w.Len()
emit.Syscall(w.BinWriter, interopnames.SystemRuntimeGetInvocationCounter)
emit.Opcodes(w.BinWriter, opcode.RET)
script := w.Bytes() script := w.Bytes()
h := hash.Hash160(script) h := hash.Hash160(script)
@ -925,6 +938,11 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
}, },
ReturnType: smartcontract.VoidType, ReturnType: smartcontract.VoidType,
}, },
{
Name: "invocCounter",
Offset: invocCounterOff,
ReturnType: smartcontract.IntegerType,
},
} }
m.Permissions = make([]manifest.Permission, 2) m.Permissions = make([]manifest.Permission, 2)
m.Permissions[0].Contract.Type = manifest.PermissionHash m.Permissions[0].Contract.Type = manifest.PermissionHash

View file

@ -1556,11 +1556,9 @@ func (v *VM) throw(item stackitem.Item) {
v.handleException() v.handleException()
} }
// Call calls method by offset. It pushes new context to the invocation stack // Call calls method by offset using new execution context.
// and increments invocation counter for the corresponding context script hash.
func (v *VM) Call(ctx *Context, offset int) { func (v *VM) Call(ctx *Context, offset int) {
v.call(ctx, offset) v.call(ctx, offset)
v.Invocations[ctx.ScriptHash()]++
} }
// call is an internal representation of Call, which does not // call is an internal representation of Call, which does not