storage: drop (KeyPrefix).Bytes() API

It allocates and most of the time we can avoid that.
This commit is contained in:
Roman Khimov 2022-02-18 15:19:57 +03:00
parent 7223caf369
commit 7d6f087337
7 changed files with 40 additions and 36 deletions

View file

@ -406,7 +406,7 @@ func (bc *Blockchain) init() error {
} }
// Check whether StateJump stage is in the storage and continue interrupted state jump if so. // Check whether StateJump stage is in the storage and continue interrupted state jump if so.
jumpStage, err := bc.dao.Store.Get(storage.SYSStateJumpStage.Bytes()) jumpStage, err := bc.dao.Store.Get([]byte{byte(storage.SYSStateJumpStage)})
if err == nil { if err == nil {
if !(bc.GetConfig().P2PStateExchangeExtensions && bc.GetConfig().RemoveUntraceableBlocks) { if !(bc.GetConfig().P2PStateExchangeExtensions && bc.GetConfig().RemoveUntraceableBlocks) {
return errors.New("state jump was not completed, but P2PStateExchangeExtensions are disabled or archival node capability is on. " + return errors.New("state jump was not completed, but P2PStateExchangeExtensions are disabled or archival node capability is on. " +
@ -500,7 +500,7 @@ func (bc *Blockchain) jumpToStateInternal(p uint32, stage stateJumpStage) error
bc.log.Info("jumping to state sync point", zap.Uint32("state sync point", p)) bc.log.Info("jumping to state sync point", zap.Uint32("state sync point", p))
jumpStageKey := storage.SYSStateJumpStage.Bytes() jumpStageKey := []byte{byte(storage.SYSStateJumpStage)}
switch stage { switch stage {
case none: case none:
bc.dao.Store.Put(jumpStageKey, []byte{byte(stateJumpStarted)}) bc.dao.Store.Put(jumpStageKey, []byte{byte(stateJumpStarted)})

View file

@ -1853,7 +1853,9 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
if bcSpout.dao.Version.StoragePrefix == tempPrefix { if bcSpout.dao.Version.StoragePrefix == tempPrefix {
tempPrefix = storage.STStorage tempPrefix = storage.STStorage
} }
bcSpout.dao.Store.Seek(storage.SeekRange{Prefix: bcSpout.dao.Version.StoragePrefix.Bytes()}, func(k, v []byte) bool { bPrefix := make([]byte, 1)
bPrefix[0] = byte(bcSpout.dao.Version.StoragePrefix)
bcSpout.dao.Store.Seek(storage.SeekRange{Prefix: bPrefix}, func(k, v []byte) bool {
key := slice.Copy(k) key := slice.Copy(k)
key[0] = byte(tempPrefix) key[0] = byte(tempPrefix)
value := slice.Copy(v) value := slice.Copy(v)
@ -1880,34 +1882,35 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
c.ProtocolConfiguration.KeepOnlyLatestState = true c.ProtocolConfiguration.KeepOnlyLatestState = true
} }
// manually store statejump stage to check statejump recover process // manually store statejump stage to check statejump recover process
bPrefix[0] = byte(storage.SYSStateJumpStage)
t.Run("invalid RemoveUntraceableBlocks setting", func(t *testing.T) { t.Run("invalid RemoveUntraceableBlocks setting", func(t *testing.T) {
bcSpout.dao.Store.Put(storage.SYSStateJumpStage.Bytes(), []byte{byte(stateJumpStarted)}) bcSpout.dao.Store.Put(bPrefix, []byte{byte(stateJumpStarted)})
checkNewBlockchainErr(t, func(c *config.Config) { checkNewBlockchainErr(t, func(c *config.Config) {
boltCfg(c) boltCfg(c)
c.ProtocolConfiguration.RemoveUntraceableBlocks = false c.ProtocolConfiguration.RemoveUntraceableBlocks = false
}, bcSpout.dao.Store, true) }, bcSpout.dao.Store, true)
}) })
t.Run("invalid state jump stage format", func(t *testing.T) { t.Run("invalid state jump stage format", func(t *testing.T) {
bcSpout.dao.Store.Put(storage.SYSStateJumpStage.Bytes(), []byte{0x01, 0x02}) bcSpout.dao.Store.Put(bPrefix, []byte{0x01, 0x02})
checkNewBlockchainErr(t, boltCfg, bcSpout.dao.Store, true) checkNewBlockchainErr(t, boltCfg, bcSpout.dao.Store, true)
}) })
t.Run("missing state sync point", func(t *testing.T) { t.Run("missing state sync point", func(t *testing.T) {
bcSpout.dao.Store.Put(storage.SYSStateJumpStage.Bytes(), []byte{byte(stateJumpStarted)}) bcSpout.dao.Store.Put(bPrefix, []byte{byte(stateJumpStarted)})
checkNewBlockchainErr(t, boltCfg, bcSpout.dao.Store, true) checkNewBlockchainErr(t, boltCfg, bcSpout.dao.Store, true)
}) })
t.Run("invalid state sync point", func(t *testing.T) { t.Run("invalid state sync point", func(t *testing.T) {
bcSpout.dao.Store.Put(storage.SYSStateJumpStage.Bytes(), []byte{byte(stateJumpStarted)}) bcSpout.dao.Store.Put(bPrefix, []byte{byte(stateJumpStarted)})
point := make([]byte, 4) point := make([]byte, 4)
binary.LittleEndian.PutUint32(point, uint32(len(bcSpout.headerHashes))) binary.LittleEndian.PutUint32(point, uint32(len(bcSpout.headerHashes)))
bcSpout.dao.Store.Put(storage.SYSStateSyncPoint.Bytes(), point) bcSpout.dao.Store.Put([]byte{byte(storage.SYSStateSyncPoint)}, point)
checkNewBlockchainErr(t, boltCfg, bcSpout.dao.Store, true) checkNewBlockchainErr(t, boltCfg, bcSpout.dao.Store, true)
}) })
for _, stage := range []stateJumpStage{stateJumpStarted, newStorageItemsAdded, genesisStateRemoved, 0x03} { for _, stage := range []stateJumpStage{stateJumpStarted, newStorageItemsAdded, genesisStateRemoved, 0x03} {
t.Run(fmt.Sprintf("state jump stage %d", stage), func(t *testing.T) { t.Run(fmt.Sprintf("state jump stage %d", stage), func(t *testing.T) {
bcSpout.dao.Store.Put(storage.SYSStateJumpStage.Bytes(), []byte{byte(stage)}) bcSpout.dao.Store.Put(bPrefix, []byte{byte(stage)})
point := make([]byte, 4) point := make([]byte, 4)
binary.LittleEndian.PutUint32(point, uint32(stateSyncPoint)) binary.LittleEndian.PutUint32(point, uint32(stateSyncPoint))
bcSpout.dao.Store.Put(storage.SYSStateSyncPoint.Bytes(), point) bcSpout.dao.Store.Put([]byte{byte(storage.SYSStateSyncPoint)}, point)
shouldFail := stage == 0x03 // unknown stage shouldFail := stage == 0x03 // unknown stage
checkNewBlockchainErr(t, spountCfg, bcSpout.dao.Store, shouldFail) checkNewBlockchainErr(t, spountCfg, bcSpout.dao.Store, shouldFail)
}) })

View file

@ -448,12 +448,18 @@ func (v *Version) Bytes() []byte {
return append([]byte(v.Value), '\x00', byte(v.StoragePrefix), mask) return append([]byte(v.Value), '\x00', byte(v.StoragePrefix), mask)
} }
func (dao *Simple) mkKeyPrefix(k storage.KeyPrefix) []byte {
b := dao.getKeyBuf(1)
b[0] = byte(k)
return b
}
// GetVersion attempts to get the current version stored in the // GetVersion attempts to get the current version stored in the
// underlying store. // underlying store.
func (dao *Simple) GetVersion() (Version, error) { func (dao *Simple) GetVersion() (Version, error) {
var version Version var version Version
data, err := dao.Store.Get(storage.SYSVersion.Bytes()) data, err := dao.Store.Get(dao.mkKeyPrefix(storage.SYSVersion))
if err == nil { if err == nil {
err = version.FromBytes(data) err = version.FromBytes(data)
} }
@ -463,7 +469,7 @@ func (dao *Simple) GetVersion() (Version, error) {
// GetCurrentBlockHeight returns the current block height found in the // GetCurrentBlockHeight returns the current block height found in the
// underlying store. // underlying store.
func (dao *Simple) GetCurrentBlockHeight() (uint32, error) { func (dao *Simple) GetCurrentBlockHeight() (uint32, error) {
b, err := dao.Store.Get(storage.SYSCurrentBlock.Bytes()) b, err := dao.Store.Get(dao.mkKeyPrefix(storage.SYSCurrentBlock))
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -474,7 +480,7 @@ func (dao *Simple) GetCurrentBlockHeight() (uint32, error) {
// the underlying store. // the underlying store.
func (dao *Simple) GetCurrentHeaderHeight() (i uint32, h util.Uint256, err error) { func (dao *Simple) GetCurrentHeaderHeight() (i uint32, h util.Uint256, err error) {
var b []byte var b []byte
b, err = dao.Store.Get(storage.SYSCurrentHeader.Bytes()) b, err = dao.Store.Get(dao.mkKeyPrefix(storage.SYSCurrentHeader))
if err != nil { if err != nil {
return return
} }
@ -485,7 +491,7 @@ func (dao *Simple) GetCurrentHeaderHeight() (i uint32, h util.Uint256, err error
// GetStateSyncPoint returns current state synchronisation point P. // GetStateSyncPoint returns current state synchronisation point P.
func (dao *Simple) GetStateSyncPoint() (uint32, error) { func (dao *Simple) GetStateSyncPoint() (uint32, error) {
b, err := dao.Store.Get(storage.SYSStateSyncPoint.Bytes()) b, err := dao.Store.Get(dao.mkKeyPrefix(storage.SYSStateSyncPoint))
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -495,7 +501,7 @@ func (dao *Simple) GetStateSyncPoint() (uint32, error) {
// GetStateSyncCurrentBlockHeight returns current block height stored during state // GetStateSyncCurrentBlockHeight returns current block height stored during state
// synchronisation process. // synchronisation process.
func (dao *Simple) GetStateSyncCurrentBlockHeight() (uint32, error) { func (dao *Simple) GetStateSyncCurrentBlockHeight() (uint32, error) {
b, err := dao.Store.Get(storage.SYSStateSyncCurrentBlockHeight.Bytes()) b, err := dao.Store.Get(dao.mkKeyPrefix(storage.SYSStateSyncCurrentBlockHeight))
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -508,7 +514,7 @@ func (dao *Simple) GetHeaderHashes() ([]util.Uint256, error) {
var hashes = make([]util.Uint256, 0) var hashes = make([]util.Uint256, 0)
dao.Store.Seek(storage.SeekRange{ dao.Store.Seek(storage.SeekRange{
Prefix: storage.IXHeaderHashList.Bytes(), Prefix: dao.mkKeyPrefix(storage.IXHeaderHashList),
}, func(k, v []byte) bool { }, func(k, v []byte) bool {
newHashes, err := read2000Uint256Hashes(v) newHashes, err := read2000Uint256Hashes(v)
if err != nil { if err != nil {
@ -555,7 +561,7 @@ func (dao *Simple) GetTransaction(hash util.Uint256) (*transaction.Transaction,
// PutVersion stores the given version in the underlying store. // PutVersion stores the given version in the underlying store.
func (dao *Simple) PutVersion(v Version) { func (dao *Simple) PutVersion(v Version) {
dao.Version = v dao.Version = v
dao.Store.Put(storage.SYSVersion.Bytes(), v.Bytes()) dao.Store.Put(dao.mkKeyPrefix(storage.SYSVersion), v.Bytes())
} }
// PutCurrentHeader stores current header. // PutCurrentHeader stores current header.
@ -563,21 +569,21 @@ func (dao *Simple) PutCurrentHeader(h util.Uint256, index uint32) {
buf := dao.getDataBuf() buf := dao.getDataBuf()
buf.WriteBytes(h.BytesLE()) buf.WriteBytes(h.BytesLE())
buf.WriteU32LE(index) buf.WriteU32LE(index)
dao.Store.Put(storage.SYSCurrentHeader.Bytes(), buf.Bytes()) dao.Store.Put(dao.mkKeyPrefix(storage.SYSCurrentHeader), buf.Bytes())
} }
// PutStateSyncPoint stores current state synchronisation point P. // PutStateSyncPoint stores current state synchronisation point P.
func (dao *Simple) PutStateSyncPoint(p uint32) { func (dao *Simple) PutStateSyncPoint(p uint32) {
buf := dao.getKeyBuf(4) // It's very small, no point in using BufBinWriter. buf := dao.getDataBuf()
binary.LittleEndian.PutUint32(buf, p) buf.WriteU32LE(p)
dao.Store.Put(storage.SYSStateSyncPoint.Bytes(), buf) dao.Store.Put(dao.mkKeyPrefix(storage.SYSStateSyncPoint), buf.Bytes())
} }
// PutStateSyncCurrentBlockHeight stores current block height during state synchronisation process. // PutStateSyncCurrentBlockHeight stores current block height during state synchronisation process.
func (dao *Simple) PutStateSyncCurrentBlockHeight(h uint32) { func (dao *Simple) PutStateSyncCurrentBlockHeight(h uint32) {
buf := dao.getKeyBuf(4) // It's very small, no point in using BufBinWriter. buf := dao.getDataBuf()
binary.LittleEndian.PutUint32(buf, h) buf.WriteU32LE(h)
dao.Store.Put(storage.SYSStateSyncCurrentBlockHeight.Bytes(), buf) dao.Store.Put(dao.mkKeyPrefix(storage.SYSStateSyncCurrentBlockHeight), buf.Bytes())
} }
// read2000Uint256Hashes attempts to read 2000 Uint256 hashes from // read2000Uint256Hashes attempts to read 2000 Uint256 hashes from
@ -712,7 +718,7 @@ func (dao *Simple) StoreAsCurrentBlock(block *block.Block) {
h := block.Hash() h := block.Hash()
h.EncodeBinary(buf.BinWriter) h.EncodeBinary(buf.BinWriter)
buf.WriteU32LE(block.Index) buf.WriteU32LE(block.Index)
dao.Store.Put(storage.SYSCurrentBlock.Bytes(), buf.Bytes()) dao.Store.Put(dao.mkKeyPrefix(storage.SYSCurrentBlock), buf.Bytes())
} }
// StoreAsTransaction stores given TX as DataTransaction. It also stores transactions // StoreAsTransaction stores given TX as DataTransaction. It also stores transactions

View file

@ -132,14 +132,14 @@ func TestGetVersion(t *testing.T) {
t.Run("invalid", func(t *testing.T) { t.Run("invalid", func(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false, false) dao := NewSimple(storage.NewMemoryStore(), false, false)
dao.Store.Put(storage.SYSVersion.Bytes(), []byte("0.1.2\x00x")) dao.Store.Put([]byte{byte(storage.SYSVersion)}, []byte("0.1.2\x00x"))
_, err := dao.GetVersion() _, err := dao.GetVersion()
require.Error(t, err) require.Error(t, err)
}) })
t.Run("old format", func(t *testing.T) { t.Run("old format", func(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false, false) dao := NewSimple(storage.NewMemoryStore(), false, false)
dao.Store.Put(storage.SYSVersion.Bytes(), []byte("0.1.2")) dao.Store.Put([]byte{byte(storage.SYSVersion)}, []byte("0.1.2"))
version, err := dao.GetVersion() version, err := dao.GetVersion()
require.NoError(t, err) require.NoError(t, err)

View file

@ -32,7 +32,7 @@ func TestModule_PR2019_discussion_r689629704(t *testing.T) {
nodes = make(map[util.Uint256][]byte) nodes = make(map[util.Uint256][]byte)
expectedItems []storage.KeyValue expectedItems []storage.KeyValue
) )
expectedStorage.Seek(storage.SeekRange{Prefix: storage.DataMPT.Bytes()}, func(k, v []byte) bool { expectedStorage.Seek(storage.SeekRange{Prefix: []byte{byte(storage.DataMPT)}}, func(k, v []byte) bool {
key := slice.Copy(k) key := slice.Copy(k)
value := slice.Copy(v) value := slice.Copy(v)
expectedItems = append(expectedItems, storage.KeyValue{ expectedItems = append(expectedItems, storage.KeyValue{
@ -96,7 +96,7 @@ func TestModule_PR2019_discussion_r689629704(t *testing.T) {
// Compare resulting storage items and refcounts. // Compare resulting storage items and refcounts.
var actualItems []storage.KeyValue var actualItems []storage.KeyValue
expectedStorage.Seek(storage.SeekRange{Prefix: storage.DataMPT.Bytes()}, func(k, v []byte) bool { expectedStorage.Seek(storage.SeekRange{Prefix: []byte{byte(storage.DataMPT)}}, func(k, v []byte) bool {
key := slice.Copy(k) key := slice.Copy(k)
value := slice.Copy(v) value := slice.Copy(v)
actualItems = append(actualItems, storage.KeyValue{ actualItems = append(actualItems, storage.KeyValue{

View file

@ -423,7 +423,7 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
// compare storage states // compare storage states
fetchStorage := func(bc *Blockchain) []storage.KeyValue { fetchStorage := func(bc *Blockchain) []storage.KeyValue {
var kv []storage.KeyValue var kv []storage.KeyValue
bc.dao.Store.Seek(storage.SeekRange{Prefix: bc.dao.Version.StoragePrefix.Bytes()}, func(k, v []byte) bool { bc.dao.Store.Seek(storage.SeekRange{Prefix: []byte{byte(bc.dao.Version.StoragePrefix)}}, func(k, v []byte) bool {
key := slice.Copy(k) key := slice.Copy(k)
value := slice.Copy(v) value := slice.Copy(v)
if key[0] == byte(storage.STTempStorage) { if key[0] == byte(storage.STTempStorage) {
@ -444,7 +444,7 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
// no temp items should be left // no temp items should be left
require.Eventually(t, func() bool { require.Eventually(t, func() bool {
var haveItems bool var haveItems bool
bcBolt.dao.Store.Seek(storage.SeekRange{Prefix: storage.STStorage.Bytes()}, func(_, _ []byte) bool { bcBolt.dao.Store.Seek(storage.SeekRange{Prefix: []byte{byte(storage.STStorage)}}, func(_, _ []byte) bool {
haveItems = true haveItems = true
return false return false
}) })

View file

@ -106,11 +106,6 @@ type (
KeyPrefix uint8 KeyPrefix uint8
) )
// Bytes returns the bytes representation of KeyPrefix.
func (k KeyPrefix) Bytes() []byte {
return []byte{byte(k)}
}
func seekRangeToPrefixes(sr SeekRange) *util.Range { func seekRangeToPrefixes(sr SeekRange) *util.Range {
var ( var (
rang *util.Range rang *util.Range