forked from TrueCloudLab/neoneo-go
core: calculate gas for System.Storage.Put
correctly
If `Put` creates new key, its length should contribute to a GAS cost of the syscall.
This commit is contained in:
parent
05c1b8746a
commit
833bbb1d35
2 changed files with 41 additions and 5 deletions
|
@ -389,14 +389,14 @@ func putWithContextAndFlags(ic *interop.Context, stc *StorageContext, key []byte
|
|||
return errors.New("StorageContext is read only")
|
||||
}
|
||||
si := ic.DAO.GetStorageItem(stc.ID, key)
|
||||
if si == nil {
|
||||
si = &state.StorageItem{}
|
||||
}
|
||||
if si.IsConst {
|
||||
if si != nil && si.IsConst {
|
||||
return errors.New("storage item exists and is read-only")
|
||||
}
|
||||
sizeInc := 1
|
||||
if len(value) > len(si.Value) {
|
||||
if si == nil {
|
||||
si = &state.StorageItem{}
|
||||
sizeInc = len(key) + len(value)
|
||||
} else if len(value) > len(si.Value) {
|
||||
sizeInc = len(value) - len(si.Value)
|
||||
}
|
||||
if !ic.VM.AddGas(int64(sizeInc) * StoragePrice) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
|
@ -327,6 +328,41 @@ func TestBlockchainGetContractState(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestStoragePut(t *testing.T) {
|
||||
_, cs, ic, bc := createVMAndContractState(t)
|
||||
defer bc.Close()
|
||||
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
|
||||
initVM := func(t *testing.T, key, value []byte, gas int64) {
|
||||
v := ic.SpawnVM()
|
||||
v.LoadScript(cs.Script)
|
||||
v.GasLimit = gas
|
||||
v.Estack().PushVal(value)
|
||||
v.Estack().PushVal(key)
|
||||
require.NoError(t, storageGetContext(ic))
|
||||
}
|
||||
|
||||
t.Run("create, not enough gas", func(t *testing.T) {
|
||||
initVM(t, []byte{1}, []byte{2, 3}, 2*StoragePrice)
|
||||
err := storagePut(ic)
|
||||
require.True(t, errors.Is(err, errGasLimitExceeded), "got: %v", err)
|
||||
})
|
||||
|
||||
initVM(t, []byte{4}, []byte{5, 6}, 3*StoragePrice)
|
||||
require.NoError(t, storagePut(ic))
|
||||
|
||||
t.Run("update", func(t *testing.T) {
|
||||
t.Run("not enough gas", func(t *testing.T) {
|
||||
initVM(t, []byte{4}, []byte{5, 6, 7, 8}, StoragePrice)
|
||||
err := storagePut(ic)
|
||||
require.True(t, errors.Is(err, errGasLimitExceeded), "got: %v", err)
|
||||
})
|
||||
initVM(t, []byte{4}, []byte{5, 6, 7, 8}, 2*StoragePrice)
|
||||
require.NoError(t, storagePut(ic))
|
||||
})
|
||||
}
|
||||
|
||||
// getTestContractState returns 2 contracts second of which is allowed to call the first.
|
||||
func getTestContractState() (*state.Contract, *state.Contract) {
|
||||
script := []byte{
|
||||
|
|
Loading…
Reference in a new issue