core: provide monotonically increasing ID for contracts

ID is a contract identifier which doesn't change during migration.
It is also used as a part of storage context instead of contract hash.
This commit is contained in:
Evgenii Stratonikov 2020-06-09 15:12:23 +03:00
parent 20616cc97f
commit a03af55732
4 changed files with 45 additions and 1 deletions

View file

@ -31,6 +31,7 @@ type DAO interface {
GetHeaderHashes() ([]util.Uint256, error) GetHeaderHashes() ([]util.Uint256, error)
GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error) GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error)
GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error)
GetNextContractID() (int32, error)
GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem
GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error) GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error)
GetStorageItemsWithPrefix(hash util.Uint160, prefix []byte) (map[string]*state.StorageItem, error) GetStorageItemsWithPrefix(hash util.Uint160, prefix []byte) (map[string]*state.StorageItem, error)
@ -45,6 +46,7 @@ type DAO interface {
PutCurrentHeader(hashAndIndex []byte) error PutCurrentHeader(hashAndIndex []byte) error
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error
PutNextContractID(id int32) error
PutStorageItem(scripthash util.Uint160, key []byte, si *state.StorageItem) error PutStorageItem(scripthash util.Uint160, key []byte, si *state.StorageItem) error
PutVersion(v string) error PutVersion(v string) error
StoreAsBlock(block *block.Block) error StoreAsBlock(block *block.Block) error
@ -169,6 +171,27 @@ func (dao *Simple) DeleteContractState(hash util.Uint160) error {
return dao.Store.Delete(key) return dao.Store.Delete(key)
} }
// GetNextContractID returns id for the next contract and increases stored id.
func (dao *Simple) GetNextContractID() (int32, error) {
key := storage.SYSContractID.Bytes()
data, err := dao.Store.Get(key)
if err != nil {
if err == storage.ErrKeyNotFound {
err = nil
}
return 0, err
}
return int32(binary.LittleEndian.Uint32(data)), nil
}
// PutNextContractID sets next contract id to id.
func (dao *Simple) PutNextContractID(id int32) error {
key := storage.SYSContractID.Bytes()
data := make([]byte, 4)
binary.LittleEndian.PutUint32(data, uint32(id))
return dao.Store.Put(key, data)
}
// -- end contracts. // -- end contracts.
// -- start nep5 balances. // -- start nep5 balances.

View file

@ -82,6 +82,17 @@ func TestDeleteContractState(t *testing.T) {
require.Nil(t, gotContractState) require.Nil(t, gotContractState)
} }
func TestSimple_GetNextContractID(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore())
id, err := dao.GetNextContractID()
require.NoError(t, err)
require.EqualValues(t, 0, id)
require.NoError(t, dao.PutNextContractID(10))
id, err = dao.GetNextContractID()
require.NoError(t, err)
require.EqualValues(t, 10, id)
}
func TestPutGetAppExecResult(t *testing.T) { func TestPutGetAppExecResult(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore()) dao := NewSimple(storage.NewMemoryStore())
hash := random.Uint256() hash := random.Uint256()

View file

@ -98,7 +98,16 @@ func contractCreate(ic *interop.Context, v *vm.VM) error {
contract, err := ic.DAO.GetContractState(newcontract.ScriptHash()) contract, err := ic.DAO.GetContractState(newcontract.ScriptHash())
if contract != nil { if contract != nil {
return errors.New("contract already exists") return errors.New("contract already exists")
} else if err := ic.DAO.PutContractState(newcontract); err != nil { }
id, err := ic.DAO.GetNextContractID()
if err != nil {
return err
}
newcontract.ID = id
if err := ic.DAO.PutNextContractID(id); err != nil {
return err
}
if err := ic.DAO.PutContractState(newcontract); err != nil {
return err return err
} }
v.Estack().PushVal(stackitem.NewInterop(newcontract)) v.Estack().PushVal(stackitem.NewInterop(newcontract))

View file

@ -18,6 +18,7 @@ const (
IXHeaderHashList KeyPrefix = 0x80 IXHeaderHashList KeyPrefix = 0x80
SYSCurrentBlock KeyPrefix = 0xc0 SYSCurrentBlock KeyPrefix = 0xc0
SYSCurrentHeader KeyPrefix = 0xc1 SYSCurrentHeader KeyPrefix = 0xc1
SYSContractID KeyPrefix = 0xc2
SYSVersion KeyPrefix = 0xf0 SYSVersion KeyPrefix = 0xf0
) )