diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 1a6d97f4c..fb15b82e0 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -45,7 +45,7 @@ import ( // Tuning parameters. const ( headerBatchCount = 2000 - version = "0.1.5" + version = "0.2.0" defaultInitialGAS = 52000000_00000000 defaultMemPoolSize = 50000 @@ -311,7 +311,8 @@ func (bc *Blockchain) init() error { ver, err := bc.dao.GetVersion() if err != nil { bc.log.Info("no storage version found! creating genesis block") - if err = bc.dao.PutVersion(version); err != nil { + v := dao.Version{Prefix: storage.STStorage, Value: version} + if err = bc.dao.PutVersion(v); err != nil { return err } genesisBlock, err := createGenesisBlock(bc.config) @@ -328,9 +329,11 @@ func (bc *Blockchain) init() error { } return bc.storeBlock(genesisBlock, nil) } - if ver != version { - return fmt.Errorf("storage version mismatch betweeen %s and %s", version, ver) + if ver.Value != version { + return fmt.Errorf("storage version mismatch betweeen %s and %s", version, ver.Value) } + bc.dao.StoragePrefix = ver.Prefix + bc.persistent.StoragePrefix = ver.Prefix // not strictly needed but we better be consistent here // At this point there was no version found in the storage which // implies a creating fresh storage with the version specified diff --git a/pkg/core/dao/dao.go b/pkg/core/dao/dao.go index e374de6b9..fd2817c7a 100644 --- a/pkg/core/dao/dao.go +++ b/pkg/core/dao/dao.go @@ -50,7 +50,7 @@ type DAO interface { GetStorageItems(id int32) ([]state.StorageItemWithKey, error) GetStorageItemsWithPrefix(id int32, prefix []byte) ([]state.StorageItemWithKey, error) GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error) - GetVersion() (string, error) + GetVersion() (Version, error) GetWrapped() DAO HasTransaction(hash util.Uint256) error Persist() (int, error) @@ -63,7 +63,7 @@ type DAO interface { PutStateSyncPoint(p uint32) error PutStateSyncCurrentBlockHeight(h uint32) error PutStorageItem(id int32, key []byte, si state.StorageItem) error - PutVersion(v string) error + PutVersion(v Version) error Seek(id int32, prefix []byte, f func(k, v []byte)) SeekAsync(ctx context.Context, id int32, prefix []byte) chan storage.KeyValue StoreAsBlock(block *block.Block, buf *io.BufBinWriter) error @@ -378,11 +378,46 @@ func (dao *Simple) GetBlock(hash util.Uint256) (*block.Block, error) { return block, nil } +// Version represents current dao version. +type Version struct { + Prefix storage.KeyPrefix + Value string +} + +// FromBytes decodes v from a byte-slice. +func (v *Version) FromBytes(data []byte) error { + if len(data) == 0 { + return errors.New("missing version") + } + i := 0 + for ; i < len(data) && data[i] != '\x00'; i++ { + } + + if i == len(data) { + v.Value = string(data) + return nil + } + + v.Value = string(data[:i]) + v.Prefix = storage.KeyPrefix(data[i+1]) + return nil +} + +// Bytes encodes v to a byte-slice. +func (v *Version) Bytes() []byte { + return append([]byte(v.Value), '\x00', byte(v.Prefix)) +} + // GetVersion attempts to get the current version stored in the // underlying store. -func (dao *Simple) GetVersion() (string, error) { - version, err := dao.Store.Get(storage.SYSVersion.Bytes()) - return string(version), err +func (dao *Simple) GetVersion() (Version, error) { + var version Version + + data, err := dao.Store.Get(storage.SYSVersion.Bytes()) + if err == nil { + err = version.FromBytes(data) + } + return version, err } // GetCurrentBlockHeight returns the current block height found in the @@ -485,8 +520,9 @@ func (dao *Simple) GetTransaction(hash util.Uint256) (*transaction.Transaction, } // PutVersion stores the given version in the underlying store. -func (dao *Simple) PutVersion(v string) error { - return dao.Store.Put(storage.SYSVersion.Bytes(), []byte(v)) +func (dao *Simple) PutVersion(v Version) error { + dao.StoragePrefix = v.Prefix + return dao.Store.Put(storage.SYSVersion.Bytes(), v.Bytes()) } // PutCurrentHeader stores current header. diff --git a/pkg/core/dao/dao_test.go b/pkg/core/dao/dao_test.go index 4ec8cc0d0..7d1c3d9c2 100644 --- a/pkg/core/dao/dao_test.go +++ b/pkg/core/dao/dao_test.go @@ -115,16 +115,26 @@ func TestGetVersion_NoVersion(t *testing.T) { dao := NewSimple(storage.NewMemoryStore(), false, false) version, err := dao.GetVersion() require.Error(t, err) - require.Equal(t, "", version) + require.Equal(t, "", version.Value) } func TestGetVersion(t *testing.T) { dao := NewSimple(storage.NewMemoryStore(), false, false) - err := dao.PutVersion("testVersion") + err := dao.PutVersion(Version{Prefix: 0x42, Value: "testVersion"}) require.NoError(t, err) version, err := dao.GetVersion() require.NoError(t, err) - require.NotNil(t, version) + require.EqualValues(t, 0x42, version.Prefix) + require.Equal(t, "testVersion", version.Value) + + t.Run("old format", func(t *testing.T) { + dao := NewSimple(storage.NewMemoryStore(), false, false) + require.NoError(t, dao.Store.Put(storage.SYSVersion.Bytes(), []byte("0.1.2"))) + + version, err := dao.GetVersion() + require.NoError(t, err) + require.Equal(t, "0.1.2", version.Value) + }) } func TestGetCurrentHeaderHeight_NoHeader(t *testing.T) {