diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 5dc1a54d4..5217f082b 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -45,7 +45,7 @@ import ( // Tuning parameters. const ( - version = "0.2.6" + version = "0.2.7" defaultInitialGAS = 52000000_00000000 defaultGCPeriod = 10000 @@ -717,21 +717,9 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage) p = time.Now() fallthrough case staleBlocksRemoved: - // Completely remove contract IDs to update them later. - bc.log.Info("trying to reset contract storage items and IDs") + bc.log.Info("trying to reset contract storage items") pStorageStart := p - cache.Store.Seek(storage.SeekRange{Prefix: []byte{byte(storage.STContractID)}}, func(k, _ []byte) bool { - cache.Store.Delete(k) - return true - }) - keys, err = cache.Persist() - if err != nil { - return fmt.Errorf("failed to persist removed contract IDs: %w", err) - } - bc.log.Info("removed contract IDs are persisted", zap.Duration("took", time.Since(p)), zap.Int("keys", keys)) - p = time.Now() - // Reset contracts storage and store new contract IDs. var mode = mpt.ModeAll if bc.config.RemoveUntraceableBlocks { mode |= mpt.ModeGCFlag @@ -739,19 +727,12 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage) trieStore := mpt.NewTrieStore(sr.Root, mode, cache.Store) oldStoragePrefix := v.StoragePrefix newStoragePrefix := statesync.TemporaryPrefix(oldStoragePrefix) - mgmtCSPrefixLen := 1 + 4 + 1 // STStorage + Management ID + contract state prefix - mgmtContractPrefix := make([]byte, mgmtCSPrefixLen-1) - id := int32(native.ManagementContractID) - binary.BigEndian.PutUint32(mgmtContractPrefix, uint32(id)) - mgmtContractPrefix[4] = native.PrefixContract - cs := new(state.Contract) const persistBatchSize = 200000 var ( seekErr error cnt int storageItmsCnt int - contractIDsCnt int batchCnt int ) trieStore.Seek(storage.SeekRange{Prefix: []byte{byte(oldStoragePrefix)}}, func(k, v []byte) bool { @@ -775,22 +756,6 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage) cnt++ storageItmsCnt++ - // @fixme: remove this part after #2702. - if bytes.HasPrefix(k[1:], mgmtContractPrefix) { - var hash util.Uint160 - copy(hash[:], k[mgmtCSPrefixLen:]) - err = stackitem.DeserializeConvertible(v, cs) - if err != nil { - bc.log.Warn("failed to deserialize contract; ID for this contract won't be stored in the DB", - zap.String("hash", hash.StringLE()), - zap.Error(err)) - } else { - cache.PutContractID(cs.ID, hash) - cnt++ - contractIDsCnt++ - } - } - return true }) if seekErr != nil { @@ -806,8 +771,7 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage) batchCnt++ bc.log.Info("last batch of contract storage items and IDs is persisted", zap.Int("batch", batchCnt), zap.Duration("took", time.Since(p)), zap.Int("keys", keys)) bc.log.Info("contract storage items and IDs are reset", zap.Duration("took", time.Since(pStorageStart)), - zap.Int("keys", storageItmsCnt), - zap.Int("ids", contractIDsCnt)) + zap.Int("keys", storageItmsCnt)) p = time.Now() fallthrough case newStorageItemsAdded: @@ -2121,7 +2085,7 @@ func (bc *Blockchain) GetContractState(hash util.Uint160) *state.Contract { // GetContractScriptHash returns contract script hash by its ID. func (bc *Blockchain) GetContractScriptHash(id int32) (util.Uint160, error) { - return bc.dao.GetContractScriptHash(id) + return native.GetContractScriptHash(bc.dao, id) } // GetNativeContractScriptHash returns native contract script hash by its name. diff --git a/pkg/core/dao/dao.go b/pkg/core/dao/dao.go index 8fb33efaa..844490dd0 100644 --- a/pkg/core/dao/dao.go +++ b/pkg/core/dao/dao.go @@ -135,32 +135,6 @@ func (dao *Simple) putWithBuffer(entity io.Serializable, key []byte, buf *io.Buf return nil } -func (dao *Simple) makeContractIDKey(id int32) []byte { - key := dao.getKeyBuf(5) - key[0] = byte(storage.STContractID) - binary.BigEndian.PutUint32(key[1:], uint32(id)) - return key -} - -// DeleteContractID deletes contract's id to hash mapping. -func (dao *Simple) DeleteContractID(id int32) { - dao.Store.Delete(dao.makeContractIDKey(id)) -} - -// PutContractID adds a mapping from a contract's ID to its hash. -func (dao *Simple) PutContractID(id int32, hash util.Uint160) { - dao.Store.Put(dao.makeContractIDKey(id), hash.BytesBE()) -} - -// GetContractScriptHash retrieves the contract's hash given its ID. -func (dao *Simple) GetContractScriptHash(id int32) (util.Uint160, error) { - var data = new(util.Uint160) - if err := dao.GetAndDecode(data, dao.makeContractIDKey(id)); err != nil { - return *data, err - } - return *data, nil -} - // -- start NEP-17 transfer info. func (dao *Simple) makeTTIKey(acc util.Uint160) []byte { diff --git a/pkg/core/native/management.go b/pkg/core/native/management.go index 3da8bac1f..2b26ad36f 100644 --- a/pkg/core/native/management.go +++ b/pkg/core/native/management.go @@ -228,19 +228,24 @@ func GetContract(d *dao.Simple, hash util.Uint160) (*state.Contract, error) { // GetContractByID returns a contract with the given ID from the given DAO. func GetContractByID(d *dao.Simple, id int32) (*state.Contract, error) { - key := make([]byte, 5) - key = putHashKey(key, id) - si := d.GetStorageItem(ManagementContractID, key) - if si == nil { - return nil, storage.ErrKeyNotFound - } - hash, err := util.Uint160DecodeBytesBE(si) + hash, err := GetContractScriptHash(d, id) if err != nil { return nil, err } return GetContract(d, hash) } +// GetContractScriptHash returns a contract hash associated with the given ID from the given DAO. +func GetContractScriptHash(d *dao.Simple, id int32) (util.Uint160, error) { + key := make([]byte, 5) + key = putHashKey(key, id) + si := d.GetStorageItem(ManagementContractID, key) + if si == nil { + return util.Uint160{}, storage.ErrKeyNotFound + } + return util.Uint160DecodeBytesBE(si) +} + func getLimitedSlice(arg stackitem.Item, max int) ([]byte, error) { _, isNull := arg.(stackitem.Null) if isNull { @@ -492,7 +497,6 @@ func (m *Management) Destroy(d *dao.Simple, hash util.Uint160) error { d.DeleteStorageItem(m.ID, key) key = putHashKey(key, contract.ID) d.DeleteStorageItem(ManagementContractID, key) - d.DeleteContractID(contract.ID) d.Seek(contract.ID, storage.SeekRange{}, func(k, _ []byte) bool { d.DeleteStorageItem(contract.ID, k) @@ -686,7 +690,6 @@ func putContractState(d *dao.Simple, cs *state.Contract, updateCache bool) error } key = putHashKey(key, cs.ID) d.PutStorageItem(ManagementContractID, key, cs.Hash.BytesBE()) - d.PutContractID(cs.ID, cs.Hash) return nil } diff --git a/pkg/core/storage/store.go b/pkg/core/storage/store.go index 71d0b765f..6583ad69a 100644 --- a/pkg/core/storage/store.go +++ b/pkg/core/storage/store.go @@ -16,9 +16,8 @@ const ( DataMPT KeyPrefix = 0x03 // DataMPTAux is used to store additional MPT data like height-root // mappings and local/validated heights. - DataMPTAux KeyPrefix = 0x04 - STContractID KeyPrefix = 0x51 - STStorage KeyPrefix = 0x70 + DataMPTAux KeyPrefix = 0x04 + STStorage KeyPrefix = 0x70 // STTempStorage is used to store contract storage items during state sync process // in order not to mess up the previous state which has its own items stored by // STStorage prefix. Once state exchange process is completed, all items with