mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-12 11:10:35 +00:00
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")
|
return errors.New("StorageContext is read only")
|
||||||
}
|
}
|
||||||
si := ic.DAO.GetStorageItem(stc.ID, key)
|
si := ic.DAO.GetStorageItem(stc.ID, key)
|
||||||
if si == nil {
|
if si != nil && si.IsConst {
|
||||||
si = &state.StorageItem{}
|
|
||||||
}
|
|
||||||
if si.IsConst {
|
|
||||||
return errors.New("storage item exists and is read-only")
|
return errors.New("storage item exists and is read-only")
|
||||||
}
|
}
|
||||||
sizeInc := 1
|
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)
|
sizeInc = len(value) - len(si.Value)
|
||||||
}
|
}
|
||||||
if !ic.VM.AddGas(int64(sizeInc) * StoragePrice) {
|
if !ic.VM.AddGas(int64(sizeInc) * StoragePrice) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"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.
|
// getTestContractState returns 2 contracts second of which is allowed to call the first.
|
||||||
func getTestContractState() (*state.Contract, *state.Contract) {
|
func getTestContractState() (*state.Contract, *state.Contract) {
|
||||||
script := []byte{
|
script := []byte{
|
||||||
|
|
Loading…
Reference in a new issue