core/state: remove IsConst from StorageItem

This commit is contained in:
Evgeniy Stratonikov 2021-03-05 15:36:32 +03:00
parent df041b8031
commit fd4174ad31
10 changed files with 10 additions and 86 deletions

View file

@ -98,7 +98,6 @@ func TestSyscallExecution(t *testing.T) {
"storage.GetContext": {interopnames.SystemStorageGetContext, nil, false}, "storage.GetContext": {interopnames.SystemStorageGetContext, nil, false},
"storage.GetReadOnlyContext": {interopnames.SystemStorageGetReadOnlyContext, nil, false}, "storage.GetReadOnlyContext": {interopnames.SystemStorageGetReadOnlyContext, nil, false},
"storage.Put": {interopnames.SystemStoragePut, []string{sctx, b, b}, true}, "storage.Put": {interopnames.SystemStoragePut, []string{sctx, b, b}, true},
"storage.PutEx": {interopnames.SystemStoragePutEx, []string{sctx, b, b, "storage.PutConstant"}, true},
"storage.ConvertContextToReadOnly": {interopnames.SystemStorageAsReadOnly, []string{sctx}, false}, "storage.ConvertContextToReadOnly": {interopnames.SystemStorageAsReadOnly, []string{sctx}, false},
"crypto.ECDsaSecp256r1Verify": {interopnames.NeoCryptoVerifyWithECDsaSecp256r1, []string{b, pub, sig}, false}, "crypto.ECDsaSecp256r1Verify": {interopnames.NeoCryptoVerifyWithECDsaSecp256r1, []string{b, pub, sig}, false},
"crypto.ECDsaSecp256k1Verify": {interopnames.NeoCryptoVerifyWithECDsaSecp256k1, []string{b, pub, sig}, false}, "crypto.ECDsaSecp256k1Verify": {interopnames.NeoCryptoVerifyWithECDsaSecp256k1, []string{b, pub, sig}, false},

View file

@ -46,7 +46,6 @@ const (
SystemStorageGetContext = "System.Storage.GetContext" SystemStorageGetContext = "System.Storage.GetContext"
SystemStorageGetReadOnlyContext = "System.Storage.GetReadOnlyContext" SystemStorageGetReadOnlyContext = "System.Storage.GetReadOnlyContext"
SystemStoragePut = "System.Storage.Put" SystemStoragePut = "System.Storage.Put"
SystemStoragePutEx = "System.Storage.PutEx"
SystemStorageAsReadOnly = "System.Storage.AsReadOnly" SystemStorageAsReadOnly = "System.Storage.AsReadOnly"
NeoCryptoVerifyWithECDsaSecp256r1 = "Neo.Crypto.VerifyWithECDsaSecp256r1" NeoCryptoVerifyWithECDsaSecp256r1 = "Neo.Crypto.VerifyWithECDsaSecp256r1"
NeoCryptoVerifyWithECDsaSecp256k1 = "Neo.Crypto.VerifyWithECDsaSecp256k1" NeoCryptoVerifyWithECDsaSecp256k1 = "Neo.Crypto.VerifyWithECDsaSecp256k1"
@ -101,7 +100,6 @@ var names = []string{
SystemStorageGetContext, SystemStorageGetContext,
SystemStorageGetReadOnlyContext, SystemStorageGetReadOnlyContext,
SystemStoragePut, SystemStoragePut,
SystemStoragePutEx,
SystemStorageAsReadOnly, SystemStorageAsReadOnly,
NeoCryptoVerifyWithECDsaSecp256r1, NeoCryptoVerifyWithECDsaSecp256r1,
NeoCryptoVerifyWithECDsaSecp256k1, NeoCryptoVerifyWithECDsaSecp256k1,

View file

@ -73,10 +73,6 @@ func storageDelete(ic *interop.Context) error {
} }
ic.VM.AddGas(ic.Chain.GetPolicer().GetStoragePrice()) ic.VM.AddGas(ic.Chain.GetPolicer().GetStoragePrice())
key := ic.VM.Estack().Pop().Bytes() key := ic.VM.Estack().Pop().Bytes()
si := ic.DAO.GetStorageItem(stc.ID, key)
if si != nil && si.IsConst {
return errors.New("storage item is constant")
}
return ic.DAO.DeleteStorageItem(stc.ID, key) return ic.DAO.DeleteStorageItem(stc.ID, key)
} }
@ -122,7 +118,7 @@ func storageGetContextInternal(ic *interop.Context, isReadOnly bool) error {
return nil return nil
} }
func putWithContextAndFlags(ic *interop.Context, stc *StorageContext, key []byte, value []byte, isConst bool) error { func putWithContext(ic *interop.Context, stc *StorageContext, key []byte, value []byte) error {
if len(key) > MaxStorageKeyLen { if len(key) > MaxStorageKeyLen {
return errors.New("key is too big") return errors.New("key is too big")
} }
@ -133,17 +129,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 && si.IsConst { sizeInc := len(value)
return errors.New("storage item exists and is read-only")
}
sizeInc := 1
if si == nil { if si == nil {
si = &state.StorageItem{} si = &state.StorageItem{}
sizeInc = len(key) + len(value) sizeInc = len(key) + len(value)
} else if len(value) != 0 { } else if len(value) != 0 {
if len(value) <= len(si.Value) { if len(value) <= len(si.Value) {
sizeInc = (len(value)-1)/4 + 1 sizeInc = (len(value)-1)/4 + 1
} else { } else if len(si.Value) != 0 {
sizeInc = (len(si.Value)-1)/4 + 1 + len(value) - len(si.Value) sizeInc = (len(si.Value)-1)/4 + 1 + len(value) - len(si.Value)
} }
} }
@ -151,12 +144,11 @@ func putWithContextAndFlags(ic *interop.Context, stc *StorageContext, key []byte
return errGasLimitExceeded return errGasLimitExceeded
} }
si.Value = value si.Value = value
si.IsConst = isConst
return ic.DAO.PutStorageItem(stc.ID, key, si) return ic.DAO.PutStorageItem(stc.ID, key, si)
} }
// storagePutInternal is a unified implementation of storagePut and storagePutEx. // storagePut puts key-value pair into the storage.
func storagePutInternal(ic *interop.Context, getFlag bool) error { func storagePut(ic *interop.Context) error {
stcInterface := ic.VM.Estack().Pop().Value() stcInterface := ic.VM.Estack().Pop().Value()
stc, ok := stcInterface.(*StorageContext) stc, ok := stcInterface.(*StorageContext)
if !ok { if !ok {
@ -164,21 +156,7 @@ func storagePutInternal(ic *interop.Context, getFlag bool) error {
} }
key := ic.VM.Estack().Pop().Bytes() key := ic.VM.Estack().Pop().Bytes()
value := ic.VM.Estack().Pop().Bytes() value := ic.VM.Estack().Pop().Bytes()
var flag int return putWithContext(ic, stc, key, value)
if getFlag {
flag = int(ic.VM.Estack().Pop().BigInt().Int64())
}
return putWithContextAndFlags(ic, stc, key, value, int(Constant)&flag != 0)
}
// storagePut puts key-value pair into the storage.
func storagePut(ic *interop.Context) error {
return storagePutInternal(ic, false)
}
// storagePutEx puts key-value pair with given flags into the storage.
func storagePutEx(ic *interop.Context) error {
return storagePutInternal(ic, true)
} }
// storageContextAsReadOnly sets given context to read-only mode. // storageContextAsReadOnly sets given context to read-only mode.

View file

@ -277,21 +277,6 @@ func TestStoragePut(t *testing.T) {
initVM(t, []byte{1}, make([]byte, MaxStorageValueLen+1), -1) initVM(t, []byte{1}, make([]byte, MaxStorageValueLen+1), -1)
require.Error(t, storagePut(ic)) require.Error(t, storagePut(ic))
}) })
t.Run("item exists and is const", func(t *testing.T) {
v := ic.SpawnVM()
v.LoadScript(cs.NEF.Script)
v.GasLimit = -1
v.Estack().PushVal(1)
v.Estack().PushVal("value")
v.Estack().PushVal("key")
require.NoError(t, storageGetContext(ic))
require.NoError(t, storagePutEx(ic))
v.Estack().PushVal("new")
v.Estack().PushVal("key")
require.NoError(t, storageGetContext(ic))
require.Error(t, storagePut(ic))
})
}) })
} }
@ -301,16 +286,14 @@ func TestStorageDelete(t *testing.T) {
require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs)) require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs))
v.LoadScriptWithHash(cs.NEF.Script, cs.Hash, callflag.All) v.LoadScriptWithHash(cs.NEF.Script, cs.Hash, callflag.All)
put := func(key, value string, flag int) { put := func(key, value string, flag int) {
v.Estack().PushVal(flag)
v.Estack().PushVal(value) v.Estack().PushVal(value)
v.Estack().PushVal(key) v.Estack().PushVal(key)
require.NoError(t, storageGetContext(ic)) require.NoError(t, storageGetContext(ic))
require.NoError(t, storagePutEx(ic)) require.NoError(t, storagePut(ic))
} }
put("key1", "value1", 0) put("key1", "value1", 0)
put("key2", "value2", 0) put("key2", "value2", 0)
put("key3", "value3", 0) put("key3", "value3", 0)
put("key4", "value4", 1)
t.Run("good", func(t *testing.T) { t.Run("good", func(t *testing.T) {
v.Estack().PushVal("key1") v.Estack().PushVal("key1")
@ -328,11 +311,6 @@ func TestStorageDelete(t *testing.T) {
require.NoError(t, storageContextAsReadOnly(ic)) require.NoError(t, storageContextAsReadOnly(ic))
require.Error(t, storageDelete(ic)) require.Error(t, storageDelete(ic))
}) })
t.Run("constant item", func(t *testing.T) {
v.Estack().PushVal("key4")
require.NoError(t, storageGetContext(ic))
require.Error(t, storageDelete(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.

View file

@ -82,8 +82,6 @@ var systemInterops = []interop.Function{
RequiredFlags: callflag.ReadStates}, RequiredFlags: callflag.ReadStates},
{Name: interopnames.SystemStoragePut, Func: storagePut, Price: 0, RequiredFlags: callflag.WriteStates, {Name: interopnames.SystemStoragePut, Func: storagePut, Price: 0, RequiredFlags: callflag.WriteStates,
ParamCount: 3}, // These don't have static price in C# code. ParamCount: 3}, // These don't have static price in C# code.
{Name: interopnames.SystemStoragePutEx, Func: storagePutEx, Price: 0, RequiredFlags: callflag.WriteStates,
ParamCount: 4},
{Name: interopnames.SystemStorageAsReadOnly, Func: storageContextAsReadOnly, Price: 1 << 4, {Name: interopnames.SystemStorageAsReadOnly, Func: storageContextAsReadOnly, Price: 1 << 4,
RequiredFlags: callflag.ReadStates, ParamCount: 1}, RequiredFlags: callflag.ReadStates, ParamCount: 1},
} }

View file

@ -39,7 +39,6 @@ func TestUnexpectedNonInterops(t *testing.T) {
storageFind, storageFind,
storageGet, storageGet,
storagePut, storagePut,
storagePutEx,
} }
for _, f := range funcs { for _, f := range funcs {
for k, v := range vals { for k, v := range vals {

View file

@ -926,9 +926,6 @@ func (n *NEO) putGASRecord(dao dao.DAO, index uint32, value *big.Int) error {
key := make([]byte, 5) key := make([]byte, 5)
key[0] = prefixGASPerBlock key[0] = prefixGASPerBlock
binary.BigEndian.PutUint32(key[1:], index) binary.BigEndian.PutUint32(key[1:], index)
si := &state.StorageItem{ si := &state.StorageItem{Value: bigint.ToBytes(value)}
Value: bigint.ToBytes(value),
IsConst: false,
}
return dao.PutStorageItem(n.ID, key, si) return dao.PutStorageItem(n.ID, key, si)
} }

View file

@ -6,18 +6,15 @@ import (
// StorageItem is the value to be stored with read-only flag. // StorageItem is the value to be stored with read-only flag.
type StorageItem struct { type StorageItem struct {
Value []byte Value []byte
IsConst bool
} }
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (si *StorageItem) EncodeBinary(w *io.BinWriter) { func (si *StorageItem) EncodeBinary(w *io.BinWriter) {
w.WriteVarBytes(si.Value) w.WriteVarBytes(si.Value)
w.WriteBool(si.IsConst)
} }
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (si *StorageItem) DecodeBinary(r *io.BinReader) { func (si *StorageItem) DecodeBinary(r *io.BinReader) {
si.Value = r.ReadVarBytes() si.Value = r.ReadVarBytes()
si.IsConst = r.ReadBool()
} }

View file

@ -8,8 +8,7 @@ import (
func TestEncodeDecodeStorageItem(t *testing.T) { func TestEncodeDecodeStorageItem(t *testing.T) {
storageItem := &StorageItem{ storageItem := &StorageItem{
Value: []byte{}, Value: []byte{1, 2, 3},
IsConst: false,
} }
testserdes.EncodeDecodeBinary(t, storageItem, new(StorageItem)) testserdes.EncodeDecodeBinary(t, storageItem, new(StorageItem))

View file

@ -38,16 +38,6 @@ const (
PickField1 FindFlags = 1 << 5 PickField1 FindFlags = 1 << 5
) )
// PutFlags represents flag of `PutEx` syscall.
type PutFlags byte
const (
// PutDefault is a storage flag for non-constant items.
PutDefault PutFlags = 0
// PutConstant is a storage flag for constant items.
PutConstant PutFlags = 0x01
)
// ConvertContextToReadOnly returns new context from the given one, but with // ConvertContextToReadOnly returns new context from the given one, but with
// writing capability turned off, so that you could only invoke Get and Find // writing capability turned off, so that you could only invoke Get and Find
// using this new Context. If Context is already read-only this function is a // using this new Context. If Context is already read-only this function is a
@ -79,15 +69,6 @@ func Put(ctx Context, key interface{}, value interface{}) {
neogointernal.Syscall3NoReturn("System.Storage.Put", ctx, key, value) neogointernal.Syscall3NoReturn("System.Storage.Put", ctx, key, value)
} }
// PutEx is an advanced version of Put which saves given value with given key
// and given ReadOnly flag in the storage using given Context. `flag` argument
// can either be odd for constant storage items or even for variable storage items.
// Refer to Put function description for details on how to pass the remaining
// arguments. This function uses `System.Storage.PutEx` syscall.
func PutEx(ctx Context, key interface{}, value interface{}, flag PutFlags) {
neogointernal.Syscall4NoReturn("System.Storage.PutEx", ctx, key, value, flag)
}
// Get retrieves value stored for the given key using given Context. See Put // Get retrieves value stored for the given key using given Context. See Put
// documentation on possible key and value types. If the value is not present in // documentation on possible key and value types. If the value is not present in
// the database it returns nil. This function uses `System.Storage.Get` syscall. // the database it returns nil. This function uses `System.Storage.Get` syscall.