forked from TrueCloudLab/neoneo-go
core/state: remove IsConst
from StorageItem
This commit is contained in:
parent
df041b8031
commit
fd4174ad31
10 changed files with 10 additions and 86 deletions
|
@ -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},
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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},
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,17 +7,14 @@ 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()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue